blob: 0f84bc03b01f1414a1fbb9c7ecc867ddd9c05d4c [file] [log] [blame]
timlindbergef8d55d2013-09-27 12:50:13 -07001#!/usr/bin/env python
2
3import time
4import pexpect
5import struct, fcntl, os, sys, signal
6import sys
7import re
8import json
9sys.path.append("../")
10from drivers.common.clidriver import CLI
11
12class QuaggaCliDriver(CLI):
13
14 def __init__(self):
15 super(CLI, self).__init__()
16
pingping-lin8b306ac2014-11-17 18:13:51 -080017 #TODO: simplify this method
timlindbergef8d55d2013-09-27 12:50:13 -070018 def connect(self, **connectargs):
19 for key in connectargs:
20 vars(self)[key] = connectargs[key]
21
22 self.name = self.options['name']
pingping-lin8b306ac2014-11-17 18:13:51 -080023 #self.handle = super(QuaggaCliDriver,self).connect(user_name = self.user_name, ip_address = self.ip_address,port = self.port, pwd = self.pwd)
24 self.handle = super(QuaggaCliDriver, self).connect(user_name=self.user_name, ip_address="1.1.1.1", port=self.port, pwd=self.pwd)
25 main.log.info("connect parameters:" + str(self.user_name) + ";" + str(self.ip_address) + ";" + str(self.port) + ";" + str(self.pwd))
timlindbergef8d55d2013-09-27 12:50:13 -070026
27 if self.handle:
28 self.handle.expect("")
29 self.handle.expect("\$")
30 self.handle.sendline("telnet localhost 2605")
31 self.handle.expect("Password:", timeout = 5)
32 self.handle.sendline("hello")
33 self.handle.expect("bgpd",timeout = 5)
34 self.handle.sendline("enable")
35 self.handle.expect("bgpd#", timeout = 5)
36 return self.handle
37 else :
38 main.log.info("NO HANDLE")
39 return main.FALSE
40
pingping-lin8b306ac2014-11-17 18:13:51 -080041 def loginQuagga(self, ip_address):
pingping-lin8b306ac2014-11-17 18:13:51 -080042 self.name = self.options['name']
43 self.handle = super(QuaggaCliDriver, self).connect(
44 user_name=self.user_name, ip_address=ip_address,
45 port=self.port, pwd=self.pwd)
46 main.log.info("connect parameters:" + str(self.user_name) + ";"
47 + str(self.ip_address) + ";" + str(self.port) + ";" + str(self.pwd))
48
49 if self.handle:
50 self.handle.expect("")
51 self.handle.expect("\$")
52 self.handle.sendline("telnet localhost 2605")
53 self.handle.expect("Password:", timeout=5)
54 self.handle.sendline("hello")
55 self.handle.expect("bgpd", timeout=5)
56 self.handle.sendline("enable")
57 self.handle.expect("bgpd#", timeout=5)
pingping-lin36fbe802014-11-25 16:01:14 -080058 main.log.info("I in quagga on host " + str(ip_address))
pingping-lin8b306ac2014-11-17 18:13:51 -080059
60 return self.handle
61 else:
62 main.log.info("NO HANDLE")
63 return main.FALSE
64
timlindbergef8d55d2013-09-27 12:50:13 -070065 def enter_config(self, asn):
pingping-lin8b306ac2014-11-17 18:13:51 -080066 main.log.info("I am in enter_config method!")
timlindbergef8d55d2013-09-27 12:50:13 -070067 try:
68 self.handle.sendline("")
69 self.handle.expect("bgpd#")
70 except:
71 main.log.warn("Probably not currently in enable mode!")
72 self.disconnect()
73 return main.FALSE
74 self.handle.sendline("configure terminal")
75 self.handle.expect("config", timeout = 5)
76 routerAS = "router bgp " + str(asn)
77 try:
78 self.handle.sendline(routerAS)
79 self.handle.expect("config-router", timeout = 5)
80 return main.TRUE
81 except:
82 return main.FALSE
pingping-lin8b306ac2014-11-17 18:13:51 -080083
pingping-lin6f6332e2014-11-19 19:13:58 -080084 def generate_prefixes(self, net, numRoutes):
85 main.log.info("I am in generate_prefixes method!")
86
87 # each IP prefix will be composed by "net" + "." + m + "." + n + "." + x
pingping-lin8b306ac2014-11-17 18:13:51 -080088 # the length of each IP prefix is 24
89 routes = []
90 routes_gen = 0
91 m = numRoutes / 256
92 n = numRoutes % 256
93
94 for i in range(0, m):
95 for j in range(0, 256):
96 network = str(net) + "." + str(i) + "." + str(j) + ".0/24"
97 routes.append(network)
98 routes_gen = routes_gen + 1
99
100 for j in range(0, n):
101 network = str(net) + "." + str(m) + "." + str(j) + ".0/24"
102 routes.append(network)
103 routes_gen = routes_gen + 1
104
105 if routes_gen == numRoutes:
106 main.log.info("Successfully generated " + str(numRoutes)
pingping-lin6f6332e2014-11-19 19:13:58 -0800107 + " prefixes!")
pingping-lin8b306ac2014-11-17 18:13:51 -0800108 return routes
109 return main.FALSE
pingping-lin6f6332e2014-11-19 19:13:58 -0800110
111 # This method generates a multiple to single point intent(MultiPointToSinglePointIntent) for a given route
112 def generate_expected_singleRouteIntent(self, prefix, nextHop, nextHopMac, sdnip_data):
113
114 ingress = []
115 egress = ""
116 for peer in sdnip_data['bgpPeers']:
117 if peer['ipAddress'] == nextHop:
118 egress = "of:" + str(peer['attachmentDpid']).replace(":", "") + ":" + str(peer['attachmentPort'])
119 else:
120 ingress.append("of:" + str(peer['attachmentDpid']).replace(":", "") + ":" + str(peer['attachmentPort']) )
121
pingping-lin36fbe802014-11-25 16:01:14 -0800122 selector = "[ETH_TYPE{ethType=800}, IPV4_DST{ip=" + prefix + "}]"
pingping-lin6f6332e2014-11-19 19:13:58 -0800123 treatment = "[ETH_DST{mac=" + str(nextHopMac) + "}]"
124
125 intent = egress + "/" + str(sorted(ingress)) + "/" + selector + "/" + treatment
126 return intent
127
128 def generate_expected_onePeerRouteIntents(self, prefixes, nextHop, nextHopMac, sdnip_json_file_path):
129 intents = []
130 sdnip_json_file=open(sdnip_json_file_path).read()
131
132 sdnip_data = json.loads(sdnip_json_file)
133
134 for prefix in prefixes:
135 intents.append(self.generate_expected_singleRouteIntent(prefix, nextHop, nextHopMac, sdnip_data))
136 return sorted(intents)
137
138 # TODO
139 # This method generates all expected route intents for all BGP peers
140 def generate_expected_routeIntents(self):
141 intents = []
142 return intents
143
144 # This method extracts all actual routes from ONOS CLI
145 def extract_actual_routes(self, get_routes_result):
146 routes_json_obj = json.loads(get_routes_result)
147
148 allRoutes_actual = []
149 for route in routes_json_obj:
150 if route['prefix'] == '172.16.10.0/24':
151 continue
152 allRoutes_actual.append(route['prefix'] + "/" + route['nextHop'])
153
154 return sorted(allRoutes_actual)
155
156 # This method extracts all actual route intents from ONOS CLI
157 def extract_actual_routeIntents(self, get_intents_result):
158 intents = []
159 # TODO: delete the line below when change to Mininet demo script
pingping-lin36fbe802014-11-25 16:01:14 -0800160 # get_intents_result=open("../tests/SdnIpTest/intents.json").read()
pingping-lin6f6332e2014-11-19 19:13:58 -0800161 intents_json_obj = json.loads(get_intents_result)
162
163 for intent in intents_json_obj:
164 if intent['appId'] != "org.onlab.onos.sdnip" :
165 continue
166 if intent['type'] == "MultiPointToSinglePointIntent":
167 egress = str(intent['egress']['device'])+ ":" + str(intent['egress']['port'])
168 ingress = []
169 for attachmentPoint in intent['ingress']:
170 ingress.append(str(attachmentPoint['device']) + ":" + str(attachmentPoint['port']))
171 intent = egress + "/" + str(sorted(ingress)) + "/" + intent['selector'] + "/" + intent['treatment']
172 intents.append(intent)
173 return sorted(intents)
174
175 # This method extracts all actual BGP intents from ONOS CLI
176 def extract_actual_bgpIntents(self, get_intents_result):
177 intents = []
178 # TODO: delete the line below when change to Mininet demo script
pingping-lin36fbe802014-11-25 16:01:14 -0800179 # get_intents_result=open("../tests/SdnIpTest/intents.json").read()
pingping-lin6f6332e2014-11-19 19:13:58 -0800180 intents_json_obj = json.loads(get_intents_result)
181
182 for intent in intents_json_obj:
183 if intent['appId'] != "org.onlab.onos.sdnip":
184 continue
185 if intent['type'] == "PointToPointIntent" and "protocol=6" in str(intent['selector']):
186 ingress = str(intent['ingress']['device']) + ":" + str(intent['ingress']['port'])
187 egress = str(intent['egress']['device']) + ":" + str(intent['egress']['port'])
188 selector = str(intent['selector']).replace(" ", "").replace("[", "").replace("]", "").split(",")
189 intent = ingress + "/" + egress + "/" + str(sorted(selector))
190 intents.append(intent)
191
192 return sorted(intents)
193
194 # This method generates a single point to single point intent(PointToPointIntent) for BGP path
195 def generate_expected_bgpIntents(self, sdnip_json_file_path):
196 from operator import eq
197
198 sdnip_json_file=open(sdnip_json_file_path).read()
199 sdnip_data = json.loads(sdnip_json_file)
200
201 intents = []
202 bgpPeerAttachmentPoint=""
203 bgpSpeakerAttachmentPoint = "of:" + str(sdnip_data['bgpSpeakers'][0]['attachmentDpid']).replace(":", "") + ":" + str(sdnip_data['bgpSpeakers'][0]['attachmentPort'])
204 for peer in sdnip_data['bgpPeers']:
205 bgpPeerAttachmentPoint = "of:" + str(peer['attachmentDpid']).replace(":", "") + ":" + str(peer['attachmentPort'])
206 # find out the BGP speaker IP address for this BGP peer
207 bgpSpeakerIpAddress=""
208 for interfaceAddress in sdnip_data['bgpSpeakers'][0]['interfaceAddresses']:
209 #if eq(interfaceAddress['interfaceDpid'],sdnip_data['bgpSpeakers'][0]['attachmentDpid']) and eq(interfaceAddress['interfacePort'], sdnip_data['bgpSpeakers'][0]['attachmentPort']):
210 if eq(interfaceAddress['interfaceDpid'],peer['attachmentDpid']) and eq(interfaceAddress['interfacePort'], peer['attachmentPort']):
211 bgpSpeakerIpAddress = interfaceAddress['ipAddress']
212 break
213 else:
214 continue
215
216 # from bgpSpeakerAttachmentPoint to bgpPeerAttachmentPoint direction
217 selector_str = "IPV4_SRC{ip=" + bgpSpeakerIpAddress + "/32}," + "IPV4_DST{ip=" + peer['ipAddress']+ "/32}," + "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_DST{tcpPort=179}"
218 selector = selector_str.replace(" ", "").replace("[", "").replace("]", "").split(",")
219 intent = bgpSpeakerAttachmentPoint + "/" + bgpPeerAttachmentPoint + "/" + str(sorted(selector))
220 intents.append(intent)
221
222 selector_str = "IPV4_SRC{ip=" + bgpSpeakerIpAddress + "/32}," + "IPV4_DST{ip=" + peer['ipAddress']+ "/32}," + "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_SRC{tcpPort=179}"
223 selector = selector_str.replace(" ", "").replace("[", "").replace("]", "").split(",")
224 intent = bgpSpeakerAttachmentPoint + "/" + bgpPeerAttachmentPoint + "/" + str(sorted(selector))
225 intents.append(intent)
226
227 # from bgpPeerAttachmentPoint to bgpSpeakerAttachmentPoint direction
228 selector_str = "IPV4_SRC{ip=" + peer['ipAddress'] + "/32}," + "IPV4_DST{ip=" + bgpSpeakerIpAddress + "/32}," + "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_DST{tcpPort=179}"
229 selector = selector_str.replace(" ", "").replace("[", "").replace("]", "").split(",")
230 intent = bgpPeerAttachmentPoint + "/" + bgpSpeakerAttachmentPoint + "/" + str(sorted(selector))
231 intents.append(intent)
232
233 selector_str = "IPV4_SRC{ip=" + peer['ipAddress'] + "/32}," + "IPV4_DST{ip=" + bgpSpeakerIpAddress + "/32}," + "IP_PROTO{protocol=6}, ETH_TYPE{ethType=800}, TCP_SRC{tcpPort=179}"
234 selector = selector_str.replace(" ", "").replace("[", "").replace("]", "").split(",")
235 intent = bgpPeerAttachmentPoint + "/" + bgpSpeakerAttachmentPoint + "/" + str(sorted(selector))
236 intents.append(intent)
237
238 return sorted(intents)
pingping-lin8b306ac2014-11-17 18:13:51 -0800239
240 def add_routes(self, routes, routeRate):
241 main.log.info("I am in add_routes method!")
242
243 routes_added = 0
244 try:
245 self.handle.sendline("")
246 #self.handle.expect("config-router")
247 self.handle.expect("config-router", timeout=5)
248 except:
249 main.log.warn("Probably not in config-router mode!")
250 self.disconnect()
251 main.log.info("Start to add routes")
252
253 for i in range(0, len(routes)):
254 routeCmd = "network " + routes[i]
255 try:
256 self.handle.sendline(routeCmd)
257 self.handle.expect("bgpd", timeout=5)
258 except:
259 main.log.warn("Failed to add route")
260 self.disconnect()
261 waitTimer = 1.00 / routeRate
262 time.sleep(waitTimer)
263 if routes_added == len(routes):
264 main.log.info("Finished adding routes")
265 return main.TRUE
266 return main.FALSE
267
pingping-lin6f6332e2014-11-19 19:13:58 -0800268 # Please use the generate_routes plus add_routes instead of this one
timlindbergef8d55d2013-09-27 12:50:13 -0700269 def add_route(self, net, numRoutes, routeRate):
270 try:
271 self.handle.sendline("")
272 self.handle.expect("config-router")
273 except:
274 main.log.warn("Probably not in config-router mode!")
275 self.disconnect()
pingping-lin36fbe802014-11-25 16:01:14 -0800276 main.log.info("Adding Routes")
timlindbergef8d55d2013-09-27 12:50:13 -0700277 j=0
278 k=0
279 while numRoutes > 255:
280 numRoutes = numRoutes - 255
281 j = j + 1
282 k = numRoutes % 254
283 routes_added = 0
284 if numRoutes > 255:
285 numRoutes = 255
286 for m in range(1,j+1):
287 for n in range(1, numRoutes+1):
288 network = str(net) + "." + str(m) + "." + str(n) + ".0/24"
289 routeCmd = "network " + network
290 try:
291 self.handle.sendline(routeCmd)
292 self.handle.expect("bgpd")
293 except:
294 main.log.warn("failed to add route")
295 self.disconnect()
296 waitTimer = 1.00/routeRate
297 time.sleep(waitTimer)
298 routes_added = routes_added + 1
299 for d in range(j+1,j+2):
300 for e in range(1,k+1):
301 network = str(net) + "." + str(d) + "." + str(e) + ".0/24"
302 routeCmd = "network " + network
303 try:
304 self.handle.sendline(routeCmd)
305 self.handle.expect("bgpd")
306 except:
307 main.log.warn("failed to add route")
308 self.disconnect
309 waitTimer = 1.00/routeRate
310 time.sleep(waitTimer)
311 routes_added = routes_added + 1
312 if routes_added == numRoutes:
313 return main.TRUE
314 return main.FALSE
pingping-lin6f6332e2014-11-19 19:13:58 -0800315
timlindbergef8d55d2013-09-27 12:50:13 -0700316 def del_route(self, net, numRoutes, routeRate):
317 try:
318 self.handle.sendline("")
319 self.handle.expect("config-router")
320 except:
321 main.log.warn("Probably not in config-router mode!")
322 self.disconnect()
pingping-lin36fbe802014-11-25 16:01:14 -0800323 main.log.info("Deleting Routes")
timlindbergef8d55d2013-09-27 12:50:13 -0700324 j=0
325 k=0
326 while numRoutes > 255:
327 numRoutes = numRoutes - 255
328 j = j + 1
329 k = numRoutes % 254
330 routes_deleted = 0
331 if numRoutes > 255:
332 numRoutes = 255
333 for m in range(1,j+1):
334 for n in range(1, numRoutes+1):
335 network = str(net) + "." + str(m) + "." + str(n) + ".0/24"
336 routeCmd = "no network " + network
337 try:
338 self.handle.sendline(routeCmd)
339 self.handle.expect("bgpd")
340 except:
341 main.log.warn("Failed to delete route")
342 self.disconnect()
343 waitTimer = 1.00/routeRate
344 time.sleep(waitTimer)
345 routes_deleted = routes_deleted + 1
346 for d in range(j+1,j+2):
347 for e in range(1,k+1):
348 network = str(net) + "." + str(d) + "." + str(e) + ".0/24"
349 routeCmd = "no network " + network
350 try:
351 self.handle.sendline(routeCmd)
352 self.handle.expect("bgpd")
353 except:
354 main.log.warn("Failed to delete route")
355 self.disconnect()
356 waitTimer = 1.00/routeRate
357 time.sleep(waitTimer)
358 routes_deleted = routes_deleted + 1
359 if routes_deleted == numRoutes:
360 return main.TRUE
361 return main.FALSE
362 def check_routes(self, brand, ip, user, pw):
363 def pronto(ip, user, passwd):
364 print "Connecting to Pronto switch"
365 child = pexpect.spawn("telnet " + ip)
366 i = child.expect(["login:", "CLI#",pexpect.TIMEOUT])
367 if i == 0:
368 print "Username and password required. Passing login info."
369 child.sendline(user)
370 child.expect("Password:")
371 child.sendline(passwd)
372 child.expect("CLI#")
373 print "Logged in, getting flowtable."
374 child.sendline("flowtable brief")
375 for t in range (9):
376 t2 = 9 - t
377 print "\r" + str(t2)
378 sys.stdout.write("\033[F")
379 time.sleep(1)
380 print "Scanning flowtable"
381 child.expect("Flow table show")
382 count = 0
383 while 1:
384 i = child.expect(['17\d\.\d{1,3}\.\d{1,3}\.\d{1,3}','CLI#',pexpect.TIMEOUT])
385 if i == 0:
386 count = count + 1
387 elif i == 1:
388 print "Pronto flows: " + str(count) + "\nDone\n"
389 break
390 else:
391 break
392 def cisco(ip,user,passwd):
393 print "Establishing Cisco switch connection"
394 child = pexpect.spawn("ssh " + user + "@" + ip)
395 i = child.expect(["Password:", "CLI#",pexpect.TIMEOUT])
396 if i == 0:
397 print "Password required. Passing now."
398 child.sendline(passwd)
399 child.expect("#")
400 print "Logged in. Retrieving flow table then counting flows."
401 child.sendline("show openflow switch all flows all")
402 child.expect("Logical Openflow Switch")
403 print "Flow table retrieved. Counting flows"
404 count = 0
405 while 1:
406 i = child.expect(["nw_src=17","#",pexpect.TIMEOUT])
407 if i == 0:
408 count = count + 1
409 elif i == 1:
410 print "Cisco flows: " + str(count) + "\nDone\n"
411 break
412 else:
413 break
414 if brand == "pronto" or brand == "PRONTO":
415 pronto(ip,user,passwd)
416 #elif brand == "cisco" or brand == "CISCO":
417 # cisco(ip,user,passwd)
418 def disconnect(self):
419 '''
420 Called when Test is complete to disconnect the Quagga handle.
421 '''
422 response = ''
423 try:
424 self.handle.close()
425 except:
426 main.log.error("Connection failed to the host")
427 response = main.FALSE
428 return response