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