blob: 7491eddafb85e7f341750d683784e08ec0d04969 [file] [log] [blame]
Steve McIntyrefdcb3782015-07-06 16:34:56 +01001#! /usr/bin/python
2
3# Copyright 2015 Linaro Limited
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18# MA 02110-1301, USA.
19
20import logging
21import pexpect
22import sys
23import re
24
25# Netgear XSM family driver
26# Developed and tested against the XSM7224S in the Linaro LAVA lab
27
28if __name__ == '__main__':
29 import os
30 vlandpath = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
31 sys.path.insert(0, vlandpath)
32 sys.path.insert(0, "%s/.." % vlandpath)
33
34from errors import InputError, PExpectError
35from drivers.common import SwitchDriver, SwitchErrors
36
37class NetgearXSM(SwitchDriver):
38
39 connection = None
40 _username = None
41 _password = None
42 _enable_password = None
43
44 _capabilities = [
45 'TrunkWildCardVlans' # Trunk ports are on all VLANs by
46 # default, so we shouldn't need to
47 # bugger with them
48 ]
49
50 # Regexps of expected hardware information - fail if we don't see
51 # this
52 _expected_manuf = re.compile('^Netgear')
53 _expected_model = re.compile('^XSM')
54
55 logfile = None
56
57 def __init__(self, switch_hostname, switch_telnetport=23, debug = False):
58 SwitchDriver.__init__(self)
59 self._systemdata = []
60 if debug:
61 self.logfile = sys.stderr
62 self.exec_string = "/usr/bin/telnet %s %d" % (switch_hostname, switch_telnetport)
63 self.errors = SwitchErrors()
64
65 ################################
66 ### Switch-level API functions
67 ################################
68
69 # Connect to the switch and log in
70 def switch_connect(self, username, password, enablepassword):
71 self._username = username
72 self._password = password
73 self._enable_password = enablepassword
74 self._switch_connect()
75
76 # Log out of the switch and drop the connection and all state
77 def switch_disconnect(self):
78 self._logout()
79 logging.debug("Closing connection: %s", self.connection)
80 self.connection.close(True)
81 self._ports = []
82 self._prompt_name = ''
83 self._systemdata = []
84 del(self)
85
86 # Save the current running config into flash - we want config to
87 # remain across reboots
88 def switch_save_running_config(self):
89 try:
90 self._cli("save")
91 self.connection.expect("Are you sure")
92 self._cli("y")
93 self.connection.expect("Configuration Saved!")
94 except (PExpectError, pexpect.EOF):
95 # recurse on error
96 self._switch_connect()
97 self.switch_save_running_config()
98
99 # Restart the switch - we need to reload config to do a
100 # roll-back. Do NOT save running-config first if the switch asks -
101 # we're trying to dump recent changes, not save them.
102 #
103 # This will also implicitly cause a connection to be closed
104 def switch_restart(self):
105 self._cli("reload")
106 index = self.connection.expect('Are you sure')
107 self._cli("y") # Yes, continue to reset
108 self.connection.close(True)
109
110 # List the capabilities of the switch (and driver) - some things
111 # make no sense to abstract. Returns a dict of strings, each one
112 # describing an extra feature that that higher levels may care
113 # about
114 def switch_get_capabilities(self):
115 return self._capabilities
116
117 ################################
118 ### VLAN API functions
119 ################################
120
121 # Create a VLAN with the specified tag
122 def vlan_create(self, tag):
123 logging.debug("Creating VLAN %d", tag)
124 try:
125 self._cli("vlan database")
126 self._cli("vlan %d" % tag)
127 self._end_configure()
128
129 # Validate it happened
130 vlans = self.vlan_get_list()
131 for vlan in vlans:
132 if vlan == tag:
133 return
134 raise IOError("Failed to create VLAN %d" % tag)
135
136 except PExpectError:
137 # recurse on error
138 self._switch_connect()
139 self.vlan_create(tag)
140
141 # Destroy a VLAN with the specified tag
142 def vlan_destroy(self, tag):
143 logging.debug("Destroying VLAN %d", tag)
144
145 try:
146 self._cli("vlan database")
147 self._cli("no vlan %d" % tag)
148 self._end_configure()
149
150 # Validate it happened
151 vlans = self.vlan_get_list()
152 for vlan in vlans:
153 if vlan == tag:
154 raise IOError("Failed to destroy VLAN %d" % tag)
155
156 except PExpectError:
157 # recurse on error
158 self._switch_connect()
159 self.vlan_destroy(tag)
160
161 # Set the name of a VLAN
162 def vlan_set_name(self, tag, name):
163 logging.debug("Setting name of VLAN %d to %s", tag, name)
164
165 try:
166 self._cli("vlan database")
167 self._cli("vlan name %d %s" % (tag, name))
168 self._end_configure()
169
170 # Validate it happened
171 read_name = self.vlan_get_name(tag)
172 if read_name != name:
173 raise IOError("Failed to set name for VLAN %d (name found is \"%s\", not \"%s\")"
174 % (tag, read_name, name))
175 except PExpectError:
176 # recurse on error
177 self._switch_connect()
178 self.vlan_set_name(tag, name)
179
180 # Get a list of the VLAN tags currently registered on the switch
181 def vlan_get_list(self):
182 logging.debug("Grabbing list of VLANs")
183
184 try:
185 vlans = []
186
187 regex = re.compile('^ *(\d+).*(Static)')
188
189 self._cli("show vlan brief")
190 for line in self._read_long_output("show vlan brief"):
191 match = regex.match(line)
192 if match:
193 vlans.append(int(match.group(1)))
194 return vlans
195
196 except PExpectError:
197 # recurse on error
198 self._switch_connect()
199 return self.vlan_get_list()
200
201 # For a given VLAN tag, ask the switch what the associated name is
202 def vlan_get_name(self, tag):
203
204 try:
205 logging.debug("Grabbing the name of VLAN %d", tag)
206 name = None
207 regex = re.compile('VLAN Name: (.*)')
208 self._cli("show vlan %d" % tag)
209 for line in self._read_long_output("show vlan"):
210 match = regex.match(line)
211 if match:
212 name = match.group(1)
213 name.strip()
214 return name
215
216 except PExpectError:
217 # recurse on error
218 self._switch_connect()
219 return self.vlan_get_name(tag)
220
221 ################################
222 ### Port API functions
223 ################################
224
225 # Set the mode of a port: access or trunk
226 def port_set_mode(self, port, mode):
227 logging.debug("Setting port %s to %s", port, mode)
228 if not self._is_port_mode_valid(mode):
229 raise InputError("Port mode %s is not allowed" % mode)
230 if not self._is_port_name_valid(port):
231 raise InputError("Port name %s not recognised" % port)
232
233 # This switch does not support specific modes, so we can't
234 # actually change the mode directly. However, we can and
235 # should deal with the PVID and memberships of existing VLANs
236 # etc.
237
238 try:
239 if mode == "trunk":
240 # We define a trunk port thus:
Steve McIntyred97ab292015-07-07 14:23:32 +0100241 # accept all frames on ingress
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100242 # exist on all current VLANs
243 # tag outgoing frames
244 # PVID should match the default VLAN (1).
245 self._configure()
246 self._cli("interface %s" % port)
Steve McIntyred97ab292015-07-07 14:23:32 +0100247 self._cli("vlan acceptframe all")
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100248 self._cli("no vlan ingressfilter")
249 self._cli("vlan tagging 1-4093")
250 self._cli("vlan pvid 1")
251 self._end_configure()
252
253 # We define an access port thus:
254 # accept only untagged frames on ingress
255 # exists on one VLAN only (1 by default)
256 # do not tag outgoing frames
257 # PVID should match the VLAN it's on (1 by default)
258 if mode == "access":
259 self._configure()
260 self._cli("interface %s" % port)
Steve McIntyreef73fca2015-07-07 14:57:59 +0100261 self._cli("vlan acceptframe admituntaggedonly")
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100262 self._cli("vlan ingressfilter")
263 self._cli("no vlan tagging 1-4093")
Steve McIntyreef73fca2015-07-07 14:57:59 +0100264 self._cli("vlan pvid 1") # Need to find the right VLAN first?
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100265 self._end_configure()
266
267 # Validate it happened
268 read_mode = self.port_get_mode(port)
269
270 if read_mode != mode:
271 raise IOError("Failed to set mode for port %s" % port)
272
273 except PExpectError:
274 # recurse on error
275 self._switch_connect()
276 self.port_set_mode(port, mode)
277
278 # Get the mode of a port: access or trunk
279 def port_get_mode(self, port):
280 logging.debug("Getting mode of port %s", port)
281 mode = ''
282 if not self._is_port_name_valid(port):
283 raise InputError("Port name %s not recognised" % port)
Steve McIntyreef73fca2015-07-07 14:57:59 +0100284 acceptframe_re = re.compile('vlan acceptframe (.*)')
285 ingress_re = re.compile('vlan ingressfilter')
286 tagging_re = re.compile('vlan tagging (.*)')
287
288 acceptframe = None
289 ingressfilter = True
290 tagging = None
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100291
292 try:
Steve McIntyreef73fca2015-07-07 14:57:59 +0100293 self._cli("show running-config interface %s" % port)
294 for line in self._read_long_output("show running-config interface"):
295
296 match = acceptframe_re.match(line)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100297 if match:
Steve McIntyreef73fca2015-07-07 14:57:59 +0100298 acceptframe = match.group(1)
299
300 match = ingress_re.match(line)
301 if match:
302 ingressfilter = True
303
304 match = tagging_re.match(line)
305 if match:
306 tagging = match.group(1)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100307
308 except PExpectError:
309 # recurse on error
310 self._switch_connect()
311 return self.port_get_mode(port)
312
Steve McIntyreef73fca2015-07-07 14:57:59 +0100313 # Simple classifier for now; may need to revisit later...
314 if (acceptframe == "untaggedonly" and ingressfilter == True):
315 return "access"
316 else:
317 return "trunk"
318
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100319 # Set an access port to be in a specified VLAN (tag)
320 def port_set_access_vlan(self, port, tag):
321 logging.debug("Setting access port %s to VLAN %d", port, tag)
322 if not self._is_port_name_valid(port):
323 raise InputError("Port name %s not recognised" % port)
324 if not (self.port_get_mode(port) == "access"):
325 raise InputError("Port %s not in access mode" % port)
326
327 try:
328 self._configure()
329 self._cli("interface %s" % port)
Steve McIntyreef73fca2015-07-07 14:57:59 +0100330 self._cli("vlan pvid %s" % tag)
331 # Find the list of VLANs we're currently on, and drop them
332 # all. "auto" mode is fine here, we won't be included
333 # unless we have GVRP configured, and we don't do
334 # that.
335 for current_vlan in self._get_port_vlans(port):
336 self._cli("vlan participation auto %s" % current_vlan)
337 # Now specifically include the VLAN we want
338 self._cli("vlan participation include %s" % tag)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100339 self._cli("no shutdown")
340 self._end_configure()
341
342 # Finally, validate things worked
343 read_vlan = int(self.port_get_access_vlan(port))
344 if read_vlan != tag:
345 raise IOError("Failed to move access port %d to VLAN %d - got VLAN %d instead"
346 % (port, tag, read_vlan))
347
348 except PExpectError:
349 # recurse on error
350 self._switch_connect()
351 self.port_set_access_vlan(port, tag)
352
Steve McIntyreef73fca2015-07-07 14:57:59 +0100353 # Add a trunk port to a specified VLAN (tag). Shouldn't be needed
354 # on this switch as we don't do VLAN ingress filtering on "trunk"
355 # ports, but...
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100356 def port_add_trunk_to_vlan(self, port, tag):
357 logging.debug("Adding trunk port %s to VLAN %d", port, tag)
358 if not self._is_port_name_valid(port):
359 raise InputError("Port name %s not recognised" % port)
360 if not (self.port_get_mode(port) == "trunk"):
361 raise InputError("Port %s not in trunk mode" % port)
362
363 try:
364 self._configure()
365 self._cli("interface %s" % port)
Steve McIntyreef73fca2015-07-07 14:57:59 +0100366 self._cli("vlan participation include %d" % tag)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100367 self._end_configure()
368
369 # Validate it happened
370 read_vlans = self.port_get_trunk_vlan_list(port)
371 for vlan in read_vlans:
372 if vlan == tag or vlan == "ALL":
373 return
374 raise IOError("Failed to add trunk port %s to VLAN %d" % (port, tag))
375
376 except PExpectError:
377 # recurse on error
378 self._switch_connect()
379 self.port_add_trunk_to_vlan(port, tag)
380
Steve McIntyreef73fca2015-07-07 14:57:59 +0100381 # Remove a trunk port from a specified VLAN (tag). Shouldn't be
382 # needed on this switch as we don't do VLAN ingress filtering on
383 # "trunk" ports, but...
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100384 def port_remove_trunk_from_vlan(self, port, tag):
385 logging.debug("Removing trunk port %s from VLAN %d", port, tag)
386 if not self._is_port_name_valid(port):
387 raise InputError("Port name %s not recognised" % port)
388 if not (self.port_get_mode(port) == "trunk"):
389 raise InputError("Port %s not in trunk mode" % port)
390
391 try:
392 self._configure()
393 self._cli("interface %s" % port)
Steve McIntyreef73fca2015-07-07 14:57:59 +0100394 self._cli("vlan participation auto %d" % tag)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100395 self._end_configure()
396
397 # Validate it happened
398 read_vlans = self.port_get_trunk_vlan_list(port)
399 for vlan in read_vlans:
400 if vlan == tag:
401 raise IOError("Failed to remove trunk port %s from VLAN %d" % (port, tag))
402
403 except PExpectError:
404 # recurse on error
405 self._switch_connect()
406 self.port_remove_trunk_from_vlan(port, tag)
407
408 # Get the configured VLAN tag for an access port (tag)
409 def port_get_access_vlan(self, port):
410 logging.debug("Getting VLAN for access port %s", port)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100411 if not self._is_port_name_valid(port):
412 raise InputError("Port name %s not recognised" % port)
413 if not (self.port_get_mode(port) == "access"):
414 raise InputError("Port %s not in access mode" % port)
Steve McIntyreef73fca2015-07-07 14:57:59 +0100415 return self._get_port_vlans(port)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100416
417 # Get the list of configured VLAN tags for a trunk port
418 def port_get_trunk_vlan_list(self, port):
Steve McIntyreef73fca2015-07-07 14:57:59 +0100419 logging.debug("Getting VLAN(s) for trunk port %s", port)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100420 if not self._is_port_name_valid(port):
421 raise InputError("Port name %s not recognised" % port)
422 if not (self.port_get_mode(port) == "trunk"):
423 raise InputError("Port %s not in trunk mode" % port)
Steve McIntyreef73fca2015-07-07 14:57:59 +0100424 return self._get_port_vlans(port)
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100425
426 ################################
427 ### Internal functions
428 ################################
429
430 # Connect to the switch and log in
431 def _switch_connect(self):
432
433 if not self.connection is None:
434 self.connection.close(True)
435 self.connection = None
436
437 logging.debug("Connecting to Switch with: %s", self.exec_string)
438 self.connection = pexpect.spawn(self.exec_string, logfile = self.logfile)
439
440 self._login()
441
442 # Avoid paged output
443 self._cli("terminal length 0")
444
445 # And grab details about the switch. in case we need it
446 self._get_systemdata()
447
448 # And also validate them - make sure we're driving a switch of
449 # the correct model! Also store the serial number
450 manuf_regex = re.compile('^Manufacturer([\.\s])+(\S+)')
451 model_regex = re.compile('^Machine Model([\.\s])+(\S+)')
452 sn_regex = re.compile('^Serial Number([\.\s])+(\S+)')
453 descr = ""
454
455 for line in self._systemdata:
456 match1 = manuf_regex.match(line)
457 if match1:
458 manuf = match1.group(2)
459
460 match2 = model_regex.match(line)
461 if match2:
462 model = match2.group(2)
463
464 match3 = sn_regex.match(line)
465 if match3:
466 self.serial_number = match3.group(2)
467
468 logging.debug("manufacturer is %s", manuf)
469 logging.debug("model is %s", model)
470 logging.debug("serial number is %s", self.serial_number)
471
472 if not (self._expected_manuf.match(manuf) and self._expected_model.match(model)):
473 raise IOError("Switch %s %s not recognised by this driver: abort" % (manuf, model))
474
475 # Now build a list of our ports, for later sanity checking
476 self._ports = self._get_port_names()
477 if len(self._ports) < 4:
478 raise IOError("Not enough ports detected - problem!")
479
480 def _login(self):
481 logging.debug("attempting login with username %s, password %s", self._username, self._password)
482 if self._username is not None:
483 self.connection.expect("User:")
484 self._cli("%s" % self._username)
485 if self._password is not None:
486 self.connection.expect("Password:")
487 self._cli("%s" % self._password, False)
488 while True:
489 index = self.connection.expect(['User:', 'Password:', 'Bad passwords', 'authentication failed', r'(.*)(#|>)'])
490 if index != 4: # Any other means: failed to log in!
491 logging.error("Login failure: index %d\n", index)
492 logging.error("Login failure: %s\n", self.connection.match.before)
493 raise IOError
494
495 # else
496 self._prompt_name = re.escape(self.connection.match.group(1).strip())
497 logging.error('\n\nSet _prompt_name to "%s"\n\n\n' % self._prompt_name)
498 if self.connection.match.group(2) == ">":
499 # Need to enter "enable" mode too
500 self._cli("enable")
501 if self._enable_password is not None:
502 self.connection.expect("Password:")
503 self._cli("%s" % self._enable_password, False)
504 index = self.connection.expect(['Password:', 'Bad passwords', 'authentication failed', r'(.*) *(#|>)'])
505 if index != 3: # Any other means: failed to log in!
506 logging.error("Enable password failure: %s\n", self.connection.match)
507 raise IOError
508 return 0
509
510 def _logout(self):
511 logging.debug("Logging out")
512 self._cli("quit", False)
513 self.connection.expect("Would you like to save them now")
514 self._cli("n")
515
516 def _configure(self):
517 self._cli("configure")
518
519 def _end_configure(self):
520 self._cli("exit")
521
522 def _read_long_output(self, text):
523 longbuf = []
524 prompt = self._prompt_name + '\s*#'
525 while True:
526 try:
527 index = self.connection.expect(['--More--', prompt])
528 if index == 0: # "--More-- or (q)uit"
529 for line in self.connection.before.split('\r\n'):
530 line1 = re.sub('(\x08|\x0D)*', '', line.strip())
531 longbuf.append(line1)
532 self._cli(' ', False)
533 elif index == 1: # Back to a prompt, says output is finished
534 break
535 except (pexpect.EOF, pexpect.TIMEOUT):
536 # Something went wrong; logout, log in and try again!
537 logging.error("PEXPECT FAILURE, RECONNECT")
538 self.errors.log_error_in(text)
539 raise PExpectError("_read_long_output failed")
540 except:
541 logging.error("prompt is \"%s\"", prompt)
542 raise
543
544 for line in self.connection.before.split('\r\n'):
545 longbuf.append(line.strip())
546 return longbuf
547
548 def _get_port_names(self):
549 logging.debug("Grabbing list of ports")
550 interfaces = []
551
552 # Use "Up" or "Down" to only identify lines in the output that
553 # match interfaces that exist
554 regex = re.compile('^(1\S+)')
555
556 try:
557 self._cli("show port all")
558 for line in self._read_long_output("show port all"):
559 match = regex.match(line)
560 if match:
561 interface = match.group(1)
562 interfaces.append(interface)
563 return interfaces
564
565 except PExpectError:
566 # recurse on error
567 self._switch_connect()
568 return self._get_port_names()
569
570 def _show_config(self):
571 logging.debug("Grabbing config")
572 try:
573 self._cli("show running-config")
574 return self._read_long_output("show running-config")
575 except PExpectError:
576 # recurse on error
577 self._switch_connect()
578 return self._show_config()
579
580 def _show_clock(self):
581 logging.debug("Grabbing time")
582 try:
583 self._cli("show clock")
584 return self._read_long_output("show clock")
585 except PExpectError:
586 # recurse on error
587 self._switch_connect()
588 return self._show_clock()
589
590 def _get_systemdata(self):
591 logging.debug("Grabbing system sw and hw versions")
592
593 try:
594 self._systemdata = []
595 self._cli("show version")
596 for line in self._read_long_output("show version"):
597 self._systemdata.append(line)
598
599 except PExpectError:
600 # recurse on error
601 self._switch_connect()
602 return self._get_systemdata()
603
604 def _parse_vlan_list(self, inputdata):
605 vlans = []
606
607 if inputdata == "ALL":
608 return ["ALL"]
609 elif inputdata == "NONE":
610 return []
611 else:
612 # Parse the complex list
613 groups = inputdata.split(',')
614 for group in groups:
615 subgroups = group.split('-')
616 if len(subgroups) == 1:
617 vlans.append(int(subgroups[0]))
618 elif len(subgroups) == 2:
619 for i in range (int(subgroups[0]), int(subgroups[1]) + 1):
620 vlans.append(i)
621 else:
622 logging.debug("Can't parse group \"" + group + "\"")
623
624 return vlans
625
Steve McIntyreef73fca2015-07-07 14:57:59 +0100626 def _get_port_vlans(self, port):
627 vlan_text = None
628
629 vlan_part_re = re.compile('vlan participation (.*)')
630
631 try:
632 self._cli("show running-config interface %s" % port)
633 for line in self._read_long_output("show running-config interface"):
634 match = vlan_part_re.match(line)
635 if match:
636 if vlan_text != None:
637 vlan_text += ","
638 vlan_text += (match.group(1))
639 else:
640 vlan_text = match.group(1)
641
642 vlans = self._parse_vlan_list(vlan_text)
643 return vlans
644
645 except PExpectError:
646 # recurse on error
647 self._switch_connect()
648 return self._get_port_vlans(port)
649
Steve McIntyrefdcb3782015-07-06 16:34:56 +0100650 # Wrapper around connection.send - by default, expect() the same
651 # text we've sent, to remove it from the output from the
652 # switch. For the few cases where we don't need that, override
653 # this using echo=False.
654 # Horrible, but seems to work.
655 def _cli(self, text, echo=True):
656 self.connection.send(text + '\r')
657 if echo:
658 try:
659 self.connection.expect(text)
660 except (pexpect.EOF, pexpect.TIMEOUT):
661 # Something went wrong; logout, log in and try again!
662 logging.error("PEXPECT FAILURE, RECONNECT")
663 self.errors.log_error_out(text)
664 raise PExpectError("_cli failed on %s" % text)
665 except:
666 logging.error("Unexpected error: %s", sys.exc_info()[0])
667 raise
668
669if __name__ == "__main__":
670
671 import optparse
672
673 switch = 'vlandswitch05'
674 parser = optparse.OptionParser()
675 parser.add_option("--switch",
676 dest = "switch",
677 action = "store",
678 nargs = 1,
679 type = "string",
680 help = "specify switch to connect to for testing",
681 metavar = "<switch>")
682 (opts, args) = parser.parse_args()
683 if opts.switch:
684 switch = opts.switch
685
686 p = NetgearXSM(switch, 23, debug=True)
687 p.switch_connect('admin', '', None)
688
689 print "VLANs are:"
690 buf = p.vlan_get_list()
691 p.dump_list(buf)
692
693 buf = p.vlan_get_name(2)
694 print "VLAN 2 is named \"%s\"" % buf
695
696 print "Create VLAN 3"
697 p.vlan_create(3)
698
699 buf = p.vlan_get_name(3)
700 print "VLAN 3 is named \"%s\"" % buf
701
702 print "Set name of VLAN 3 to test333"
703 p.vlan_set_name(3, "test333")
704
705 buf = p.vlan_get_name(3)
706 print "VLAN 3 is named \"%s\"" % buf
707
708 print "VLANs are:"
709 buf = p.vlan_get_list()
710 p.dump_list(buf)
711
712 print "Destroy VLAN 3"
713 p.vlan_destroy(3)
714
715 print "VLANs are:"
716 buf = p.vlan_get_list()
717 p.dump_list(buf)
718
719 buf = p.port_get_mode("1/0/10")
720 print "Port 1/0/10 is in %s mode" % buf
721
722 buf = p.port_get_mode("1/0/11")
723 print "Port 1/0/11 is in %s mode" % buf
724
725 # Test access stuff
726 print "Set 1/0/9 to access mode"
727 p.port_set_mode("1/0/9", "access")
728
729 print "Move 1/0/9 to VLAN 4"
730 p.port_set_access_vlan("1/0/9", 4)
731
732 buf = p.port_get_access_vlan("1/0/9")
733 print "Read from switch: 1/0/9 is on VLAN %s" % buf
734
735 print "Move 1/0/9 back to VLAN 1"
736 p.port_set_access_vlan("1/0/9", 1)
737
738 # Test access stuff
739 print "Set 1/0/9 to trunk mode"
740 p.port_set_mode("1/0/9", "trunk")
741 print "Read from switch: which VLANs is 1/0/9 on?"
742 buf = p.port_get_trunk_vlan_list("1/0/9")
743 p.dump_list(buf)
744 print "Add 1/0/9 to VLAN 2"
745 p.port_add_trunk_to_vlan("1/0/9", 2)
746 print "Add 1/0/9 to VLAN 3"
747 p.port_add_trunk_to_vlan("1/0/9", 3)
748 print "Add 1/0/9 to VLAN 4"
749 p.port_add_trunk_to_vlan("1/0/9", 4)
750 print "Read from switch: which VLANs is 1/0/9 on?"
751 buf = p.port_get_trunk_vlan_list("1/0/9")
752 p.dump_list(buf)
753
754 p.port_remove_trunk_from_vlan("1/0/9", 3)
755 p.port_remove_trunk_from_vlan("1/0/9", 3)
756 p.port_remove_trunk_from_vlan("1/0/9", 4)
757 print "Read from switch: which VLANs is 1/0/9 on?"
758 buf = p.port_get_trunk_vlan_list("1/0/9")
759 p.dump_list(buf)
760
761# print 'Restarting switch, to explicitly reset config'
762# p.switch_restart()
763
764# p.switch_save_running_config()
765
766# p.switch_disconnect()
767# p._show_config()