blob: 09b761456354d4738da8647e49c78db634f2ce84 [file] [log] [blame]
kelvin8ec71442015-01-15 16:57:00 -08001#!/usr/bin/env python
2
3import time
4import pexpect
5import struct
6import fcntl
7import os
8import sys
9import signal
10import sys
11import re
12import json
13sys.path.append( "../" )
14from drivers.common.clidriver import CLI
15
16
17class QuaggaCliDriver( CLI ):
18
19 def __init__( self ):
20 super( CLI, self ).__init__()
21
22 # TODO: simplify this method
23 def connect( self, **connectargs ):
24 for key in connectargs:
25 vars( self )[ key ] = connectargs[ key ]
26
27 self.name = self.options[ 'name' ]
28 # self.handle = super( QuaggaCliDriver,self ).connect(
29 # user_name=self.user_name, ip_address=self.ip_address,port=self.port,
30 # pwd=self.pwd )
31 self.handle = super(
32 QuaggaCliDriver,
33 self ).connect(
34 user_name=self.user_name,
35 ip_address="1.1.1.1",
36 port=self.port,
37 pwd=self.pwd )
38 main.log.info(
39 "connect parameters:" + str(
40 self.user_name ) + ";" + str(
41 self.ip_address ) + ";" + str(
42 self.port ) + ";" + str(
43 self.pwd ) )
44
45 if self.handle:
46 # self.handle.expect( "",timeout=10 )
47 # self.handle.expect( "\$",timeout=10 )
48 self.handle.sendline( "telnet localhost 2605" )
49 # self.handle.expect( "Password:", timeout=5 )
50 self.handle.expect( "Password:" )
51 self.handle.sendline( "hello" )
52 # self.handle.expect( "bgpd", timeout=5 )
53 self.handle.expect( "bgpd" )
54 self.handle.sendline( "enable" )
55 # self.handle.expect( "bgpd#", timeout=5 )
56 self.handle.expect( "bgpd#" )
57 return self.handle
58 else:
59 main.log.info( "NO HANDLE" )
60 return main.FALSE
61
62 def loginQuagga( self, ip_address ):
63 self.name = self.options[ 'name' ]
64 self.handle = super( QuaggaCliDriver, self ).connect(
65 user_name=self.user_name, ip_address=ip_address,
66 port=self.port, pwd=self.pwd )
67 main.log.info( "connect parameters:" + str( self.user_name ) + ";"
68 + str( self.ip_address ) + ";" + str( self.port ) + ";" + str( self.pwd ) )
69
70 if self.handle:
71 # self.handle.expect( "" )
72 # self.handle.expect( "\$" )
73 self.handle.sendline( "telnet localhost 2605" )
74 # self.handle.expect( "Password:", timeout=5 )
75 self.handle.expect( "Password:" )
76 self.handle.sendline( "hello" )
77 # self.handle.expect( "bgpd", timeout=5 )
78 self.handle.expect( "bgpd" )
79 self.handle.sendline( "enable" )
80 # self.handle.expect( "bgpd#", timeout=5 )
81 self.handle.expect( "bgpd#" )
82 main.log.info( "I in quagga on host " + str( ip_address ) )
83
84 return self.handle
85 else:
86 main.log.info( "NO HANDLE" )
87 return main.FALSE
88
89 def enter_config( self, asn ):
90 main.log.info( "I am in enter_config method!" )
91 try:
92 self.handle.sendline( "" )
93 self.handle.expect( "bgpd#" )
94 except:
95 main.log.warn( "Probably not currently in enable mode!" )
96 self.disconnect()
97 return main.FALSE
98 self.handle.sendline( "configure terminal" )
99 self.handle.expect( "config", timeout=5 )
100 routerAS = "router bgp " + str( asn )
101 try:
102 self.handle.sendline( routerAS )
103 self.handle.expect( "config-router", timeout=5 )
104 return main.TRUE
105 except:
106 return main.FALSE
107
108 def generate_prefixes( self, net, numRoutes ):
109 main.log.info( "I am in generate_prefixes method!" )
110
111 # each IP prefix will be composed by "net" + "." + m + "." + n + "." + x
112 # the length of each IP prefix is 24
113 routes = []
114 routes_gen = 0
115 m = numRoutes / 256
116 n = numRoutes % 256
117
118 for i in range( 0, m ):
119 for j in range( 0, 256 ):
120 network = str(
121 net ) + "." + str(
122 i ) + "." + str(
123 j ) + ".0/24"
124 routes.append( network )
125 routes_gen = routes_gen + 1
126
127 for j in range( 0, n ):
128 network = str( net ) + "." + str( m ) + "." + str( j ) + ".0/24"
129 routes.append( network )
130 routes_gen = routes_gen + 1
131
132 if routes_gen == numRoutes:
133 main.log.info( "Successfully generated " + str( numRoutes )
134 + " prefixes!" )
135 return routes
136 return main.FALSE
137
138 # This method generates a multiple to single point intent(
139 # MultiPointToSinglePointIntent ) for a given route
140 def generate_expected_singleRouteIntent(
141 self,
142 prefix,
143 nextHop,
144 nextHopMac,
145 sdnip_data ):
146
147 ingress = []
148 egress = ""
149 for peer in sdnip_data[ 'bgpPeers' ]:
150 if peer[ 'ipAddress' ] == nextHop:
151 egress = "of:" + str(
152 peer[ 'attachmentDpid' ] ).replace( ":",
153 "" ) + ":" + str( peer[ 'attachmentPort' ] )
154 else:
155 ingress.append(
156 "of:" + str( peer[ 'attachmentDpid' ] ).replace( ":",
157 "" ) + ":" + str( peer[ 'attachmentPort' ] ) )
158
159 selector = "ETH_TYPE{ethType=800},IPV4_DST{ip=" + prefix + "}"
160 treatment = "[ETH_DST{mac=" + str( nextHopMac ) + "}]"
161
162 intent = egress + "/" + \
163 str( sorted( ingress ) ) + "/" + selector + "/" + treatment
164 return intent
165
166 def generate_expected_onePeerRouteIntents(
167 self,
168 prefixes,
169 nextHop,
170 nextHopMac,
171 sdnip_json_file_path ):
172 intents = []
173 sdnip_json_file = open( sdnip_json_file_path ).read()
174
175 sdnip_data = json.loads( sdnip_json_file )
176
177 for prefix in prefixes:
178 intents.append(
179 self.generate_expected_singleRouteIntent(
180 prefix,
181 nextHop,
182 nextHopMac,
183 sdnip_data ) )
184 return sorted( intents )
185
186 # TODO
187 # This method generates all expected route intents for all BGP peers
188 def generate_expected_routeIntents( self ):
189 intents = []
190 return intents
191
192 # This method extracts all actual routes from ONOS CLI
193 def extract_actual_routes( self, get_routes_result ):
194 routes_json_obj = json.loads( get_routes_result )
195
196 allRoutes_actual = []
197 for route in routes_json_obj:
198 if route[ 'prefix' ] == '172.16.10.0/24':
199 continue
200 allRoutes_actual.append(
201 route[ 'prefix' ] + "/" + route[ 'nextHop' ] )
202
203 return sorted( allRoutes_actual )
204
205 # This method extracts all actual route intents from ONOS CLI
206 def extract_actual_routeIntents( self, get_intents_result ):
207 intents = []
208 # TODO: delete the line below when change to Mininet demo script
209 # get_intents_result=open( "../tests/SdnIpTest/intents.json" ).read()
210 intents_json_obj = json.loads( get_intents_result )
211
212 for intent in intents_json_obj:
213 if intent[ 'appId' ] != "org.onosproject.sdnip":
214 continue
215 if intent[ 'type' ] == "MultiPointToSinglePointIntent" and intent[ 'state' ] == 'INSTALLED':
216 egress = str( intent[ 'egress' ][ 'device' ] ) + ":" + str(
217 intent[ 'egress' ][ 'port' ] )
218 ingress = []
219 for attachmentPoint in intent[ 'ingress' ]:
220 ingress.append(
221 str( attachmentPoint[ 'device' ] ) + ":" + str( attachmentPoint[ 'port' ] ) )
222
223 selector = intent[ 'selector' ].replace(
224 "[", "" ).replace( "]", "" ).replace( " ", "" )
225 if str( selector ).startswith( "IPV4" ):
226 str1, str2 = str( selector ).split( "," )
227 selector = str2 + "," + str1
228
229 intent = egress + "/" + \
230 str( sorted( ingress ) ) + "/" + \
231 selector + "/" + intent[ 'treatment' ]
232 intents.append( intent )
233 return sorted( intents )
234
235 # This method extracts all actual BGP intents from ONOS CLI
236 def extract_actual_bgpIntents( self, get_intents_result ):
237 intents = []
238 # TODO: delete the line below when change to Mininet demo script
239 # get_intents_result=open( "../tests/SdnIpTest/intents.json" ).read()
240 intents_json_obj = json.loads( get_intents_result )
241
242 for intent in intents_json_obj:
243 if intent[ 'appId' ] != "org.onosproject.sdnip":
244 continue
245 if intent[ 'type' ] == "PointToPointIntent" and "protocol=6" in str( intent[ 'selector' ] ):
246 ingress = str( intent[ 'ingress' ][ 'device' ] ) + ":" + str(
247 intent[ 'ingress' ][ 'port' ] )
248 egress = str( intent[ 'egress' ][ 'device' ] ) + ":" + str(
249 intent[ 'egress' ][ 'port' ] )
250 selector = str(
251 intent[ 'selector' ] ).replace( " ",
252 "" ).replace( "[",
253 "" ).replace( "]",
254 "" ).split( "," )
255 intent = ingress + "/" + egress + \
256 "/" + str( sorted( selector ) )
257 intents.append( intent )
258
259 return sorted( intents )
260
261 # This method generates a single point to single point intent(
262 # PointToPointIntent ) for BGP path
263 def generate_expected_bgpIntents( self, sdnip_json_file_path ):
264 from operator import eq
265
266 sdnip_json_file = open( sdnip_json_file_path ).read()
267 sdnip_data = json.loads( sdnip_json_file )
268
269 intents = []
270 bgpPeerAttachmentPoint = ""
271 bgpSpeakerAttachmentPoint = "of:" + str(
272 sdnip_data[ 'bgpSpeakers' ][ 0 ][ 'attachmentDpid' ] ).replace( ":",
273 "" ) + ":" + str( sdnip_data[ 'bgpSpeakers' ][ 0 ][ 'attachmentPort' ] )
274 for peer in sdnip_data[ 'bgpPeers' ]:
275 bgpPeerAttachmentPoint = "of:" + str(
276 peer[ 'attachmentDpid' ] ).replace( ":",
277 "" ) + ":" + str( peer[ 'attachmentPort' ] )
278 # find out the BGP speaker IP address for this BGP peer
279 bgpSpeakerIpAddress = ""
280 for interfaceAddress in sdnip_data[ 'bgpSpeakers' ][ 0 ][ 'interfaceAddresses' ]:
281 # if eq( interfaceAddress[ 'interfaceDpid' ],sdnip_data[
282 # 'bgpSpeakers' ][ 0 ][ 'attachmentDpid' ] ) and eq(
283 # interfaceAddress[ 'interfacePort' ], sdnip_data[
284 # 'bgpSpeakers' ][ 0 ][ 'attachmentPort' ] ):
285 if eq( interfaceAddress[ 'interfaceDpid' ], peer[ 'attachmentDpid' ] ) and eq( interfaceAddress[ 'interfacePort' ], peer[ 'attachmentPort' ] ):
286 bgpSpeakerIpAddress = interfaceAddress[ 'ipAddress' ]
287 break
288 else:
289 continue
290
291 # from bgpSpeakerAttachmentPoint to bgpPeerAttachmentPoint
292 # direction
293 selector_str = "IPV4_SRC{ip=" + bgpSpeakerIpAddress + "/32}," + "IPV4_DST{ip=" + peer[
294 'ipAddress' ] + "/32}," + "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_DST{tcpPort=179}"
295 selector = selector_str.replace( " ", "" ).replace(
296 "[", "" ).replace( "]", "" ).split( "," )
297 intent = bgpSpeakerAttachmentPoint + "/" + \
298 bgpPeerAttachmentPoint + "/" + str( sorted( selector ) )
299 intents.append( intent )
300
301 selector_str = "IPV4_SRC{ip=" + bgpSpeakerIpAddress + "/32}," + "IPV4_DST{ip=" + peer[
302 'ipAddress' ] + "/32}," + "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_SRC{tcpPort=179}"
303 selector = selector_str.replace( " ", "" ).replace(
304 "[", "" ).replace( "]", "" ).split( "," )
305 intent = bgpSpeakerAttachmentPoint + "/" + \
306 bgpPeerAttachmentPoint + "/" + str( sorted( selector ) )
307 intents.append( intent )
308
309 # from bgpPeerAttachmentPoint to bgpSpeakerAttachmentPoint
310 # direction
311 selector_str = "IPV4_SRC{ip=" + peer[ 'ipAddress' ] + "/32}," + "IPV4_DST{ip=" + bgpSpeakerIpAddress + "/32}," + \
312 "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_DST{tcpPort=179}"
313 selector = selector_str.replace( " ", "" ).replace(
314 "[", "" ).replace( "]", "" ).split( "," )
315 intent = bgpPeerAttachmentPoint + "/" + \
316 bgpSpeakerAttachmentPoint + "/" + str( sorted( selector ) )
317 intents.append( intent )
318
319 selector_str = "IPV4_SRC{ip=" + peer[ 'ipAddress' ] + "/32}," + "IPV4_DST{ip=" + bgpSpeakerIpAddress + "/32}," + \
320 "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_SRC{tcpPort=179}"
321 selector = selector_str.replace( " ", "" ).replace(
322 "[", "" ).replace( "]", "" ).split( "," )
323 intent = bgpPeerAttachmentPoint + "/" + \
324 bgpSpeakerAttachmentPoint + "/" + str( sorted( selector ) )
325 intents.append( intent )
326
327 return sorted( intents )
328
329 def add_routes( self, routes, routeRate ):
330 main.log.info( "I am in add_routes method!" )
331
332 routes_added = 0
333 try:
334 self.handle.sendline( "" )
335 # self.handle.expect( "config-router" )
336 self.handle.expect( "config-router", timeout=5 )
337 except:
338 main.log.warn( "Probably not in config-router mode!" )
339 self.disconnect()
340 main.log.info( "Start to add routes" )
341
342 for i in range( 0, len( routes ) ):
343 routeCmd = "network " + routes[ i ]
344 try:
345 self.handle.sendline( routeCmd )
346 self.handle.expect( "bgpd", timeout=5 )
347 except:
348 main.log.warn( "Failed to add route" )
349 self.disconnect()
350 waitTimer = 1.00 / routeRate
351 time.sleep( waitTimer )
352 if routes_added == len( routes ):
353 main.log.info( "Finished adding routes" )
354 return main.TRUE
355 return main.FALSE
356
357 def delete_routes( self, routes, routeRate ):
358 main.log.info( "I am in delete_routes method!" )
359
360 routes_added = 0
361 try:
362 self.handle.sendline( "" )
363 # self.handle.expect( "config-router" )
364 self.handle.expect( "config-router", timeout=5 )
365 except:
366 main.log.warn( "Probably not in config-router mode!" )
367 self.disconnect()
368 main.log.info( "Start to delete routes" )
369
370 for i in range( 0, len( routes ) ):
371 routeCmd = "no network " + routes[ i ]
372 try:
373 self.handle.sendline( routeCmd )
374 self.handle.expect( "bgpd", timeout=5 )
375 except:
376 main.log.warn( "Failed to add route" )
377 self.disconnect()
378 waitTimer = 1.00 / routeRate
379 time.sleep( waitTimer )
380 if routes_added == len( routes ):
381 main.log.info( "Finished deleting routes" )
382 return main.TRUE
383 return main.FALSE
384
385 def ping_test( self, ip_address, ping_test_file, ping_test_result_file ):
386 main.log.info( "Start the ping test on host:" + str( ip_address ) )
387
388 self.name = self.options[ 'name' ]
389 self.handle = super( QuaggaCliDriver, self ).connect(
390 user_name=self.user_name, ip_address=ip_address,
391 port=self.port, pwd=self.pwd )
392 main.log.info( "connect parameters:" + str( self.user_name ) + ";"
393 + str( self.ip_address ) + ";" + str( self.port ) + ";" + str( self.pwd ) )
394
395 if self.handle:
396 # self.handle.expect( "" )
397 # self.handle.expect( "\$" )
398 main.log.info( "I in host " + str( ip_address ) )
399 main.log.info(
400 ping_test_file +
401 " > " +
402 ping_test_result_file +
403 " &" )
404 self.handle.sendline(
405 ping_test_file +
406 " > " +
407 ping_test_result_file +
408 " &" )
409 self.handle.expect( "\$", timeout=60 )
410 handle = self.handle.before
411
412 return handle
413 else:
414 main.log.info( "NO HANDLE" )
415 return main.FALSE
416
417 # Please use the generate_routes plus add_routes instead of this one
418 def add_route( self, net, numRoutes, routeRate ):
419 try:
420 self.handle.sendline( "" )
421 self.handle.expect( "config-router" )
422 except:
423 main.log.warn( "Probably not in config-router mode!" )
424 self.disconnect()
425 main.log.info( "Adding Routes" )
426 j = 0
427 k = 0
428 while numRoutes > 255:
429 numRoutes = numRoutes - 255
430 j = j + 1
431 k = numRoutes % 254
432 routes_added = 0
433 if numRoutes > 255:
434 numRoutes = 255
435 for m in range( 1, j + 1 ):
436 for n in range( 1, numRoutes + 1 ):
437 network = str(
438 net ) + "." + str(
439 m ) + "." + str(
440 n ) + ".0/24"
441 routeCmd = "network " + network
442 try:
443 self.handle.sendline( routeCmd )
444 self.handle.expect( "bgpd" )
445 except:
446 main.log.warn( "failed to add route" )
447 self.disconnect()
448 waitTimer = 1.00 / routeRate
449 time.sleep( waitTimer )
450 routes_added = routes_added + 1
451 for d in range( j + 1, j + 2 ):
452 for e in range( 1, k + 1 ):
453 network = str(
454 net ) + "." + str(
455 d ) + "." + str(
456 e ) + ".0/24"
457 routeCmd = "network " + network
458 try:
459 self.handle.sendline( routeCmd )
460 self.handle.expect( "bgpd" )
461 except:
462 main.log.warn( "failed to add route" )
463 self.disconnect
464 waitTimer = 1.00 / routeRate
465 time.sleep( waitTimer )
466 routes_added = routes_added + 1
467 if routes_added == numRoutes:
468 return main.TRUE
469 return main.FALSE
470
471 def del_route( self, net, numRoutes, routeRate ):
472 try:
473 self.handle.sendline( "" )
474 self.handle.expect( "config-router" )
475 except:
476 main.log.warn( "Probably not in config-router mode!" )
477 self.disconnect()
478 main.log.info( "Deleting Routes" )
479 j = 0
480 k = 0
481 while numRoutes > 255:
482 numRoutes = numRoutes - 255
483 j = j + 1
484 k = numRoutes % 254
485 routes_deleted = 0
486 if numRoutes > 255:
487 numRoutes = 255
488 for m in range( 1, j + 1 ):
489 for n in range( 1, numRoutes + 1 ):
490 network = str(
491 net ) + "." + str(
492 m ) + "." + str(
493 n ) + ".0/24"
494 routeCmd = "no network " + network
495 try:
496 self.handle.sendline( routeCmd )
497 self.handle.expect( "bgpd" )
498 except:
499 main.log.warn( "Failed to delete route" )
500 self.disconnect()
501 waitTimer = 1.00 / routeRate
502 time.sleep( waitTimer )
503 routes_deleted = routes_deleted + 1
504 for d in range( j + 1, j + 2 ):
505 for e in range( 1, k + 1 ):
506 network = str(
507 net ) + "." + str(
508 d ) + "." + str(
509 e ) + ".0/24"
510 routeCmd = "no network " + network
511 try:
512 self.handle.sendline( routeCmd )
513 self.handle.expect( "bgpd" )
514 except:
515 main.log.warn( "Failed to delete route" )
516 self.disconnect()
517 waitTimer = 1.00 / routeRate
518 time.sleep( waitTimer )
519 routes_deleted = routes_deleted + 1
520 if routes_deleted == numRoutes:
521 return main.TRUE
522 return main.FALSE
523
524 def check_routes( self, brand, ip, user, pw ):
525 def pronto( ip, user, passwd ):
526 print "Connecting to Pronto switch"
527 child = pexpect.spawn( "telnet " + ip )
528 i = child.expect( [ "login:", "CLI#", pexpect.TIMEOUT ] )
529 if i == 0:
530 print "Username and password required. Passing login info."
531 child.sendline( user )
532 child.expect( "Password:" )
533 child.sendline( passwd )
534 child.expect( "CLI#" )
535 print "Logged in, getting flowtable."
536 child.sendline( "flowtable brief" )
537 for t in range( 9 ):
538 t2 = 9 - t
539 print "\r" + str( t2 )
540 sys.stdout.write( "\033[F" )
541 time.sleep( 1 )
542 print "Scanning flowtable"
543 child.expect( "Flow table show" )
544 count = 0
545 while True:
546 i = child.expect(
547 [ '17\d\.\d{1,3}\.\d{1,3}\.\d{1,3}',
548 'CLI#',
549 pexpect.TIMEOUT ] )
550 if i == 0:
551 count = count + 1
552 elif i == 1:
553 print "Pronto flows: " + str( count ) + "\nDone\n"
554 break
555 else:
556 break
557
558 def cisco( ip, user, passwd ):
559 print "Establishing Cisco switch connection"
560 child = pexpect.spawn( "ssh " + user + "@" + ip )
561 i = child.expect( [ "Password:", "CLI#", pexpect.TIMEOUT ] )
562 if i == 0:
563 print "Password required. Passing now."
564 child.sendline( passwd )
565 child.expect( "#" )
566 print "Logged in. Retrieving flow table then counting flows."
567 child.sendline( "show openflow switch all flows all" )
568 child.expect( "Logical Openflow Switch" )
569 print "Flow table retrieved. Counting flows"
570 count = 0
571 while True:
572 i = child.expect( [ "nw_src=17", "#", pexpect.TIMEOUT ] )
573 if i == 0:
574 count = count + 1
575 elif i == 1:
576 print "Cisco flows: " + str( count ) + "\nDone\n"
577 break
578 else:
579 break
580 if brand == "pronto" or brand == "PRONTO":
581 pronto( ip, user, passwd )
582 # elif brand == "cisco" or brand == "CISCO":
583 # cisco( ip,user,passwd )
584
585 def disconnect( self ):
586 """
587 Called when Test is complete to disconnect the Quagga handle.
588 """
589 response = ''
590 try:
591 self.handle.close()
592 except:
593 main.log.error( "Connection failed to the host" )
594 response = main.FALSE
595 return response
596