blob: ea74bf09bb2eba1d9e254850071917e13d182120 [file] [log] [blame]
Steve McIntyre59ffe892018-01-24 16:46:00 +00001#! /usr/bin/python
2
3# Copyright 2018 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 sys
22import re
23import pexpect
24
25# Mellanox MLNX-OS driver
26# Developed and tested against the SN2100 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
Steve McIntyre4ed20f32018-01-24 17:21:37 +000037class Mellanox(SwitchDriver):
Steve McIntyre59ffe892018-01-24 16:46:00 +000038
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 # Regexp of expected hardware information - fail if we don't see
51 # this
52 _expected_descr_re = re.compile(r'MLNX-OS')
53
54 def __init__(self, switch_hostname, switch_telnetport=23, debug = False):
55 SwitchDriver.__init__(self, switch_hostname, debug)
56 self._systemdata = []
57 self.exec_string = "/usr/bin/telnet %s %d" % (switch_hostname, switch_telnetport)
58 self.errors = SwitchErrors()
59
60 ################################
61 ### Switch-level API functions
62 ################################
63
64 # Save the current running config into flash - we want config to
65 # remain across reboots
66 def switch_save_running_config(self):
67 try:
68 self._configure()
69 self._cli("configuration write")
70 self._end_configure()
71 except (PExpectError, pexpect.EOF):
72 # recurse on error
73 self._switch_connect()
74 self.switch_save_running_config()
75
76 # Restart the switch - we need to reload config to do a
77 # roll-back. Do NOT save running-config first if the switch asks -
78 # we're trying to dump recent changes, not save them.
79 #
80 # This will also implicitly cause a connection to be closed
81 def switch_restart(self):
82 self._cli("reload noconfirm")
83
84 # List the capabilities of the switch (and driver) - some things
85 # make no sense to abstract. Returns a dict of strings, each one
86 # describing an extra feature that that higher levels may care
87 # about
88 def switch_get_capabilities(self):
89 return self._capabilities
90
91 ################################
92 ### VLAN API functions
93 ################################
94
95 # Create a VLAN with the specified tag
96 def vlan_create(self, tag):
97 logging.debug("Creating VLAN %d", tag)
98 try:
99 self._configure()
100 self._cli("vlan %d" % tag)
101 self._end_vlan()
102 self._end_configure()
103
104 # Validate it happened
105 vlans = self.vlan_get_list()
106 for vlan in vlans:
107 if vlan == tag:
108 return
109 raise IOError("Failed to create VLAN %d" % tag)
110
111 except PExpectError:
112 # recurse on error
113 self._switch_connect()
114 self.vlan_create(tag)
115
116 # Destroy a VLAN with the specified tag
117 def vlan_destroy(self, tag):
118 logging.debug("Destroying VLAN %d", tag)
119
120 try:
121 self._configure()
122 self._cli("no vlan %d" % tag)
123 self._end_configure()
124
125 # Validate it happened
126 vlans = self.vlan_get_list()
127 for vlan in vlans:
128 if vlan == tag:
129 raise IOError("Failed to destroy VLAN %d" % tag)
130
131 except PExpectError:
132 # recurse on error
133 self._switch_connect()
134 self.vlan_destroy(tag)
135
136 # Set the name of a VLAN
137 def vlan_set_name(self, tag, name):
138 logging.debug("Setting name of VLAN %d to %s", tag, name)
139
140 try:
141 self._configure()
142 self._cli("vlan %d name %s" % (tag, name))
143 self._end_configure()
144
Steve McIntyre7b1aa392018-02-08 12:33:17 +0000145 # This switch *might* have problems if we drive it too quickly? At
146 # least one instance of set_name()/get_name() not working. This
147 # might help?
148 self._delay()
149
150 # And retry around here
151 retries = 5
152 read_name = None
153 while (retries > 0 and read_name is None):
154 # Validate it happened
155 read_name = self.vlan_get_name(tag)
156 retries -= 1
157
Steve McIntyre59ffe892018-01-24 16:46:00 +0000158 if read_name != name:
159 raise IOError("Failed to set name for VLAN %d (name found is \"%s\", not \"%s\")"
160 % (tag, read_name, name))
161 except PExpectError:
162 # recurse on error
163 self._switch_connect()
164 self.vlan_set_name(tag, name)
165
166 # Get a list of the VLAN tags currently registered on the switch
167 def vlan_get_list(self):
168 logging.debug("Grabbing list of VLANs")
169
170 try:
171 vlans = []
172
173 regex = re.compile(r'^ *(\d+)')
174
175 self._cli("show vlan")
176 for line in self._read_long_output("show vlan"):
177 match = regex.match(line)
178 if match:
179 vlans.append(int(match.group(1)))
180 return vlans
181
182 except PExpectError:
183 # recurse on error
184 self._switch_connect()
185 return self.vlan_get_list()
186
187 # For a given VLAN tag, ask the switch what the associated name is
188 def vlan_get_name(self, tag):
189
190 try:
191 logging.debug("Grabbing the name of VLAN %d", tag)
192 name = None
193
194 # Ugh, the output here is messy. VLAN names can include spaces, and
195 # there are no delimiters in the output, e.g.:
196 # VLAN Name Ports
197 # ---- ----------- --------------------------------------
198 # 1 default Eth1/1/1, Eth1/1/2, Eth1/2, Eth1/3/1, Eth1/3/2,
199 # Eth1/4, Eth1/5, Eth1/6, Eth1/7, Eth1/8,
200 # Eth1/10, Eth1/12, Eth1/13, Eth1/14, Eth1/15,
201 # Eth1/16
202 # 102 mdev testing
203 # 103 vpp 1 performance testing Eth1/1/3, Eth1/9
204 # 104 vpp 2 performance testing Eth1/1/4, Eth1/11
205 #
206 # Simplest strategy:
207 # 1. Match on a leading number and grab all the text after it
208 # 2. Drop anything starting with "Eth" to EOL
209 # 3. Strip leading and trailing whitespace
210 #
211 # Not perfect, but it'll have to do. Anybody including "Eth" in a
212 # VLAN name deserves to lose...
213
214 regex = re.compile(r'^ *\d+\s+(.+)')
215 self._cli("show vlan id %d" % tag)
216 for line in self._read_long_output("show vlan id"):
217 match = regex.match(line)
218 if match:
219 name = re.sub(r'Eth.*$',"",match.group(1)).strip()
Steve McIntyre7b1aa392018-02-08 12:33:17 +0000220 if name is None:
221 logging.debug("vlan_get_name: did not find a name")
Steve McIntyre59ffe892018-01-24 16:46:00 +0000222 return name
223
224 except PExpectError:
225 # recurse on error
226 self._switch_connect()
227 return self.vlan_get_name(tag)
228
229
230 ################################
231 ### Port API functions
232 ################################
233
234 # Set the mode of a port: access or trunk
235 def port_set_mode(self, port, mode):
236 logging.debug("Setting port %s to %s", port, mode)
237 if not self._is_port_mode_valid(mode):
238 raise InputError("Port mode %s is not allowed" % mode)
239 if not self._is_port_name_valid(port):
240 raise InputError("Port name %s not recognised" % port)
241
242 try:
243 self._configure()
244 self._cli("interface ethernet %s" % port)
245 self._cli("switchport mode %s" % mode)
246 if mode == "trunk":
247 # Put the new trunk port on all VLANs
248 self._cli("switchport trunk allowed-vlan all")
249 self._end_interface()
250 self._end_configure()
251
252 # Validate it happened
253 read_mode = self._port_get_mode(port)
254 if read_mode != mode:
255 raise IOError("Failed to set mode for port %s" % port)
256
257 # And cache the result
258 self._port_modes[port] = mode
259
260 except PExpectError:
261 # recurse on error
262 self._switch_connect()
263 self.port_set_mode(port, mode)
264
265 # Set an access port to be in a specified VLAN (tag)
266 def port_set_access_vlan(self, port, tag):
267 logging.debug("Setting access port %s to VLAN %d", port, tag)
268 if not self._is_port_name_valid(port):
269 raise InputError("Port name %s not recognised" % port)
270 if not (self.port_get_mode(port) == "access"):
271 raise InputError("Port %s not in access mode" % port)
272
273 try:
274 self._configure()
275 self._cli("interface ethernet %s" % port)
276 self._cli("switchport access vlan %d" % tag)
277 self._end_interface()
278 self._end_configure()
279
280 # Validate things worked
281 read_vlan = int(self.port_get_access_vlan(port))
282 if read_vlan != tag:
283 raise IOError("Failed to move access port %s to VLAN %d - got VLAN %d instead"
284 % (port, tag, read_vlan))
285
286 except PExpectError:
287 # recurse on error
288 self._switch_connect()
289 self.port_set_access_vlan(port, tag)
290
291 # Add a trunk port to a specified VLAN (tag)
292 def port_add_trunk_to_vlan(self, port, tag):
293 logging.debug("Adding trunk port %s to VLAN %d", port, tag)
294 if not self._is_port_name_valid(port):
295 raise InputError("Port name %s not recognised" % port)
296 if not (self.port_get_mode(port) == "trunk"):
297 raise InputError("Port %s not in trunk mode" % port)
298
299 try:
300 self._configure()
301 self._cli("interface ethernet %s" % port)
302 self._cli("switchport trunk allowed-vlan add %d" % tag)
303 self._end_interface()
304 self._end_configure()
305
306 # Validate it happened
307 read_vlans = self.port_get_trunk_vlan_list(port)
308 for vlan in read_vlans:
309 if vlan == tag or vlan == "ALL":
310 return
311 raise IOError("Failed to add trunk port %s to VLAN %d" % (port, tag))
312
313 except PExpectError:
314 # recurse on error
315 self._switch_connect()
316 self.port_add_trunk_to_vlan(port, tag)
317
318 # Remove a trunk port from a specified VLAN (tag)
319 def port_remove_trunk_from_vlan(self, port, tag):
320 logging.debug("Removing trunk port %s from VLAN %d", port, tag)
321 if not self._is_port_name_valid(port):
322 raise InputError("Port name %s not recognised" % port)
323 if not (self.port_get_mode(port) == "trunk"):
324 raise InputError("Port %s not in trunk mode" % port)
325
326 try:
327 self._configure()
328 self._cli("interface ethernet %s" % port)
329 self._cli("switchport trunk allowed-vlan remove %d" % tag)
330 self._end_interface()
331 self._end_configure()
332
333 # Validate it happened
334 read_vlans = self.port_get_trunk_vlan_list(port)
335 for vlan in read_vlans:
336 if vlan == tag:
337 raise IOError("Failed to remove trunk port %s from VLAN %d" % (port, tag))
338
339 except PExpectError:
340 # recurse on error
341 self._switch_connect()
342 self.port_remove_trunk_from_vlan(port, tag)
343
344 # Get the configured VLAN tag for an access port (tag)
345 def port_get_access_vlan(self, port):
346 logging.debug("Getting VLAN for access port %s", port)
347 if not self._is_port_name_valid(port):
348 raise InputError("Port name %s not recognised" % port)
349 if not (self.port_get_mode(port) == "access"):
350 raise InputError("Port %s not in access mode" % port)
351
352 regex = re.compile(r'^Eth%s\s+access\s+(\d+)' % port)
353
354 try:
355 self._cli("show interfaces switchport")
356 for line in self._read_long_output("show interfaces switchport"):
357 match = regex.match(line)
358 if match:
359 vlan = match.group(1)
360 return int(vlan)
361
362 except PExpectError:
363 # recurse on error
364 self._switch_connect()
365 return self.port_get_access_vlan(port)
366
367 # Get the list of configured VLAN tags for a trunk port
368 def port_get_trunk_vlan_list(self, port):
369 logging.debug("Getting VLANs for trunk port %s", port)
370 vlans = []
371 if not self._is_port_name_valid(port):
372 raise InputError("Port name %s not recognised" % port)
373 if not (self.port_get_mode(port) == "trunk"):
374 raise InputError("Port %s not in trunk mode" % port)
375 regex_start = re.compile(r'^Eth%s\s+trunk\s+N/A\s+(.*)' % port)
376 regex_continue = re.compile(r'^(\d.*)')
377
378 try:
379 self._cli("show interfaces switchport")
380
381 # Complex parsing work - VLAN list may extend over several lines, e.g.:
382 #
383 # Eth1/16 trunk N/A 1, 102, 103, 104, 1000, 1001, 1002
384 # 1003, 1004
385 #
386 in_match = False
387 vlan_text = ''
388
389 for line in self._read_long_output("show interfaces switchport"):
390 if in_match:
391 match = regex_continue.match(line)
392 if match:
393 vlan_text += ', ' # Make a consistently-formed list
394 vlan_text += match.group(1)
395 else:
396 in_match = False
397 if not in_match:
398 match = regex_start.match(line)
399 if match:
400 vlan_text += match.group(1)
401 in_match = True
402
403 vlans = self._parse_vlan_list(vlan_text)
404 return vlans
405
406 except PExpectError:
407 # recurse on error
408 self._switch_connect()
409 return self.port_get_trunk_vlan_list(port)
410
411 ################################
412 ### Internal functions
413 ################################
414
415 # Connect to the switch and log in
416 def _switch_connect(self):
417
418 if not self.connection is None:
419 self.connection.close(True)
420 self.connection = None
421
422 logging.debug("Connecting to Switch with: %s", self.exec_string)
423 self.connection = pexpect.spawn(self.exec_string, logfile=self.logger)
424 self._login()
425
426 # Avoid paged output as much as possible
427 self._cli("terminal length 999")
428 # Don't do silly things with ANSI codes
429 self._cli("terminal type dumb")
430 # and disable auto-logout after delay
431 self._cli("no cli session auto-logout")
432
433 # And grab details about the switch. in case we need it
434 self._get_systemdata()
435
436 # And also validate them - make sure we're driving a switch of
437 # the correct model! Also store the serial number
438 descr_regex = re.compile(r'Product name:\s*(\S+)')
439 sn_regex = re.compile(r'System serial num:\s*(\S+)')
440 descr = ""
441
442 for line in self._systemdata:
443 match = descr_regex.match(line)
444 if match:
445 descr = match.group(1)
446 match = sn_regex.match(line)
447 if match:
448 self.serial_number = match.group(1)
449
450 logging.debug("serial number is %s", self.serial_number)
451 logging.debug("system description is %s", descr)
452
453 if not self._expected_descr_re.match(descr):
454 raise IOError("Switch %s not recognised by this driver: abort" % descr)
455
456 # Now build a list of our ports, for later sanity checking
457 self._ports = self._get_port_names()
458 if len(self._ports) < 4:
459 raise IOError("Not enough ports detected - problem!")
460
461 def _login(self):
462 logging.debug("attempting login with username %s, password %s", self._username, self._password)
463 if self._username is not None:
464 self.connection.expect("login:")
465 self._cli("%s" % self._username)
466 if self._password is not None:
467 self.connection.expect("Password:")
468 self._cli("%s" % self._password, False)
469 while True:
470 index = self.connection.expect(['User:', 'Password:', 'Login incorrect', 'authentication failed', r'(.*?)(#|>)'])
471 if index != 4: # Any other means: failed to log in!
472 logging.error("Login failure: index %d\n", index)
473 logging.error("Login failure: %s\n", self.connection.match.before)
474 raise IOError
475
476 # else
477
478 # Add a couple of newlines to get past the "last login" etc. junk
479 self._cli("")
480 self._cli("")
481 self.connection.expect(r'^(.*?) (#|>)')
482 self._prompt_name = re.escape(self.connection.match.group(1).strip())
483 logging.info("Got outer prompt \"%s\"", self._prompt_name)
484 if self.connection.match.group(2) == ">":
485 # Need to enter "enable" mode too
486 self._cli("enable")
487 if self._enable_password is not None:
488 self.connection.expect("Password:")
489 self._cli("%s" % self._enable_password, False)
490 index = self.connection.expect(['Password:', 'Login incorrect', 'authentication failed', r'(.*) *(#|>)'])
491 if index != 3: # Any other means: failed to log in!
492 logging.error("Enable password failure: %s\n", self.connection.match)
493 raise IOError
494 self._cli("")
495 self._cli("")
496 self.connection.expect(r'^(.*?) (#|>)')
497 self._prompt_name = re.escape(self.connection.match.group(1).strip())
498 logging.info("Got enable prompt \"%s\"", self._prompt_name)
499 return 0
500
501 def _logout(self):
502 logging.debug("Logging out")
503 self._cli("quit", False)
504 try:
505 self.connection.expect("Would you like to save them now")
506 self._cli("n")
507 except (pexpect.EOF):
508 pass
509 self.connection.close(True)
510
511 def _configure(self):
512 self._cli("configure terminal")
513
514 def _end_configure(self):
515 self._cli("exit")
516
517 def _end_interface(self):
518 self._cli("exit")
519
520 def _end_vlan(self):
521 self._cli("exit")
522
523 def _read_long_output(self, text):
524 longbuf = []
525 prompt = self._prompt_name + r'\s*#'
526 while True:
527 try:
528 index = self.connection.expect([r'lines \d+-\d+', prompt])
529 if index == 0: # "lines 45-50"
530 for line in self.connection.before.split('\r\n'):
531 longbuf.append(line.strip())
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 # Look for "Eth1" at the beginning of the output lines to just
553 # match lines with interfaces - they have names like
554 # "Eth1/15". We do not care about Link Aggregation Groups (lag)
555 # here.
556 regex = re.compile(r'^Eth(\S+)')
557
558 try:
559 self._cli("show interfaces switchport")
560 for line in self._read_long_output("show interfaces switchport"):
561 match = regex.match(line)
562 if match:
563 interface = match.group(1)
564 interfaces.append(interface)
565 self._port_numbers[interface] = len(interfaces)
566 logging.debug(" found %d ports on the switch", len(interfaces))
567 return interfaces
568
569 except PExpectError:
570 # recurse on error
571 self._switch_connect()
572 return self._get_port_names()
573
574 # Get the mode of a port: access or trunk
575 def _port_get_mode(self, port):
576 logging.debug("Getting mode of port %s", port)
577 mode = ''
578 if not self._is_port_name_valid(port):
579 raise InputError("Port name %s not recognised" % port)
580 regex = re.compile('Switchport mode: (.*)')
581
582 try:
583 self._cli("show interfaces ethernet %s" % port)
584 for line in self._read_long_output("show interfaces ethernet"):
585 match = regex.match(line)
586 if match:
587 mode = match.group(1)
588 if mode == 'access':
589 return 'access'
590 if mode == 'trunk':
591 return 'trunk'
592 return mode
593
594 except PExpectError:
595 # recurse on error
596 self._switch_connect()
597 return self.port_get_mode(port)
598
599 def _show_config(self):
600 logging.debug("Grabbing config")
601 try:
602 self._cli("show running-config")
603 return self._read_long_output("show running-config")
604 except PExpectError:
605 # recurse on error
606 self._switch_connect()
607 return self._show_config()
608
609 def _show_clock(self):
610 logging.debug("Grabbing time")
611 try:
612 self._cli("show clock")
613 return self._read_long_output("show clock")
614 except PExpectError:
615 # recurse on error
616 self._switch_connect()
617 return self._show_clock()
618
619 def _get_systemdata(self):
620 logging.debug("Grabbing system sw and hw versions")
621
622 try:
623 self._systemdata = []
624 self._cli("show version")
625 for line in self._read_long_output("show version"):
626 self._systemdata.append(line)
627
628 except PExpectError:
629 # recurse on error
630 self._switch_connect()
631 return self._get_systemdata()
632
633 # Borrowed from the Catalyst driver. Over-complex for our needs here, but
634 # it's already tested and will do the job.
635 def _parse_vlan_list(self, inputdata):
636 vlans = []
637
638 if inputdata == "ALL":
639 return ["ALL"]
640 elif inputdata == "NONE":
641 return []
642 elif inputdata == "":
643 return []
644 else:
645 # Parse the complex list
646 groups = inputdata.split(',')
647 for group in groups:
648 subgroups = group.split('-')
649 if len(subgroups) == 1:
650 vlans.append(int(subgroups[0]))
651 elif len(subgroups) == 2:
652 for i in range (int(subgroups[0]), int(subgroups[1]) + 1):
653 vlans.append(i)
654 else:
655 logging.debug("Can't parse group \"" + group + "\"")
656
657 return vlans
658
659 # Wrapper around connection.send - by default, expect() the same
660 # text we've sent, to remove it from the output from the
661 # switch. For the few cases where we don't need that, override
662 # this using echo=False.
663 # Horrible, but seems to work.
664 def _cli(self, text, echo=True):
665 self.connection.send(text + '\r')
666 if echo:
667 try:
668 self.connection.expect(text)
669 except (pexpect.EOF, pexpect.TIMEOUT):
670 # Something went wrong; logout, log in and try again!
671 logging.error("PEXPECT FAILURE, RECONNECT")
672 self.errors.log_error_out(text)
673 raise PExpectError("_cli failed on %s" % text)
674 except:
675 logging.error("Unexpected error: %s", sys.exc_info()[0])
676 raise
677
678if __name__ == "__main__":
679
680 # Simple test harness - exercise the main working functions above to verify
681 # they work. This does *NOT* test really disruptive things like "save
682 # running-config" and "reload" - test those by hand.
683
684 import optparse
685
686 switch = '172.27.16.6'
687 parser = optparse.OptionParser()
688 parser.add_option("--switch",
689 dest = "switch",
690 action = "store",
691 nargs = 1,
692 type = "string",
693 help = "specify switch to connect to for testing",
694 metavar = "<switch>")
695 (opts, args) = parser.parse_args()
696 if opts.switch:
697 switch = opts.switch
698
699 logging.basicConfig(level = logging.DEBUG,
700 format = '%(asctime)s %(levelname)-8s %(message)s')
701 p = MlnxOS(switch, 23, debug=False)
702 p.switch_connect('admin', 'admin', None)
703
704 print "VLANs are:"
705 buf = p.vlan_get_list()
706 p.dump_list(buf)
707
708 buf = p.vlan_get_name(102)
709 print "VLAN 102 is named \"%s\"" % buf
710
711 print "Create VLAN 1003"
712 p.vlan_create(1003)
713
714 buf = p.vlan_get_name(1003)
715 print "VLAN 1003 is named \"%s\"" % buf
716
717 print "Set name of VLAN 1003 to test333"
718 p.vlan_set_name(1003, "test333")
719
720 buf = p.vlan_get_name(1003)
721 print "VLAN 1003 is named \"%s\"" % buf
722
723 print "VLANs are:"
724 buf = p.vlan_get_list()
725 p.dump_list(buf)
726
727 print "Destroy VLAN 1003"
728 p.vlan_destroy(1003)
729
730 print "VLANs are:"
731 buf = p.vlan_get_list()
732 p.dump_list(buf)
733
734 buf = p.port_get_mode("1/15")
735 print "Port 1/15 is in %s mode" % buf
736
737 buf = p.port_get_mode("1/16")
738 print "Port 1/16 is in %s mode" % buf
739
740 # Test access stuff
741 print "Set 1/15 to access mode"
742 p.port_set_mode("1/15", "access")
743
744 print "Move 1/15 to VLAN 4"
745 p.port_set_access_vlan("1/15", 4)
746
747 buf = p.port_get_access_vlan("1/15")
748 print "Read from switch: 1/15 is on VLAN %s" % buf
749
750 print "Move 1/15 back to VLAN 1"
751 p.port_set_access_vlan("1/15", 1)
752
753 print "Create VLAN 1002"
754 p.vlan_create(1002)
755
756 print "Create VLAN 1003"
757 p.vlan_create(1003)
758
759 print "Create VLAN 1004"
760 p.vlan_create(1004)
761
762 # Test access stuff
763 print "Set 1/15 to trunk mode"
764 p.port_set_mode("1/15", "trunk")
765 print "Read from switch: which VLANs is 1/15 on?"
766 buf = p.port_get_trunk_vlan_list("1/15")
767 p.dump_list(buf)
768
769 # The adds below are NOOPs in effect on this switch - no filtering
770 # for "trunk" ports
771 print "Add 1/15 to VLAN 1002"
772 p.port_add_trunk_to_vlan("1/15", 1002)
773 print "Add 1/15 to VLAN 1003"
774 p.port_add_trunk_to_vlan("1/15", 1003)
775 print "Add 1/15 to VLAN 1004"
776 p.port_add_trunk_to_vlan("1/15", 1004)
777 print "Read from switch: which VLANs is 1/15 on?"
778 buf = p.port_get_trunk_vlan_list("1/15")
779 p.dump_list(buf)
780
781 # And the same for removals here
782 p.port_remove_trunk_from_vlan("1/15", 1003)
783 p.port_remove_trunk_from_vlan("1/15", 1002)
784 p.port_remove_trunk_from_vlan("1/15", 1004)
785 print "Read from switch: which VLANs is 1/15 on?"
786 buf = p.port_get_trunk_vlan_list("1/15")
787 p.dump_list(buf)
788
789# print 'Restarting switch, to explicitly reset config'
790# p.switch_restart()
791
792# p.switch_save_running_config()
793
794# p.switch_disconnect()
795# p._show_config()