netutils 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/README.md +36 -0
  8. data/Rakefile +6 -0
  9. data/bin/acl +109 -0
  10. data/bin/alaxala-deploy +271 -0
  11. data/bin/config-diff-check +111 -0
  12. data/bin/config-gets +64 -0
  13. data/bin/console +14 -0
  14. data/bin/host-locate-on-demand +102 -0
  15. data/bin/ipaddr-resolv +74 -0
  16. data/bin/ipaddr-resolv.sh +97 -0
  17. data/bin/mac-drop +84 -0
  18. data/bin/mac-nodrop +45 -0
  19. data/bin/port-shutdown +78 -0
  20. data/bin/setup +8 -0
  21. data/lib/netutils.rb +118 -0
  22. data/lib/netutils/arp.rb +28 -0
  23. data/lib/netutils/cli.rb +702 -0
  24. data/lib/netutils/cli/alaxala.rb +121 -0
  25. data/lib/netutils/cli/alaxala/interface.rb +137 -0
  26. data/lib/netutils/cli/alaxala/lldp.rb +166 -0
  27. data/lib/netutils/cli/alaxala/macfib.rb +62 -0
  28. data/lib/netutils/cli/alaxala/showarp.rb +51 -0
  29. data/lib/netutils/cli/alaxala/showroute.rb +86 -0
  30. data/lib/netutils/cli/alaxala/showvrf.rb +46 -0
  31. data/lib/netutils/cli/aruba.rb +15 -0
  32. data/lib/netutils/cli/cisco.rb +45 -0
  33. data/lib/netutils/cli/cisco/cdp.rb +117 -0
  34. data/lib/netutils/cli/cisco/ifsummary.rb +32 -0
  35. data/lib/netutils/cli/cisco/interface.rb +67 -0
  36. data/lib/netutils/cli/cisco/macfib.rb +38 -0
  37. data/lib/netutils/cli/cisco/showarp.rb +27 -0
  38. data/lib/netutils/cli/cisco/showinterface.rb +27 -0
  39. data/lib/netutils/cli/cisco/showroute.rb +73 -0
  40. data/lib/netutils/cli/cisco/showvrf.rb +45 -0
  41. data/lib/netutils/cli/nec.rb +20 -0
  42. data/lib/netutils/cli/nec/lldp.rb +16 -0
  43. data/lib/netutils/cli/paloalto.rb +21 -0
  44. data/lib/netutils/fsm.rb +43 -0
  45. data/lib/netutils/macaddr.rb +51 -0
  46. data/lib/netutils/oncequeue.rb +78 -0
  47. data/lib/netutils/parser.rb +30 -0
  48. data/lib/netutils/rib.rb +80 -0
  49. data/lib/netutils/switch.rb +402 -0
  50. data/lib/netutils/tunnel.rb +8 -0
  51. data/lib/netutils/version.rb +3 -0
  52. data/lib/netutils/vrf.rb +42 -0
  53. data/log/.gitignore +1 -0
  54. data/netutils.gemspec +33 -0
  55. metadata +195 -0
@@ -0,0 +1,121 @@
1
+ require 'netutils/cli/alaxala/interface'
2
+ require 'netutils/cli/alaxala/lldp'
3
+ require 'netutils/cli/alaxala/macfib'
4
+ require 'netutils/cli/alaxala/showarp'
5
+ require 'netutils/cli/alaxala/showroute'
6
+ require 'netutils/cli/alaxala/showvrf'
7
+
8
+ module Alaxala
9
+ CONFIG_RE = /\A((?:#configuration list for [^\n]+|#Last modified [^\n]+)\n.*)\n\Z/m
10
+
11
+ def disable_logging_console
12
+ case @product
13
+ when /^AX86[0-9]{2}/
14
+ # AX8600
15
+ configure
16
+ cmd('username default_user logging-console event-level 0')
17
+ unconfigure
18
+ when /^AX22[0-9]{2}/
19
+ # XXX: AX2230 seems not to have set logging commands...
20
+ when /^AX[23][0-9]{2,3}/
21
+ # AX3800, AX3600, AX2500, AX260
22
+ for level in 3..9
23
+ cmd("set logging console disable E#{level}")
24
+ end
25
+ end
26
+ end
27
+
28
+ def interface_name(sw, name)
29
+ if name =~ /^Port\s+(.*)$/i
30
+ name = $1
31
+ elsif name =~ /^[^\s0-9]/
32
+ return name
33
+ end
34
+ numbers = name.delete(' ').split('/')
35
+ sw.ports.each do |port|
36
+ return port.name.to_s if port.name.numbers == numbers
37
+ if sw.product =~ /^AX3[0-9]{3}/ &&
38
+ port.name.numbers.size === 3 &&
39
+ numbers.size === 2 &&
40
+ port.name.numbers.drop(1) == numbers
41
+ return port.name.to_s
42
+ end
43
+ end
44
+ nil
45
+ end
46
+
47
+ def interface_name_cli(name)
48
+ name.split(' ')[1]
49
+ end
50
+
51
+ def unconfigure
52
+ cmd('save')
53
+ super
54
+ end
55
+
56
+ #
57
+ # XXX: forcely override method because Alaxala
58
+ # interface command accept lower case characters only...
59
+ # e.g., GigabitEthernet should be gigabitethernet...
60
+ #
61
+ def interface_name_interface_command(port)
62
+ port.downcase
63
+ end
64
+ private :interface_name_interface_command
65
+
66
+ def interface_shutdown(port)
67
+ super(interface_name_interface_command(port))
68
+ end
69
+
70
+ def interface_noshutdown(port)
71
+ super(interface_name_interface_command(port))
72
+ end
73
+
74
+ def acl_definition(type, name)
75
+ case type
76
+ when 'ip'
77
+ when 'mac'
78
+ "#{type} access-list extended #{name}"
79
+ when 'advance' # XXX: AX8600 only
80
+ "#{type} access-list #{name}"
81
+ else
82
+ raise(ArgumentError, "Unsupported ACL type: #{type}")
83
+ end
84
+ end
85
+
86
+ def acl_type_to_cmd(type)
87
+ case type
88
+ when 'ip'
89
+ when 'mac'
90
+ when 'advance' # XXX: AX8600 only
91
+ #
92
+ # we here use only ``mac'' even though mac-ip and
93
+ # mac-ipv6 are available.
94
+ #
95
+ type = 'mac'
96
+ else
97
+ raise(ArgumentError, "Unsupported ACL type: #{type}")
98
+ end
99
+ type
100
+ end
101
+
102
+ def show_running_config
103
+ return cmd('show running-config')
104
+ end
105
+
106
+ def syslog(host, vrf = 1)
107
+ configure
108
+ case @product
109
+ when /^AX86[0-9]{2}/
110
+ # AX8600
111
+ cmd("logging syslog-host #{host} vrf #{vrf} no-date-info")
112
+ when /^AX(?:25[0-9]{2}|3[0-9]{3})/
113
+ # AX2500, AX3000
114
+ cmd("logging host #{host} no-date-info")
115
+ when /^AX22[0-9]{2}/
116
+ # AX2230
117
+ cmd("logging host #{host}")
118
+ end
119
+ unconfigure
120
+ end
121
+ end
@@ -0,0 +1,137 @@
1
+ require 'netutils/parser'
2
+
3
+ module Alaxala
4
+
5
+ class Interface < Parser
6
+ def cmd
7
+ return 'show port'
8
+ end
9
+
10
+ # AX2500
11
+ # Date 2017/10/14 21:00:10 JST
12
+ # Port Counts: 52
13
+ # Port Name Status Speed Duplex FCtl FrLen ChGr/Status
14
+ # 0/1 geth0/1 down - - - - -/-
15
+ # 0/2 geth0/2 down - - - - -/-
16
+
17
+ # AX2200
18
+ # Date 2017/10/14 20:47:34 JST
19
+ # Port Counts: 28
20
+ # Port Name Status Speed Duplex FCtl FrLen ChGr/Status
21
+ # 0/1 gigaether0/1 up 1000BASE-T full(auto) off 1518 -/-
22
+ # 0/2 gigaether0/2 up 1000BASE-T full(auto) off 1518 -/-
23
+
24
+ # AX3800 (stack)
25
+ # Switch 1 (Master)
26
+ # -----------------
27
+ # Date 2017/10/15 23:10:44 JST
28
+ # Port Counts: 48
29
+ # Port Name Status Speed Duplex FCtl FrLen ChGr/Status
30
+ # 0/ 1 tengeth1/0/1 up 10GBASE-SR full off 1518 1/up
31
+ # 0/ 2 tengeth1/0/2 up 10GBASE-SR full off 1518 2/up
32
+ #
33
+ #
34
+ # Switch 2 (Backup)
35
+ # -----------------
36
+ # Date 2017/10/15 23:10:44 JST
37
+ # Port Counts: 48
38
+ # Port Name Status Speed Duplex FCtl FrLen ChGr/Status
39
+ # 0/ 1 tengeth2/0/1 up 10GBASE-SR full off 1518 1/-
40
+ # 0/ 2 tengeth2/0/2 up 10GBASE-SR full off 1518 2/-
41
+
42
+ # AX8600
43
+ # Date 2017/10/14 20:16:41 JST
44
+ # Port Counts: 54
45
+ # Port Status Speed Duplex FCtl FrLen Description
46
+ # 1/1 up 10GBASE-SR full off 1518 hogehoge
47
+ # 1/2 up 10GBASE-SR full off 1518 fugafuga
48
+ PORT_RE = /^\s*([0-9\/\s]+)\s+([^\s]*)\s*(up|down|dis|inact|init)\s+([^\s]+)\s+(full|half|-)(?:\(auto\))?\s+(on|off|-)\s+(?:[0-9]+|-)\s+.*$/
49
+
50
+ def initialize(sw)
51
+ super()
52
+ add('Init', :init)
53
+ add('Date', :date, /^Port Counts:.*$/)
54
+ add('Count', :count, /^Port\s+(?:Name|Status).*$/)
55
+ add('Port', :port)
56
+ @sw = sw
57
+ end
58
+
59
+ private
60
+
61
+ def init(l, m)
62
+ case l
63
+ when /^Date/
64
+ changeto('Date')
65
+ when /^Switch/
66
+ when /^-------/
67
+ when /^$/
68
+ end
69
+ end
70
+
71
+ def date(l, m)
72
+ changeto('Count')
73
+ end
74
+
75
+ def count(l, m)
76
+ changeto('Port')
77
+ end
78
+
79
+ def port_name_normalize(port0, name, speed)
80
+ port0.delete!(' ')
81
+ # XXX: should check actual port capability...
82
+ if ! name || name.empty?
83
+ case speed
84
+ when /^(10|100|1000)BASE/
85
+ name = 'Gigabit'
86
+ when /^10GBASE/
87
+ name = 'TenG'
88
+ when /^40GBASE/
89
+ name = 'FortyG'
90
+ when /^100GBASE/
91
+ name = 'HundredG'
92
+ when '-'
93
+ else
94
+ raise "Unknown Speed: #{speed}"
95
+ end
96
+ elsif @sw.product =~ /^AX3[0-9]{3}/
97
+ #
98
+ # AX3000 series uses 3 numbers for port numbers
99
+ # in many commands of CLI but ``show port''
100
+ # command returns 2 numbers only like below.
101
+ #
102
+ # 0/23 tengeth1/0/23 up 1000BASE-SX...
103
+ #
104
+ if name !~ /^[a-z]+([0-9\/]+)$/
105
+ raise "Invalid port format: \"#{name}\""
106
+ end
107
+ port0 = $1
108
+ end
109
+ case name
110
+ when /^TenG/i
111
+ prefix = 'Ten'
112
+ when /^FourtyG/i
113
+ prefix = 'Fourty'
114
+ when /^HundredG/i
115
+ prefix = 'Hundred'
116
+ else
117
+ prefix = ''
118
+ end
119
+ return "#{prefix}GigabitEthernet #{port0}"
120
+ end
121
+
122
+ def port(l, m)
123
+ if l =~ /^Switch/
124
+ changeto('Init')
125
+ return
126
+ end
127
+ return if l =~ /^$/ # AX2500, or others...
128
+ if l !~ PORT_RE
129
+ raise "CLI invalid format of port: #{l}"
130
+ end
131
+ name = port_name_normalize($1, $2, $4)
132
+ @sw.ports.add(name, nil, $4, $4, $5)
133
+ @sw.ports[name].up = $3 == 'up'
134
+ end
135
+ end
136
+
137
+ end
@@ -0,0 +1,166 @@
1
+ require 'netutils/parser'
2
+ require 'netutils/switch'
3
+
4
+ module Alaxala
5
+
6
+ class LLDP < Parser
7
+ def cmd(port)
8
+ if port
9
+ port = @sw.interface_name_cli(port)
10
+ # XXX: how about stack configuration...
11
+ if @sw.product =~ /^AX3[0-9]{3}/
12
+ numbers = port.split('/')
13
+ if numbers.size != 3
14
+ raise "Invalid port format: #{numbers}"
15
+ end
16
+ port = "#{numbers[1]}/#{numbers[2]}"
17
+ end
18
+ port = "port #{port} "
19
+ end
20
+ return "show lldp #{port}detail"
21
+ end
22
+
23
+ # Date 2017/10/15 00:06:36 JST
24
+ # Status: Enabled Chassis ID: Type=MAC Info=beef.dad.beef
25
+ # Interval Time: 30 Hold Count: 4 TTL: 121 Draft TTL: 120
26
+ # System Name: hogehoge
27
+ # System Description: ALAXALA AX8600S AX-8600-S16 [AX8616S] Switching software (including encryption) Ver. 12.7.B [OS-SE]
28
+ # Neighbor Counts=1
29
+ # Draft Neighbor Counts=0
30
+ # Port Counts=1
31
+ # Port 1/ 1(CH: 1)
32
+ # Link: Up PortEnabled: TRUE AdminStatus: enabledRxTx
33
+ # Neighbor Counts: 1 Draft Neighbor Counts: 0
34
+ # Port ID: Type=MAC Info=beef.dead.beef
35
+ # Port Description: hogehoge
36
+ # Neighbor 1 TTL: 95
37
+ # Chassis ID: Type=MAC Info=dead.beef.dead
38
+ # System Name: fugafuga
39
+ # System Description: ALAXALA AX2530 AX-2530-48T2X-B [AX2530S-48T2X] Switching software Ver. 4.6.A [OS-L2B]
40
+ # Port ID: Type=MAC Info=dead.beef.dead
41
+ # Port Description: hogehoge
42
+
43
+ attr_reader :rsw
44
+ def initialize(sw)
45
+ super()
46
+ add('Init', :init)
47
+ add('Port', :port)
48
+ add('PortInfo', :port_info)
49
+ add('ChassisID', :chassis_id, /^ Chassis ID: Type=[^\s]+ \s+Info=[0-9a-z.]+$/)
50
+ add('SystemName', :system_name, /^\s{4,6}System Name: ([^\s]+)$/)
51
+ add('SystemDescription',:system_description, /^\s{4,6}System Description: (.*)$/)
52
+ add('PortID', :port_id)
53
+ add('PortDescription', :port_description, /^\s{4,6}Port Description: .*$/)
54
+ add('TagID', :tag_id)
55
+ @sw = sw
56
+ end
57
+
58
+ private
59
+
60
+ def init(l, m)
61
+ changeto('Port') if l =~ /^Port Counts.*$/
62
+ end
63
+
64
+ def port(l, m)
65
+ raise 'Invalid format' if l !~ /^Port\s+([0-9\s\/]+).*$/
66
+ @lport = @sw.interface_name($1)
67
+ changeto('PortInfo')
68
+ end
69
+
70
+ def port_info(l, m)
71
+ if l =~ /^ (?:Draft Neighbor|Neighbor)\s+[0-9]+\s+TTL: [0-9]+\s*.*$/
72
+ neighbor(l, m)
73
+ elsif l =~ /^ [0-9]+\s+TTL:\s*[0-9]+\s+Chassis ID: Type=[^\s]+\s+Info=[0-9a-z.]+$/
74
+ neighbor_ax3000(l, m)
75
+ elsif l =~ /^Port/
76
+ port(l, m)
77
+ else
78
+ end
79
+ end
80
+
81
+ def neighbor(l, m)
82
+ @rname = nil
83
+ changeto('ChassisID')
84
+ end
85
+
86
+ def neighbor_ax3000(l, m)
87
+ @rname = nil
88
+ changeto('SystemName')
89
+ end
90
+
91
+ def chassis_id(l, m)
92
+ changeto('SystemName')
93
+ end
94
+
95
+ def system_name(l, m)
96
+ @rname = m[1]
97
+ changeto('SystemDescription')
98
+ end
99
+
100
+ def system_description(l, m)
101
+ desc = m[1]
102
+ case desc
103
+ when /^(ALAXALA.*) Switching software Ver. (.*)$/
104
+ platform = $1
105
+ firmware = $2
106
+ else
107
+ platform = desc
108
+ firmware = nil
109
+ end
110
+ case platform
111
+ when /Cisco*/,
112
+ /^ALAXALA AX[87643]/, /ALAXALA AX2[0-9]{2}[^0-9]/
113
+ type = Switch::Type::ROUTER
114
+ when /^ALAXALA AX[12][0-9]{3}[^0-9]/
115
+ type = Switch::Type::SWITCH
116
+ # elsif /XXX/
117
+ # type = Switch::Type::BRIDGE
118
+ else
119
+ type = Switch::Type::HOST
120
+ end
121
+ neighbor_add(@lport, @rname, type, platform, firmware)
122
+ changeto('PortID')
123
+ end
124
+
125
+ def port_id(l, m)
126
+ # XXX: this may be left system description.
127
+ return if l !~ /^\s{4,6}Port ID: Type=[^\s]+ \s+Info=.*+$/
128
+ changeto('PortDescription')
129
+ end
130
+
131
+ def port_description(l, m)
132
+ changeto('TagID')
133
+ end
134
+
135
+ def tag_id(l, m)
136
+ case l
137
+ when /^Port+/
138
+ if ! @rsw.ia
139
+ raise "no IP address found for #{@rsw.name} "
140
+ "on #{@sw.name} #{@lport}"
141
+ end
142
+ port(l, m)
143
+ when /^ [^\s]+/
144
+ port_info(l, m)
145
+ when /^\s{4,6}Tag ID: .*$/
146
+ return
147
+ when /^\s{4,6}IPv4 Address: (?:Untagged|Tagged:\s+[0-9]+)\s+([0-9.]+)$/,
148
+ /^\s{4,6}Management Address:\s+([0-9.]+)$/
149
+ @rsw.ip_address_set($1)
150
+ end
151
+ end
152
+
153
+ def neighbor_add(lport, rname, type, platform, firmware)
154
+ # XXX: this is valid for cisco only...
155
+ if firmware =~ /^.*Copyright \(c\) .*([0-9]{4}) .*$/
156
+ time = $1
157
+ else
158
+ time = 'unknown'
159
+ end
160
+ static_neighbor_resolve(@sw.name, lport)
161
+ @rsw = Switch.get(rname, type, platform, firmware, time)
162
+ @sw.ports[lport].peers.add(@rsw, nil) # XXX: no way to know remote port...
163
+ end
164
+ end
165
+
166
+ end
@@ -0,0 +1,62 @@
1
+ require 'netutils/parser'
2
+ require 'netutils/macaddr'
3
+
4
+ module Alaxala
5
+
6
+ class MACFIB < Parser
7
+ attr_reader :ports
8
+
9
+ #
10
+ # Date 2017/10/15 08:24:22 JST
11
+ # Aging time : 300
12
+ # MAC address VLAN Type Port-list
13
+ # dead.beef.dead 9999 Dynamic 0/26-27
14
+ #
15
+ AX2000_RE = /^[0-9a-z.]+\s+[0-9]+\s+[^\s]+\s+([0-9\/,\-]+)$/
16
+
17
+ # Date 2017/10/14 19:39:20 JST
18
+ # MAC address VLAN C-Tag Aging-Time Type Port-list
19
+ # dead.beef.dead 9999 - 479 Dynamic 7/5,11/5
20
+ AX8600_RE = /^[0-9a-z.]+\s+[0-9]+\s+[^\s]+\s+[0-9]+\s+[^\s]+\s+([0-9\/,\-]+)$/
21
+
22
+ def cmd(ma, vlan)
23
+ mac = "mac " if @sw.product =~ /^AX2[0-9]{3}/
24
+ return "show mac-address-table #{mac}#{ma.to_s} vlan #{vlan}"
25
+ end
26
+
27
+ def initialize(sw)
28
+ @ports = {}
29
+ super()
30
+ add('Init', :init)
31
+ @sw = sw
32
+ end
33
+
34
+ def init(l, m)
35
+ case l
36
+ # XXX: other switches...
37
+ when AX2000_RE, AX8600_RE
38
+ $1.split(',').each do |port|
39
+ port, last = port.split('-')
40
+ if port =~ /^(.*\/)([0-9]+)$/
41
+ prefix = $1
42
+ first = $2.to_i
43
+ else
44
+ raise(ArgumentError,
45
+ "Unknown port name format: #{port}")
46
+ end
47
+ if last
48
+ last = last.to_i
49
+ else
50
+ last = first
51
+ end
52
+ for i in first .. last do
53
+ name = prefix + i.to_s
54
+ name = @sw.interface_name(name)
55
+ @ports[name] = name
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ end