cisco_node_utils 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -1
- data/CHANGELOG.md +81 -2
- data/CONTRIBUTING.md +2 -17
- data/Gemfile +5 -0
- data/README.md +92 -47
- data/Rakefile +23 -1
- data/bin/git/hooks/hook_lib +7 -0
- data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
- data/bin/git/hooks/pre-commit/rubocop +7 -2
- data/bin/git/hooks/pre-commit/validate-diffs +18 -4
- data/bin/git/hooks/pre-commit/validate-yaml +18 -0
- data/bin/git/update-hooks +64 -6
- data/cisco_node_utils.gemspec +9 -6
- data/docs/README-develop-best-practices.md +149 -50
- data/docs/README-develop-node-utils-APIs.md +92 -42
- data/docs/README-maintainers.md +7 -4
- data/docs/README-test-execution.md +57 -0
- data/docs/cisco_node_utils.yaml.example +30 -0
- data/docs/template-router.rb +4 -0
- data/ext/mkrf_conf.rb +63 -0
- data/lib/.rubocop.yml +2 -2
- data/lib/cisco_node_utils.rb +5 -0
- data/lib/cisco_node_utils/aaa_authentication_login.rb +5 -6
- data/lib/cisco_node_utils/aaa_authorization_service.rb +1 -1
- data/lib/cisco_node_utils/ace.rb +165 -12
- data/lib/cisco_node_utils/acl.rb +2 -1
- data/lib/cisco_node_utils/bgp.rb +184 -21
- data/lib/cisco_node_utils/bgp_af.rb +94 -249
- data/lib/cisco_node_utils/bgp_neighbor.rb +94 -14
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +75 -8
- data/lib/cisco_node_utils/bridge_domain.rb +183 -0
- data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +85 -2
- data/lib/cisco_node_utils/client.rb +35 -0
- data/lib/cisco_node_utils/client/client.rb +234 -0
- data/lib/cisco_node_utils/client/grpc.rb +33 -0
- data/lib/cisco_node_utils/client/grpc/client.rb +311 -0
- data/lib/cisco_node_utils/client/grpc/ems.proto +148 -0
- data/lib/cisco_node_utils/client/grpc/ems.rb +111 -0
- data/lib/cisco_node_utils/client/grpc/ems_services.rb +49 -0
- data/lib/cisco_node_utils/client/nxapi.rb +31 -0
- data/lib/cisco_node_utils/client/nxapi/client.rb +305 -0
- data/lib/cisco_node_utils/client/utils.rb +164 -0
- data/lib/cisco_node_utils/cmd_ref/README_YAML.md +222 -254
- data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +22 -15
- data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/acl.yaml +21 -16
- data/lib/cisco_node_utils/cmd_ref/bgp.yaml +239 -109
- data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +114 -55
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +76 -52
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +106 -62
- data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +71 -0
- data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
- data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +35 -14
- data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +23 -17
- data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +94 -83
- data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +22 -17
- data/lib/cisco_node_utils/cmd_ref/feature.yaml +76 -26
- data/lib/cisco_node_utils/cmd_ref/images.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/interface.yaml +381 -153
- data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +21 -21
- data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +30 -21
- data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +18 -13
- data/lib/cisco_node_utils/cmd_ref/inventory.yaml +26 -31
- data/lib/cisco_node_utils/cmd_ref/itd_device_group.yaml +83 -0
- data/lib/cisco_node_utils/cmd_ref/itd_service.yaml +119 -0
- data/lib/cisco_node_utils/cmd_ref/memory.yaml +17 -6
- data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +10 -3
- data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +17 -5
- data/lib/cisco_node_utils/cmd_ref/ospf.yaml +33 -29
- data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +12 -10
- data/lib/cisco_node_utils/cmd_ref/pim.yaml +16 -19
- data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +40 -25
- data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +17 -12
- data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +71 -35
- data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +10 -5
- data/lib/cisco_node_utils/cmd_ref/show_system.yaml +6 -2
- data/lib/cisco_node_utils/cmd_ref/show_version.yaml +47 -43
- data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +13 -11
- data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +4 -2
- data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +23 -21
- data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +26 -22
- data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +19 -17
- data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +18 -6
- data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +234 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +24 -9
- data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +5 -3
- data/lib/cisco_node_utils/cmd_ref/system.yaml +4 -3
- data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +22 -20
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +27 -15
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +45 -16
- data/lib/cisco_node_utils/cmd_ref/vdc.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/vlan.yaml +60 -32
- data/lib/cisco_node_utils/cmd_ref/vpc.yaml +118 -101
- data/lib/cisco_node_utils/cmd_ref/vrf.yaml +54 -58
- data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +118 -0
- data/lib/cisco_node_utils/cmd_ref/vtp.yaml +19 -25
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +28 -18
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +34 -17
- data/lib/cisco_node_utils/cmd_ref/yum.yaml +6 -4
- data/lib/cisco_node_utils/command_reference.rb +261 -142
- data/lib/cisco_node_utils/constants.rb +33 -0
- data/lib/cisco_node_utils/encapsulation.rb +112 -0
- data/lib/cisco_node_utils/environment.rb +102 -0
- data/lib/cisco_node_utils/evpn_vni.rb +5 -3
- data/lib/cisco_node_utils/exceptions.rb +111 -0
- data/lib/cisco_node_utils/fabricpath_global.rb +52 -35
- data/lib/cisco_node_utils/fabricpath_topology.rb +44 -57
- data/lib/cisco_node_utils/feature.rb +165 -3
- data/lib/cisco_node_utils/interface.rb +1051 -260
- data/lib/cisco_node_utils/interface_channel_group.rb +11 -10
- data/lib/cisco_node_utils/interface_ospf.rb +1 -2
- data/lib/cisco_node_utils/interface_portchannel.rb +4 -12
- data/lib/cisco_node_utils/interface_service_vni.rb +7 -7
- data/lib/cisco_node_utils/itd_device_group.rb +248 -0
- data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
- data/lib/cisco_node_utils/itd_service.rb +523 -0
- data/lib/cisco_node_utils/logger.rb +75 -0
- data/lib/cisco_node_utils/node.rb +62 -192
- data/lib/cisco_node_utils/node_util.rb +56 -10
- data/lib/cisco_node_utils/overlay_global.rb +2 -2
- data/lib/cisco_node_utils/pim.rb +2 -13
- data/lib/cisco_node_utils/pim_group_list.rb +1 -1
- data/lib/cisco_node_utils/pim_rp_address.rb +1 -1
- data/lib/cisco_node_utils/platform.rb +52 -21
- data/lib/cisco_node_utils/portchannel_global.rb +89 -19
- data/lib/cisco_node_utils/radius_server.rb +168 -37
- data/lib/cisco_node_utils/router_ospf.rb +20 -35
- data/lib/cisco_node_utils/router_ospf_vrf.rb +4 -4
- data/lib/cisco_node_utils/snmpserver.rb +1 -6
- data/lib/cisco_node_utils/snmpuser.rb +6 -4
- data/lib/cisco_node_utils/stp_global.rb +676 -0
- data/lib/cisco_node_utils/syslog_server.rb +77 -18
- data/lib/cisco_node_utils/syslog_settings.rb +1 -1
- data/lib/cisco_node_utils/tacacs_server_group.rb +8 -4
- data/lib/cisco_node_utils/tacacs_server_host.rb +115 -25
- data/lib/cisco_node_utils/vdc.rb +12 -0
- data/lib/cisco_node_utils/version.rb +1 -1
- data/lib/cisco_node_utils/vlan.rb +147 -29
- data/lib/cisco_node_utils/vpc.rb +55 -3
- data/lib/cisco_node_utils/vrf.rb +72 -11
- data/lib/cisco_node_utils/vrf_af.rb +114 -29
- data/lib/cisco_node_utils/vtp.rb +34 -52
- data/lib/cisco_node_utils/vxlan_vtep.rb +34 -8
- data/lib/cisco_node_utils/vxlan_vtep_vni.rb +36 -4
- data/lib/minitest/environment_plugin.rb +31 -0
- data/lib/minitest/log_level_plugin.rb +41 -0
- data/spec/client_spec.rb +7 -0
- data/spec/environment_spec.rb +263 -0
- data/spec/grpc_client_spec.rb +23 -0
- data/spec/isolate/all_clients_spec.rb +9 -0
- data/spec/isolate/grpc_only_spec.rb +16 -0
- data/spec/isolate/no_clients_spec.rb +26 -0
- data/spec/isolate/nxapi_only_spec.rb +16 -0
- data/spec/nxapi_client_spec.rb +42 -0
- data/spec/schema.yaml +75 -0
- data/spec/shared_examples_for_clients.rb +14 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/whitespace_spec.rb +10 -0
- data/spec/yaml_spec.rb +42 -0
- data/tests/.rubocop.yml +2 -2
- data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
- data/tests/basetest.rb +96 -36
- data/tests/ciscotest.rb +220 -12
- data/tests/cmd_config.yaml +71 -49
- data/tests/cmd_config_invalid.yaml +1 -1
- data/tests/test_aaa_authentication_login.rb +1 -0
- data/tests/test_aaa_authentication_login_service.rb +9 -0
- data/tests/test_aaa_authorization_service.rb +173 -367
- data/tests/test_ace.rb +171 -100
- data/tests/test_acl.rb +10 -1
- data/tests/test_bgp_af.rb +395 -728
- data/tests/test_bgp_neighbor.rb +274 -115
- data/tests/test_bgp_neighbor_af.rb +178 -77
- data/tests/test_bridge_domain.rb +191 -0
- data/tests/test_bridge_domain_vni.rb +116 -0
- data/tests/test_client_utils.rb +111 -0
- data/tests/test_command_config.rb +9 -5
- data/tests/test_command_reference.rb +380 -102
- data/tests/test_dns_domain.rb +13 -3
- data/tests/test_domain_name.rb +13 -3
- data/tests/test_encapsulation.rb +77 -0
- data/tests/test_evpn_vni.rb +25 -7
- data/tests/test_fabricpath_global.rb +167 -163
- data/tests/test_fabricpath_topology.rb +12 -33
- data/tests/test_feature.rb +215 -0
- data/tests/test_grpc.rb +166 -0
- data/tests/test_interface.rb +585 -344
- data/tests/test_interface_bdi.rb +80 -0
- data/tests/test_interface_channel_group.rb +6 -3
- data/tests/test_interface_ospf.rb +26 -24
- data/tests/test_interface_portchannel.rb +1 -0
- data/tests/test_interface_private_vlan.rb +724 -0
- data/tests/test_interface_service_vni.rb +37 -66
- data/tests/test_interface_svi.rb +98 -101
- data/tests/test_interface_switchport.rb +419 -549
- data/tests/test_itd_device_group.rb +145 -0
- data/tests/test_itd_device_group_node.rb +199 -0
- data/tests/test_itd_service.rb +298 -0
- data/tests/test_logger.rb +43 -0
- data/tests/test_name_server.rb +11 -2
- data/tests/test_node.rb +16 -75
- data/tests/test_node_ext.rb +174 -163
- data/tests/test_node_util.rb +119 -0
- data/tests/test_ntp_config.rb +5 -1
- data/tests/test_ntp_server.rb +2 -2
- data/tests/test_nxapi.rb +221 -0
- data/tests/test_overlay_global.rb +47 -38
- data/tests/test_pim.rb +2 -0
- data/tests/test_pim_group_list.rb +2 -0
- data/tests/test_pim_rp_address.rb +2 -0
- data/tests/test_platform.rb +86 -39
- data/tests/test_portchannel_global.rb +211 -135
- data/tests/test_radius_global.rb +13 -5
- data/tests/test_radius_server.rb +256 -104
- data/tests/test_radius_server_group.rb +2 -0
- data/tests/test_router_bgp.rb +781 -485
- data/tests/test_router_ospf.rb +26 -103
- data/tests/test_router_ospf_vrf.rb +52 -57
- data/tests/test_snmp_notification_receiver.rb +2 -0
- data/tests/test_snmpcommunity.rb +2 -0
- data/tests/test_snmpgroup.rb +2 -0
- data/tests/test_snmpnotification.rb +40 -21
- data/tests/test_snmpserver.rb +2 -0
- data/tests/test_snmpuser.rb +2 -0
- data/tests/test_stp_global.rb +563 -0
- data/tests/test_syslog_server.rb +32 -8
- data/tests/test_syslog_settings.rb +22 -9
- data/tests/test_tacacs_server.rb +32 -27
- data/tests/test_tacacs_server_group.rb +100 -45
- data/tests/test_tacacs_server_host.rb +135 -43
- data/tests/test_vdc.rb +2 -16
- data/tests/test_vlan.rb +106 -54
- data/tests/test_vlan_mt_full.rb +11 -21
- data/tests/test_vlan_private.rb +669 -0
- data/tests/test_vpc.rb +312 -159
- data/tests/test_vrf.rb +122 -113
- data/tests/test_vrf_af.rb +238 -0
- data/tests/test_vtp.rb +58 -102
- data/tests/test_vxlan_vtep.rb +38 -17
- data/tests/test_vxlan_vtep_vni.rb +61 -9
- data/tests/test_yum.rb +49 -25
- metadata +122 -36
- data/lib/cisco_node_utils/cmd_ref/fex.yaml +0 -9
- data/lib/cisco_node_utils/cmd_ref/vni.yaml +0 -76
- data/lib/cisco_node_utils/vni.rb +0 -227
- data/tests/test_vni.rb +0 -106
@@ -26,7 +26,6 @@ module Cisco
|
|
26
26
|
|
27
27
|
def initialize(topo_id, instantiate=true)
|
28
28
|
@topo_id = topo_id.to_s
|
29
|
-
@set_params = {}
|
30
29
|
fail ArgumentError, "Invalid value(non-numeric
|
31
30
|
Topo id #{@topo_id})" unless @topo_id[/^\d+$/]
|
32
31
|
|
@@ -35,8 +34,8 @@ module Cisco
|
|
35
34
|
|
36
35
|
def self.topos
|
37
36
|
hash = {}
|
38
|
-
|
39
|
-
return hash if
|
37
|
+
feature = config_get('fabricpath', 'feature')
|
38
|
+
return hash if feature.nil? || feature.to_sym != :enabled
|
40
39
|
topo_list = config_get('fabricpath_topology', 'all_topos')
|
41
40
|
return hash if topo_list.nil?
|
42
41
|
|
@@ -44,24 +43,20 @@ module Cisco
|
|
44
43
|
hash[id] = FabricpathTopo.new(id, false)
|
45
44
|
end
|
46
45
|
hash
|
46
|
+
rescue Cisco::CliError => e
|
47
|
+
# cmd will syntax reject when feature is not enabled
|
48
|
+
raise unless e.clierror =~ /Syntax error/
|
49
|
+
return {}
|
47
50
|
end
|
48
51
|
|
49
52
|
def create
|
50
53
|
fabricpath_feature_set(:enabled) unless :enabled == fabricpath_feature
|
51
54
|
config_set('fabricpath_topology', 'create',
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
def cli_error_check(result)
|
56
|
-
# The NXOS vlan cli does not raise an exception in some conditions and
|
57
|
-
# instead just displays a STDOUT error message; thus NXAPI does not detect
|
58
|
-
# the failure and we must catch it by inspecting the "body" hash entry
|
59
|
-
# returned by NXAPI. This vlan cli behavior is unlikely to change.
|
60
|
-
fail result[2]['body'] unless result[2]['body'].empty?
|
55
|
+
topo_id: @topo_id) unless @topo_id == '0'
|
61
56
|
end
|
62
57
|
|
63
58
|
def destroy
|
64
|
-
config_set('fabricpath_topology', 'destroy',
|
59
|
+
config_set('fabricpath_topology', 'destroy', topo_id: @topo_id)
|
65
60
|
end
|
66
61
|
|
67
62
|
def fabricpath_feature
|
@@ -72,54 +67,50 @@ module Cisco
|
|
72
67
|
FabricpathGlobal.fabricpath_feature_set(fabricpath_set)
|
73
68
|
end
|
74
69
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
70
|
+
def member_vlans
|
71
|
+
config_get('fabricpath_topology', 'member_vlans',
|
72
|
+
@topo_id).gsub(/\s+/, '')
|
73
|
+
end
|
74
|
+
|
75
|
+
def member_vlans=(str)
|
76
|
+
if str.empty?
|
77
|
+
state = 'no'
|
78
|
+
range = ''
|
79
|
+
else
|
80
|
+
state = ''
|
81
|
+
range = str
|
82
|
+
# reset existing range since we don't want incremental sets
|
83
|
+
config_set('fabricpath_topology', 'member_vlans', topo_id: @topo_id,
|
84
|
+
state: 'no', vlan_range: '') if member_vlans != ''
|
83
85
|
end
|
86
|
+
config_set('fabricpath_topology', 'member_vlans', topo_id: @topo_id,
|
87
|
+
state: state, vlan_range: range)
|
84
88
|
end
|
85
89
|
|
86
|
-
def
|
87
|
-
config_get_default('fabricpath_topology', '
|
90
|
+
def default_member_vlans
|
91
|
+
config_get_default('fabricpath_topology', 'member_vlans')
|
88
92
|
end
|
89
93
|
|
90
|
-
def
|
91
|
-
|
92
|
-
return [] if str == '--'
|
93
|
-
str.gsub!('-', '..')
|
94
|
-
if /,/.match(str)
|
95
|
-
str.split(/\s*,\s*/)
|
96
|
-
else
|
97
|
-
str.lines.to_a
|
98
|
-
end
|
94
|
+
def member_vnis
|
95
|
+
config_get('fabricpath_topology', 'member_vnis', @topo_id).gsub(/\s+/, '')
|
99
96
|
end
|
100
97
|
|
101
|
-
def
|
98
|
+
def member_vnis=(str)
|
102
99
|
debug "str is #{str} whose class is #{str.class}"
|
103
|
-
@set_params = {}
|
104
100
|
str = str.join(',') unless str.empty?
|
105
101
|
if str.empty?
|
106
|
-
|
107
|
-
|
108
|
-
@set_params[:vlan_range] = ''
|
102
|
+
state = 'no'
|
103
|
+
range = ''
|
109
104
|
else
|
110
|
-
|
111
|
-
|
112
|
-
@set_params[:state] = ''
|
113
|
-
@set_params[:vlan_range] = str
|
105
|
+
state = ''
|
106
|
+
range = str
|
114
107
|
end
|
115
|
-
|
116
|
-
|
117
|
-
rescue CliError => e
|
118
|
-
raise "[topo #{@topo_id}] '#{e.command}' : #{e.clierror}"
|
108
|
+
config_set('fabricpath_topology', 'member_vnis', topo_id: @topo_id,
|
109
|
+
state: state, vni_range: range)
|
119
110
|
end
|
120
111
|
|
121
|
-
def
|
122
|
-
|
112
|
+
def default_member_vnis
|
113
|
+
config_get_default('fabricpath_topology', 'member_vlans')
|
123
114
|
end
|
124
115
|
|
125
116
|
def topo_name
|
@@ -128,19 +119,15 @@ module Cisco
|
|
128
119
|
|
129
120
|
def topo_name=(desc)
|
130
121
|
fail TypeError unless desc.is_a?(String)
|
131
|
-
@set_params = {}
|
132
122
|
if desc.empty?
|
133
|
-
|
134
|
-
|
135
|
-
@set_params[:name] = ''
|
123
|
+
state = 'no'
|
124
|
+
name = ''
|
136
125
|
else
|
137
|
-
|
138
|
-
|
139
|
-
@set_params[:name] = desc
|
126
|
+
state = ''
|
127
|
+
name = desc
|
140
128
|
end
|
141
|
-
config_set('fabricpath_topology', 'description', @
|
142
|
-
|
143
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
129
|
+
config_set('fabricpath_topology', 'description', topo_id: @topo_id,
|
130
|
+
state: state, name: name)
|
144
131
|
end
|
145
132
|
|
146
133
|
def default_topo_name
|
@@ -63,7 +63,7 @@ module Cisco
|
|
63
63
|
begin
|
64
64
|
config_set('feature', 'fabric_forwarding')
|
65
65
|
rescue Cisco::CliError
|
66
|
-
|
66
|
+
Cisco::Logger.debug '"feature fabric forwarding" CLI was rejected'
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
@@ -71,11 +71,54 @@ module Cisco
|
|
71
71
|
config_get('feature', 'fabric_forwarding')
|
72
72
|
end
|
73
73
|
|
74
|
+
# ---------------------------
|
75
|
+
def self.fex_enable
|
76
|
+
# install feature-set and enable it
|
77
|
+
return if fex_enabled?
|
78
|
+
config_set('feature', 'fex', state: 'install') unless fex_installed?
|
79
|
+
config_set('feature', 'fex', state: '')
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.fex_enabled?
|
83
|
+
config_get('feature', 'fex') =~ /^enabled/
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.fex_installed?
|
87
|
+
config_get('feature', 'fex') !~ /^uninstalled/
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.fex_supported?
|
91
|
+
config_get('feature', 'fex')
|
92
|
+
end
|
93
|
+
|
94
|
+
# ---------------------------
|
95
|
+
def self.itd_enable
|
96
|
+
return if itd_enabled?
|
97
|
+
config_set('feature', 'itd')
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.itd_enabled?
|
101
|
+
config_get('feature', 'itd')
|
102
|
+
rescue Cisco::CliError => e
|
103
|
+
# cmd will syntax reject when feature is not enabled.
|
104
|
+
raise unless e.clierror =~ /Syntax error/
|
105
|
+
return false
|
106
|
+
end
|
107
|
+
|
74
108
|
# ---------------------------
|
75
109
|
def self.nv_overlay_enable
|
76
110
|
# Note: vdc platforms restrict this feature to F3 or newer linecards
|
77
111
|
return if nv_overlay_enabled?
|
78
|
-
config_set('feature', 'nv_overlay')
|
112
|
+
config_set('feature', 'nv_overlay', state: '')
|
113
|
+
sleep 1
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.nv_overlay_disable
|
117
|
+
# Note: vdc platforms restrict this feature to F3 or newer linecards
|
118
|
+
# Note: this is for test purposes only
|
119
|
+
return unless nv_overlay_enabled?
|
120
|
+
config_set('feature', 'nv_overlay', state: 'no')
|
121
|
+
sleep 1
|
79
122
|
end
|
80
123
|
|
81
124
|
def self.nv_overlay_enabled?
|
@@ -86,6 +129,10 @@ module Cisco
|
|
86
129
|
return false
|
87
130
|
end
|
88
131
|
|
132
|
+
def self.nv_overlay_supported?
|
133
|
+
node.cmd_ref.supports?('feature', 'nv_overlay')
|
134
|
+
end
|
135
|
+
|
89
136
|
# ---------------------------
|
90
137
|
def self.nv_overlay_evpn_enable
|
91
138
|
return if nv_overlay_evpn_enabled?
|
@@ -96,10 +143,55 @@ module Cisco
|
|
96
143
|
config_get('feature', 'nv_overlay_evpn')
|
97
144
|
end
|
98
145
|
|
146
|
+
def self.nv_overlay_evpn_supported?
|
147
|
+
node.cmd_ref.supports?('feature', 'nv_overlay_evpn')
|
148
|
+
end
|
149
|
+
|
150
|
+
# ---------------------------
|
151
|
+
def self.ospf_enable
|
152
|
+
return if ospf_enabled?
|
153
|
+
config_set('feature', 'ospf')
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.ospf_enabled?
|
157
|
+
config_get('feature', 'ospf')
|
158
|
+
end
|
159
|
+
|
160
|
+
# ---------------------------
|
161
|
+
def self.pim_enable
|
162
|
+
return if pim_enabled?
|
163
|
+
config_set('feature', 'pim')
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.pim_enabled?
|
167
|
+
config_get('feature', 'pim')
|
168
|
+
end
|
169
|
+
|
170
|
+
# ---------------------------
|
171
|
+
def self.private_vlan_enable
|
172
|
+
return if private_vlan_enabled?
|
173
|
+
config_set('feature', 'private_vlan')
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.private_vlan_enabled?
|
177
|
+
config_get('feature', 'private_vlan')
|
178
|
+
end
|
179
|
+
|
180
|
+
# ---------------------------
|
181
|
+
def self.tacacs_enable
|
182
|
+
return if tacacs_enabled? || platform == :ios_xr
|
183
|
+
config_set('feature', 'tacacs')
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.tacacs_enabled?
|
187
|
+
config_get('feature', 'tacacs')
|
188
|
+
end
|
189
|
+
|
99
190
|
# ---------------------------
|
100
191
|
def self.vn_segment_vlan_based_enable
|
101
192
|
return if vn_segment_vlan_based_enabled?
|
102
|
-
config_set('feature', 'vn_segment_vlan_based')
|
193
|
+
result = config_set('feature', 'vn_segment_vlan_based')
|
194
|
+
cli_error_check(result)
|
103
195
|
end
|
104
196
|
|
105
197
|
def self.vn_segment_vlan_based_enabled?
|
@@ -107,5 +199,75 @@ module Cisco
|
|
107
199
|
end
|
108
200
|
|
109
201
|
# ---------------------------
|
202
|
+
def self.vni_enable
|
203
|
+
return if vni_enabled?
|
204
|
+
result = config_set('feature', 'vni')
|
205
|
+
cli_error_check(result)
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.vni_enabled?
|
209
|
+
config_get('feature', 'vni')
|
210
|
+
end
|
211
|
+
|
212
|
+
# ---------------------------
|
213
|
+
def self.vtp_enable
|
214
|
+
return if vtp_enabled?
|
215
|
+
result = config_set('feature', 'vtp', state: '')
|
216
|
+
cli_error_check(result)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Special Case: The only way to remove a vtp instance
|
220
|
+
# is by disabling the feature.
|
221
|
+
def self.vtp_disable
|
222
|
+
return unless vtp_enabled?
|
223
|
+
config_set('feature', 'vtp', state: 'no')
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.vtp_enabled?
|
227
|
+
config_get('feature', 'vtp')
|
228
|
+
rescue Cisco::CliError => e
|
229
|
+
# cmd will syntax reject when feature is not enabled.
|
230
|
+
raise unless e.clierror =~ /Syntax error/
|
231
|
+
return false
|
232
|
+
end
|
233
|
+
|
234
|
+
# ---------------------------
|
235
|
+
def self.cli_error_check(result)
|
236
|
+
# The NXOS feature cli may not raise an exception in some conditions and
|
237
|
+
# instead just displays a STDOUT error message; thus NXAPI does not detect
|
238
|
+
# the failure and we must catch it by inspecting the "body" hash entry
|
239
|
+
# returned by NXAPI. This cli behavior is unlikely to change soon.
|
240
|
+
fail result[2]['body'] if
|
241
|
+
result[2].is_a?(Hash) &&
|
242
|
+
/Hardware is not capable of supporting/.match(result[2]['body'].to_s)
|
243
|
+
|
244
|
+
# Some test environments get result as a string instead of a hash
|
245
|
+
fail result if
|
246
|
+
result.is_a?(String) &&
|
247
|
+
/Hardware is not capable of supporting/.match(result)
|
248
|
+
end
|
249
|
+
|
250
|
+
# ---------------------------
|
251
|
+
def self.compatible_interfaces(feature, property='supported_module_pids')
|
252
|
+
# Figure out the interfaces in a modular switch that are
|
253
|
+
# compatible with the given feature (or property within a feature)
|
254
|
+
# and return an array of such interfaces
|
255
|
+
module_pids = config_get(feature, property)
|
256
|
+
return [] if module_pids.nil?
|
257
|
+
module_regex = Regexp.new module_pids
|
258
|
+
# first get the compatible modules present in the switch
|
259
|
+
slots = Platform.slots.select do |_slot, filt_mod|
|
260
|
+
filt_mod['pid'] =~ module_regex
|
261
|
+
end
|
262
|
+
return [] if slots.empty?
|
263
|
+
# get the slot numbers only into filtered slots array
|
264
|
+
filt_slots = slots.keys.map { |key| key[/\d+/] }
|
265
|
+
# now filter interfaces in the vdc based on compatible slots
|
266
|
+
vdc = Vdc.new(Vdc.default_vdc_name)
|
267
|
+
filt_intfs = vdc.interface_membership.select do |intf|
|
268
|
+
filt_slots.include? intf[/\d+/]
|
269
|
+
end
|
270
|
+
filt_intfs
|
271
|
+
end
|
110
272
|
end
|
111
273
|
end
|
@@ -16,145 +16,151 @@
|
|
16
16
|
|
17
17
|
require_relative 'cisco_cmn_utils'
|
18
18
|
require_relative 'node_util'
|
19
|
-
require_relative 'pim'
|
20
19
|
require_relative 'vrf'
|
21
|
-
require_relative 'vni'
|
22
20
|
require_relative 'overlay_global'
|
23
21
|
|
24
22
|
# Add some interface-specific constants to the Cisco namespace
|
25
23
|
module Cisco
|
26
24
|
IF_SWITCHPORT_MODE = {
|
27
|
-
disabled:
|
28
|
-
access:
|
29
|
-
trunk:
|
30
|
-
fex_fabric:
|
31
|
-
tunnel:
|
32
|
-
fabricpath:
|
25
|
+
disabled: '',
|
26
|
+
access: 'access',
|
27
|
+
trunk: 'trunk',
|
28
|
+
fex_fabric: 'fex-fabric',
|
29
|
+
tunnel: 'dot1q-tunnel',
|
30
|
+
fabricpath: 'fabricpath',
|
31
|
+
host: 'host',
|
32
|
+
promiscuous: 'promiscuous',
|
33
|
+
secondary: 'secondary',
|
34
|
+
}
|
35
|
+
|
36
|
+
PVLAN_PROPERTY = {
|
37
|
+
host_promisc: 'switchport_mode_private_vlan_host_promiscous',
|
38
|
+
allow_vlan: 'switchport_private_vlan_trunk_allowed_vlan',
|
39
|
+
trunk_assoc: 'switchport_private_vlan_association_trunk',
|
40
|
+
mapping_trunk: 'switchport_private_vlan_mapping_trunk',
|
41
|
+
vlan_mapping: 'private_vlan_mapping',
|
33
42
|
}
|
34
43
|
|
35
44
|
# Interface - node utility class for general interface config management
|
36
45
|
class Interface < NodeUtil
|
46
|
+
# Regexp to match various Ethernet interface variants:
|
47
|
+
# Ethernet
|
48
|
+
# GigabitEthernet
|
49
|
+
# TenGigE
|
50
|
+
# HundredGigE
|
51
|
+
# MgmtEth
|
52
|
+
ETHERNET = Regexp.new('(Ethernet|GigE|MgmtEth)', Regexp::IGNORECASE)
|
53
|
+
# Regexp to match various link bundle interface variants
|
54
|
+
PORTCHANNEL = Regexp.new('(port-channel|Bundle-Ether)', Regexp::IGNORECASE)
|
55
|
+
|
37
56
|
attr_reader :name
|
38
57
|
|
39
58
|
def initialize(name, instantiate=true)
|
40
59
|
fail TypeError unless name.is_a?(String)
|
41
60
|
fail ArgumentError unless name.length > 0
|
42
61
|
@name = name.downcase
|
43
|
-
|
62
|
+
@smr = config_get('interface', 'stp_mst_range')
|
63
|
+
@svr = config_get('interface', 'stp_vlan_range')
|
64
|
+
@match_found = false
|
44
65
|
create if instantiate
|
45
66
|
end
|
46
67
|
|
47
|
-
def
|
68
|
+
def to_s
|
69
|
+
"interface #{name}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.interfaces(opt=nil)
|
48
73
|
hash = {}
|
49
74
|
intf_list = config_get('interface', 'all_interfaces')
|
50
75
|
return hash if intf_list.nil?
|
51
76
|
|
52
77
|
intf_list.each do |id|
|
53
78
|
id = id.downcase
|
79
|
+
next if opt && filter(opt, id)
|
54
80
|
hash[id] = Interface.new(id, false)
|
55
81
|
end
|
56
82
|
hash
|
57
83
|
end
|
58
84
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
########################################################
|
69
|
-
# PROPERTIES #
|
70
|
-
########################################################
|
71
|
-
|
72
|
-
def access_vlan
|
73
|
-
config_get('interface', 'access_vlan', @name)
|
74
|
-
end
|
75
|
-
|
76
|
-
def access_vlan=(vlan)
|
77
|
-
config_set('interface', 'access_vlan', @name, vlan)
|
78
|
-
rescue Cisco::CliError => e
|
79
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
80
|
-
end
|
81
|
-
|
82
|
-
def ipv4_acl_in
|
83
|
-
config_get('interface', 'ipv4_acl_in', @name)
|
84
|
-
end
|
85
|
-
|
86
|
-
def ipv4_acl_in=(val)
|
87
|
-
if val != ''
|
88
|
-
state = ''
|
89
|
-
else
|
90
|
-
state = 'no'
|
91
|
-
val = ipv4_acl_in
|
85
|
+
# General-purpose filter for Interface.interfaces().
|
86
|
+
# opt: Identifies the filter. This may be overloaded in the future to
|
87
|
+
# allow a hash of filter conditions.
|
88
|
+
# id: The interface name
|
89
|
+
# Return: true if the interface should be filtered out, false to keep it.
|
90
|
+
def self.filter(opt, id)
|
91
|
+
case opt
|
92
|
+
when :private_vlan_any
|
93
|
+
return false if config_get('interface', 'private_vlan_any', name: id)
|
92
94
|
end
|
93
|
-
|
94
|
-
return unless val && val != ''
|
95
|
-
config_set('interface', 'ipv4_acl_in', @name, state, val)
|
96
|
-
end
|
97
|
-
|
98
|
-
def default_ipv4_acl_in
|
99
|
-
config_get_default('interface', 'ipv4_acl_in')
|
95
|
+
true
|
100
96
|
end
|
101
97
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
98
|
+
# 'capabilities' is a getter-only helper for minitest and beaker.
|
99
|
+
# mode values:
|
100
|
+
# :hash = Transform the output into a hash
|
101
|
+
# :raw = The raw output from 'show int capabilities'. Some multi-line
|
102
|
+
# values do not translate easily so this option allows the
|
103
|
+
# caller to extract the data it needs.
|
104
|
+
#
|
105
|
+
# Sample cli output:
|
106
|
+
# Model: N7K-M132XP-12L
|
107
|
+
# Type (SFP capable): 10Gbase-SR
|
108
|
+
# Speed: 10,100,1000
|
109
|
+
#
|
110
|
+
# Sample hash output:
|
111
|
+
# {"Model"=>"N7K-M132XP-12L", "Type"=>"10Gbase-SR", "Speed"=>"10,100,1000"}
|
112
|
+
#
|
113
|
+
def self.capabilities(intf, mode=:hash)
|
114
|
+
array = config_get('interface', 'capabilities', name: intf)
|
115
|
+
return array if mode == :raw
|
116
|
+
hash = {}
|
117
|
+
if array
|
118
|
+
array.delete('')
|
119
|
+
array.each do |line|
|
120
|
+
k, v = line.split(':')
|
121
|
+
next if k.nil? || v.nil?
|
122
|
+
k.gsub!(/ \(.*\)/, '') # Remove any parenthetical text from key
|
123
|
+
v.strip!
|
124
|
+
hash[k] = v
|
125
|
+
end
|
112
126
|
end
|
113
|
-
|
114
|
-
return unless val && val != ''
|
115
|
-
config_set('interface', 'ipv4_acl_out', @name, state, val)
|
116
|
-
end
|
117
|
-
|
118
|
-
def default_ipv4_acl_out
|
119
|
-
config_get_default('interface', 'ipv4_acl_out')
|
127
|
+
hash
|
120
128
|
end
|
121
129
|
|
122
|
-
def
|
123
|
-
|
130
|
+
def create
|
131
|
+
feature_vlan_set(true) if @name[/(vlan|bdi)/i]
|
132
|
+
config_set('interface', 'create', name: @name)
|
133
|
+
rescue Cisco::CliError
|
134
|
+
# Some XR platforms do not support channel-group configuration
|
135
|
+
# on some OS versions. Since this is an OS version difference and not
|
136
|
+
# a platform difference, we can't handle this in the YAML.
|
137
|
+
raise unless PORTCHANNEL =~ @name && platform == :ios_xr
|
138
|
+
raise Cisco::UnsupportedError.new('interface', @name, 'create')
|
124
139
|
end
|
125
140
|
|
126
|
-
def
|
127
|
-
|
128
|
-
state = ''
|
129
|
-
else
|
130
|
-
state = 'no'
|
131
|
-
val = ipv6_acl_in
|
132
|
-
end
|
133
|
-
return unless val && val != ''
|
134
|
-
config_set('interface', 'ipv6_acl_in', @name, state, val)
|
141
|
+
def destroy
|
142
|
+
config_set('interface', 'destroy', name: @name)
|
135
143
|
end
|
136
144
|
|
137
|
-
|
138
|
-
|
139
|
-
|
145
|
+
########################################################
|
146
|
+
# PROPERTIES #
|
147
|
+
########################################################
|
140
148
|
|
141
|
-
|
142
|
-
|
143
|
-
|
149
|
+
# For range based attributes, a new attribute purge will
|
150
|
+
# be added in future. When purge is set to true, all the
|
151
|
+
# ranges which are specified in the manifest will be set
|
152
|
+
# to the desired values and those which are not specified
|
153
|
+
# in the manifest will be set to default. When purge is
|
154
|
+
# false, only the ranges specified in the manifest will
|
155
|
+
# be set to the values given in the manifest and others
|
156
|
+
# are left untouched.
|
144
157
|
|
145
|
-
def
|
146
|
-
|
147
|
-
state = ''
|
148
|
-
else
|
149
|
-
state = 'no'
|
150
|
-
val = ipv6_acl_out
|
151
|
-
end
|
152
|
-
return unless val && val != ''
|
153
|
-
config_set('interface', 'ipv6_acl_out', @name, state, val)
|
158
|
+
def access_vlan
|
159
|
+
config_get('interface', 'access_vlan', name: @name)
|
154
160
|
end
|
155
161
|
|
156
|
-
def
|
157
|
-
|
162
|
+
def access_vlan=(vlan)
|
163
|
+
config_set('interface', 'access_vlan', name: @name, vlan: vlan)
|
158
164
|
end
|
159
165
|
|
160
166
|
def default_access_vlan
|
@@ -162,18 +168,18 @@ module Cisco
|
|
162
168
|
end
|
163
169
|
|
164
170
|
def description
|
165
|
-
config_get('interface', 'description', @name)
|
171
|
+
config_get('interface', 'description', name: @name)
|
166
172
|
end
|
167
173
|
|
168
174
|
def description=(desc)
|
169
175
|
fail TypeError unless desc.is_a?(String)
|
170
176
|
if desc.strip.empty?
|
171
|
-
config_set('interface', 'description',
|
177
|
+
config_set('interface', 'description',
|
178
|
+
name: @name, state: 'no', desc: '')
|
172
179
|
else
|
173
|
-
config_set('interface', 'description',
|
180
|
+
config_set('interface', 'description',
|
181
|
+
name: @name, state: '', desc: desc)
|
174
182
|
end
|
175
|
-
rescue Cisco::CliError => e
|
176
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
177
183
|
end
|
178
184
|
|
179
185
|
def default_description
|
@@ -181,17 +187,17 @@ module Cisco
|
|
181
187
|
end
|
182
188
|
|
183
189
|
def encapsulation_dot1q
|
184
|
-
config_get('interface', 'encapsulation_dot1q', @name)
|
190
|
+
config_get('interface', 'encapsulation_dot1q', name: @name)
|
185
191
|
end
|
186
192
|
|
187
193
|
def encapsulation_dot1q=(val)
|
188
194
|
if val.to_s.empty?
|
189
|
-
config_set('interface', 'encapsulation_dot1q',
|
195
|
+
config_set('interface', 'encapsulation_dot1q',
|
196
|
+
name: @name, state: 'no', vlan: '')
|
190
197
|
else
|
191
|
-
config_set('interface', 'encapsulation_dot1q',
|
198
|
+
config_set('interface', 'encapsulation_dot1q',
|
199
|
+
name: @name, state: '', vlan: val)
|
192
200
|
end
|
193
|
-
rescue Cisco::CliError => e
|
194
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
195
201
|
end
|
196
202
|
|
197
203
|
def default_encapsulation_dot1q
|
@@ -207,59 +213,74 @@ module Cisco
|
|
207
213
|
end
|
208
214
|
|
209
215
|
def fabric_forwarding_anycast_gateway
|
210
|
-
config_get('interface', 'fabric_forwarding_anycast_gateway', @name)
|
216
|
+
config_get('interface', 'fabric_forwarding_anycast_gateway', name: @name)
|
211
217
|
end
|
212
218
|
|
213
219
|
def fabric_forwarding_anycast_gateway=(state)
|
214
220
|
no_cmd = (state ? '' : 'no')
|
215
221
|
config_set('interface',
|
216
|
-
'fabric_forwarding_anycast_gateway',
|
222
|
+
'fabric_forwarding_anycast_gateway',
|
223
|
+
name: @name, state: no_cmd)
|
217
224
|
fail if fabric_forwarding_anycast_gateway.to_s != state.to_s
|
218
225
|
rescue Cisco::CliError => e
|
219
|
-
|
220
|
-
raise "#{info} 'fabric_forwarding_anycast_gateway' can only be " \
|
226
|
+
raise "#{e} 'fabric_forwarding_anycast_gateway' can only be " \
|
221
227
|
'configured on a vlan interface' unless /vlan/.match(@name)
|
222
228
|
anycast_gateway_mac = OverlayGlobal.new.anycast_gateway_mac
|
223
229
|
if anycast_gateway_mac.nil? || anycast_gateway_mac.empty?
|
224
|
-
raise "#{
|
230
|
+
raise "#{e} Anycast gateway mac must be configured " \
|
225
231
|
'before configuring forwarding mode under interface'
|
226
232
|
end
|
227
|
-
raise
|
233
|
+
raise
|
228
234
|
end
|
229
235
|
|
230
236
|
def default_fabric_forwarding_anycast_gateway
|
231
237
|
config_get_default('interface', 'fabric_forwarding_anycast_gateway')
|
232
238
|
end
|
233
239
|
|
234
|
-
def
|
235
|
-
|
236
|
-
fail 'fex_feature not found' if fex.nil?
|
237
|
-
fex.to_sym
|
240
|
+
def ipv4_acl_in
|
241
|
+
config_get('interface', 'ipv4_acl_in', name: @name)
|
238
242
|
end
|
239
243
|
|
240
|
-
def
|
241
|
-
|
242
|
-
|
244
|
+
def ipv4_acl_in=(val)
|
245
|
+
if val != ''
|
246
|
+
state = ''
|
247
|
+
else
|
248
|
+
state = 'no'
|
249
|
+
val = ipv4_acl_in
|
250
|
+
end
|
243
251
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
252
|
+
return unless val && val != ''
|
253
|
+
config_set('interface', 'ipv4_acl_in',
|
254
|
+
name: @name, state: state, acl: val)
|
255
|
+
end
|
256
|
+
|
257
|
+
def default_ipv4_acl_in
|
258
|
+
config_get_default('interface', 'ipv4_acl_in')
|
259
|
+
end
|
260
|
+
|
261
|
+
def ipv4_acl_out
|
262
|
+
config_get('interface', 'ipv4_acl_out', name: @name)
|
263
|
+
end
|
264
|
+
|
265
|
+
def ipv4_acl_out=(val)
|
266
|
+
if val != ''
|
267
|
+
state = ''
|
268
|
+
else
|
269
|
+
state = 'no'
|
270
|
+
val = ipv4_acl_out
|
256
271
|
end
|
257
|
-
|
258
|
-
|
272
|
+
|
273
|
+
return unless val && val != ''
|
274
|
+
config_set('interface', 'ipv4_acl_out',
|
275
|
+
name: @name, state: state, acl: val)
|
276
|
+
end
|
277
|
+
|
278
|
+
def default_ipv4_acl_out
|
279
|
+
config_get_default('interface', 'ipv4_acl_out')
|
259
280
|
end
|
260
281
|
|
261
282
|
def ipv4_addr_mask_set(addr, mask, secondary=false)
|
262
|
-
|
283
|
+
check_switchport(:disabled)
|
263
284
|
sec = secondary ? 'secondary' : ''
|
264
285
|
if addr.nil? || addr == default_ipv4_address
|
265
286
|
state = 'no'
|
@@ -275,13 +296,22 @@ module Cisco
|
|
275
296
|
state = ''
|
276
297
|
am = "#{addr}/#{mask}"
|
277
298
|
end
|
278
|
-
config_set('interface', 'ipv4_addr_mask',
|
279
|
-
|
280
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
299
|
+
config_set('interface', 'ipv4_addr_mask',
|
300
|
+
name: @name, state: state, addr: am, secondary: sec)
|
281
301
|
end
|
282
302
|
|
283
303
|
def ipv4_addr_mask
|
284
|
-
config_get('interface', 'ipv4_addr_mask', @name)
|
304
|
+
val = config_get('interface', 'ipv4_addr_mask', name: @name)
|
305
|
+
if val && platform == :ios_xr
|
306
|
+
# IOS XR reports address as <address> <bitmask> [secondary] but we
|
307
|
+
# want <address>/<length> [secondary]
|
308
|
+
val.each_with_index do |entry, i|
|
309
|
+
mask = entry[1].split(' ')
|
310
|
+
mask[0] = Utils.bitmask_to_length(mask[0])
|
311
|
+
val[i][1] = mask.join(' ')
|
312
|
+
end
|
313
|
+
end
|
314
|
+
val
|
285
315
|
end
|
286
316
|
|
287
317
|
def select_ipv4_attribute(attribute)
|
@@ -346,31 +376,43 @@ module Cisco
|
|
346
376
|
end
|
347
377
|
|
348
378
|
def ipv4_arp_timeout
|
349
|
-
config_get('interface', ipv4_arp_timeout_lookup_string, @name)
|
379
|
+
config_get('interface', ipv4_arp_timeout_lookup_string, name: @name)
|
350
380
|
end
|
351
381
|
|
352
382
|
def ipv4_arp_timeout=(timeout)
|
353
383
|
fail "'ipv4 arp timeout' can ony be configured on a vlan interface" unless
|
354
384
|
/vlan/.match(@name)
|
355
385
|
state = (timeout == default_ipv4_arp_timeout) ? 'no' : ''
|
356
|
-
config_set('interface', 'ipv4_arp_timeout',
|
386
|
+
config_set('interface', 'ipv4_arp_timeout',
|
387
|
+
name: @name, state: state, timeout: timeout)
|
357
388
|
end
|
358
389
|
|
359
390
|
def default_ipv4_arp_timeout
|
360
391
|
config_get_default('interface', ipv4_arp_timeout_lookup_string)
|
361
392
|
end
|
362
393
|
|
394
|
+
def ipv4_forwarding
|
395
|
+
config_get('interface', 'ipv4_forwarding', name: @name)
|
396
|
+
end
|
397
|
+
|
398
|
+
def ipv4_forwarding=(state)
|
399
|
+
config_set('interface', 'ipv4_forwarding',
|
400
|
+
name: @name, state: state ? '' : 'no')
|
401
|
+
end
|
402
|
+
|
403
|
+
def default_ipv4_forwarding
|
404
|
+
config_get_default('interface', 'ipv4_forwarding')
|
405
|
+
end
|
406
|
+
|
363
407
|
def ipv4_pim_sparse_mode
|
364
|
-
config_get('interface', 'ipv4_pim_sparse_mode', @name)
|
408
|
+
config_get('interface', 'ipv4_pim_sparse_mode', name: @name)
|
365
409
|
end
|
366
410
|
|
367
411
|
def ipv4_pim_sparse_mode=(state)
|
368
|
-
|
369
|
-
|
370
|
-
config_set('interface', 'ipv4_pim_sparse_mode',
|
371
|
-
state ? '' : 'no')
|
372
|
-
rescue Cisco::CliError => e
|
373
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
412
|
+
check_switchport(:disabled)
|
413
|
+
Feature.pim_enable unless platform == :ios_xr
|
414
|
+
config_set('interface', 'ipv4_pim_sparse_mode',
|
415
|
+
name: @name, state: state ? '' : 'no')
|
374
416
|
end
|
375
417
|
|
376
418
|
def default_ipv4_pim_sparse_mode
|
@@ -378,13 +420,13 @@ module Cisco
|
|
378
420
|
end
|
379
421
|
|
380
422
|
def ipv4_proxy_arp
|
381
|
-
config_get('interface', 'ipv4_proxy_arp', @name)
|
423
|
+
config_get('interface', 'ipv4_proxy_arp', name: @name)
|
382
424
|
end
|
383
425
|
|
384
426
|
def ipv4_proxy_arp=(proxy_arp)
|
385
|
-
|
427
|
+
check_switchport(:disabled)
|
386
428
|
no_cmd = (proxy_arp ? '' : 'no')
|
387
|
-
config_set('interface', 'ipv4_proxy_arp', @name, no_cmd)
|
429
|
+
config_set('interface', 'ipv4_proxy_arp', name: @name, state: no_cmd)
|
388
430
|
end
|
389
431
|
|
390
432
|
def default_ipv4_proxy_arp
|
@@ -401,54 +443,98 @@ module Cisco
|
|
401
443
|
end
|
402
444
|
|
403
445
|
def ipv4_redirects
|
404
|
-
config_get('interface', ipv4_redirects_lookup_string, @name)
|
446
|
+
config_get('interface', ipv4_redirects_lookup_string, name: @name)
|
405
447
|
end
|
406
448
|
|
407
449
|
def ipv4_redirects=(redirects)
|
408
|
-
|
450
|
+
check_switchport(:disabled)
|
409
451
|
no_cmd = (redirects ? '' : 'no')
|
410
|
-
config_set('interface', ipv4_redirects_lookup_string,
|
452
|
+
config_set('interface', ipv4_redirects_lookup_string,
|
453
|
+
name: @name, state: no_cmd)
|
411
454
|
end
|
412
455
|
|
413
456
|
def default_ipv4_redirects
|
414
457
|
config_get_default('interface', ipv4_redirects_lookup_string)
|
415
458
|
end
|
416
459
|
|
460
|
+
def ipv6_acl_in
|
461
|
+
config_get('interface', 'ipv6_acl_in', name: @name)
|
462
|
+
end
|
463
|
+
|
464
|
+
def ipv6_acl_in=(val)
|
465
|
+
if val != ''
|
466
|
+
state = ''
|
467
|
+
else
|
468
|
+
state = 'no'
|
469
|
+
val = ipv6_acl_in
|
470
|
+
end
|
471
|
+
return unless val && val != ''
|
472
|
+
config_set('interface', 'ipv6_acl_in',
|
473
|
+
name: @name, state: state, acl: val)
|
474
|
+
end
|
475
|
+
|
476
|
+
def default_ipv6_acl_in
|
477
|
+
config_get_default('interface', 'ipv6_acl_in')
|
478
|
+
end
|
479
|
+
|
480
|
+
def ipv6_acl_out
|
481
|
+
config_get('interface', 'ipv6_acl_out', name: @name)
|
482
|
+
end
|
483
|
+
|
484
|
+
def ipv6_acl_out=(val)
|
485
|
+
if val != ''
|
486
|
+
state = ''
|
487
|
+
else
|
488
|
+
state = 'no'
|
489
|
+
val = ipv6_acl_out
|
490
|
+
end
|
491
|
+
return unless val && val != ''
|
492
|
+
config_set('interface', 'ipv6_acl_out',
|
493
|
+
name: @name, state: state, acl: val)
|
494
|
+
end
|
495
|
+
|
496
|
+
def default_ipv6_acl_out
|
497
|
+
config_get_default('interface', 'ipv6_acl_out')
|
498
|
+
end
|
499
|
+
|
417
500
|
def feature_lacp?
|
418
501
|
config_get('interface', 'feature_lacp')
|
419
502
|
end
|
420
503
|
|
421
504
|
def feature_lacp_set(val)
|
422
505
|
return if feature_lacp? == val
|
423
|
-
config_set('interface', 'feature_lacp', val ? '' : 'no')
|
506
|
+
config_set('interface', 'feature_lacp', state: val ? '' : 'no')
|
507
|
+
end
|
508
|
+
|
509
|
+
def mtu_lookup_string
|
510
|
+
case @name
|
511
|
+
when /loopback/i
|
512
|
+
return 'mtu_loopback'
|
513
|
+
else
|
514
|
+
return 'mtu_other_interfaces'
|
515
|
+
end
|
424
516
|
end
|
425
517
|
|
426
518
|
def mtu
|
427
|
-
config_get('interface',
|
519
|
+
config_get('interface', mtu_lookup_string, name: @name)
|
428
520
|
end
|
429
521
|
|
430
522
|
def mtu=(val)
|
431
|
-
|
432
|
-
config_set('interface',
|
433
|
-
|
434
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
523
|
+
check_switchport(:disabled)
|
524
|
+
config_set('interface', mtu_lookup_string,
|
525
|
+
name: @name, state: '', mtu: val)
|
435
526
|
end
|
436
527
|
|
437
528
|
def default_mtu
|
438
|
-
config_get_default('interface',
|
529
|
+
config_get_default('interface', mtu_lookup_string)
|
439
530
|
end
|
440
531
|
|
441
532
|
def speed
|
442
|
-
config_get('interface', 'speed', @name)
|
533
|
+
config_get('interface', 'speed', name: @name)
|
443
534
|
end
|
444
535
|
|
445
536
|
def speed=(val)
|
446
|
-
|
447
|
-
fail 'Changing interface speed is not permitted on this platform'
|
448
|
-
end
|
449
|
-
config_set('interface', 'speed', @name, val)
|
450
|
-
rescue Cisco::CliError => e
|
451
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
537
|
+
config_set('interface', 'speed', name: @name, speed: val)
|
452
538
|
end
|
453
539
|
|
454
540
|
def default_speed
|
@@ -456,16 +542,11 @@ module Cisco
|
|
456
542
|
end
|
457
543
|
|
458
544
|
def duplex
|
459
|
-
config_get('interface', 'duplex', @name)
|
545
|
+
config_get('interface', 'duplex', name: @name)
|
460
546
|
end
|
461
547
|
|
462
548
|
def duplex=(val)
|
463
|
-
|
464
|
-
fail 'Changing interface duplex is not permitted on this platform'
|
465
|
-
end
|
466
|
-
config_set('interface', 'duplex', @name, val)
|
467
|
-
rescue Cisco::CliError => e
|
468
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
549
|
+
config_set('interface', 'duplex', name: @name, duplex: val)
|
469
550
|
end
|
470
551
|
|
471
552
|
def default_duplex
|
@@ -474,9 +555,9 @@ module Cisco
|
|
474
555
|
|
475
556
|
def negotiate_auto_lookup_string
|
476
557
|
case @name
|
477
|
-
when
|
558
|
+
when ETHERNET
|
478
559
|
return 'negotiate_auto_ethernet'
|
479
|
-
when
|
560
|
+
when PORTCHANNEL
|
480
561
|
return 'negotiate_auto_portchannel'
|
481
562
|
else
|
482
563
|
return 'negotiate_auto_other_interfaces'
|
@@ -484,13 +565,13 @@ module Cisco
|
|
484
565
|
end
|
485
566
|
|
486
567
|
def negotiate_auto
|
487
|
-
config_get('interface', negotiate_auto_lookup_string, @name)
|
568
|
+
config_get('interface', negotiate_auto_lookup_string, name: @name)
|
488
569
|
end
|
489
570
|
|
490
571
|
def negotiate_auto=(negotiate_auto)
|
491
572
|
lookup = negotiate_auto_lookup_string
|
492
573
|
no_cmd = (negotiate_auto ? '' : 'no')
|
493
|
-
config_set('interface', lookup, @name, no_cmd)
|
574
|
+
config_set('interface', lookup, name: @name, state: no_cmd)
|
494
575
|
end
|
495
576
|
|
496
577
|
def default_negotiate_auto
|
@@ -498,19 +579,17 @@ module Cisco
|
|
498
579
|
end
|
499
580
|
|
500
581
|
def shutdown
|
501
|
-
config_get('interface', 'shutdown', @name)
|
582
|
+
config_get('interface', 'shutdown', name: @name)
|
502
583
|
end
|
503
584
|
|
504
585
|
def shutdown=(state)
|
505
586
|
no_cmd = (state ? '' : 'no')
|
506
|
-
config_set('interface', 'shutdown', @name, no_cmd)
|
507
|
-
rescue Cisco::CliError => e
|
508
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
587
|
+
config_set('interface', 'shutdown', name: @name, state: no_cmd)
|
509
588
|
end
|
510
589
|
|
511
590
|
def default_shutdown
|
512
591
|
case @name
|
513
|
-
when
|
592
|
+
when ETHERNET
|
514
593
|
def_sw = system_default_switchport
|
515
594
|
def_shut = system_default_switchport_shutdown
|
516
595
|
|
@@ -529,7 +608,7 @@ module Cisco
|
|
529
608
|
when /loopback/i
|
530
609
|
lookup = 'shutdown_loopback'
|
531
610
|
|
532
|
-
when
|
611
|
+
when PORTCHANNEL
|
533
612
|
lookup = 'shutdown_ether_channel'
|
534
613
|
|
535
614
|
when /Vlan/i
|
@@ -541,28 +620,236 @@ module Cisco
|
|
541
620
|
config_get_default('interface', lookup)
|
542
621
|
end
|
543
622
|
|
623
|
+
def stp_bpdufilter
|
624
|
+
config_get('interface', 'stp_bpdufilter', name: @name)
|
625
|
+
end
|
626
|
+
|
627
|
+
def stp_bpdufilter=(val)
|
628
|
+
check_switchport([:access, :trunk])
|
629
|
+
if val
|
630
|
+
state = ''
|
631
|
+
else
|
632
|
+
state = 'no'
|
633
|
+
val = ''
|
634
|
+
end
|
635
|
+
config_set('interface',
|
636
|
+
'stp_bpdufilter', name: @name, state: state, filter: val)
|
637
|
+
end
|
638
|
+
|
639
|
+
def default_stp_bpdufilter
|
640
|
+
config_get_default('interface', 'stp_bpdufilter')
|
641
|
+
end
|
642
|
+
|
643
|
+
def stp_bpduguard
|
644
|
+
config_get('interface', 'stp_bpduguard', name: @name)
|
645
|
+
end
|
646
|
+
|
647
|
+
def stp_bpduguard=(val)
|
648
|
+
if val
|
649
|
+
state = ''
|
650
|
+
else
|
651
|
+
state = 'no'
|
652
|
+
val = ''
|
653
|
+
end
|
654
|
+
config_set('interface',
|
655
|
+
'stp_bpduguard', name: @name, state: state, guard: val)
|
656
|
+
end
|
657
|
+
|
658
|
+
def default_stp_bpduguard
|
659
|
+
config_get_default('interface', 'stp_bpduguard')
|
660
|
+
end
|
661
|
+
|
662
|
+
def stp_cost
|
663
|
+
cost = config_get('interface', 'stp_cost', name: @name)
|
664
|
+
cost == 'auto' ? cost : cost.to_i
|
665
|
+
end
|
666
|
+
|
667
|
+
def stp_cost=(val)
|
668
|
+
check_switchport([:access, :trunk])
|
669
|
+
config_set('interface', 'stp_cost', name: @name, cost: val)
|
670
|
+
end
|
671
|
+
|
672
|
+
def default_stp_cost
|
673
|
+
config_get_default('interface', 'stp_cost')
|
674
|
+
end
|
675
|
+
|
676
|
+
def stp_guard
|
677
|
+
config_get('interface', 'stp_guard', name: @name)
|
678
|
+
end
|
679
|
+
|
680
|
+
def stp_guard=(val)
|
681
|
+
check_switchport([:access, :trunk])
|
682
|
+
if val
|
683
|
+
state = ''
|
684
|
+
else
|
685
|
+
state = 'no'
|
686
|
+
val = ''
|
687
|
+
end
|
688
|
+
config_set('interface', 'stp_guard', name: @name, state: state,
|
689
|
+
guard: val)
|
690
|
+
end
|
691
|
+
|
692
|
+
def default_stp_guard
|
693
|
+
config_get_default('interface', 'stp_guard')
|
694
|
+
end
|
695
|
+
|
696
|
+
def stp_link_type
|
697
|
+
config_get('interface', 'stp_link_type', name: @name)
|
698
|
+
end
|
699
|
+
|
700
|
+
def stp_link_type=(val)
|
701
|
+
check_switchport([:access, :trunk])
|
702
|
+
config_set('interface', 'stp_link_type', name: @name, type: val)
|
703
|
+
end
|
704
|
+
|
705
|
+
def default_stp_link_type
|
706
|
+
config_get_default('interface', 'stp_link_type')
|
707
|
+
end
|
708
|
+
|
709
|
+
def stp_port_priority
|
710
|
+
config_get('interface', 'stp_port_priority', name: @name)
|
711
|
+
end
|
712
|
+
|
713
|
+
def stp_port_priority=(val)
|
714
|
+
check_switchport([:access, :trunk])
|
715
|
+
config_set('interface', 'stp_port_priority', name: @name, pp: val)
|
716
|
+
end
|
717
|
+
|
718
|
+
def default_stp_port_priority
|
719
|
+
config_get_default('interface', 'stp_port_priority')
|
720
|
+
end
|
721
|
+
|
722
|
+
# Getter: Builds an array of mst cost commands currently
|
723
|
+
# on the device.
|
724
|
+
# cli: spanning-tree mst 0,2-4,6,8-12 cost 1000
|
725
|
+
# spanning-tree mst 4000-4020 cost 2568
|
726
|
+
# array: [['0,2-4,6,8-12', '1000'], ['4000-4020', '2568']]
|
727
|
+
#
|
728
|
+
def stp_mst_cost
|
729
|
+
config_get('interface', 'stp_mst_cost', name: @name)
|
730
|
+
end
|
731
|
+
|
732
|
+
def stp_mst_cost=(list)
|
733
|
+
check_switchport([:access, :trunk])
|
734
|
+
config_set('interface', 'stp_mst_cost',
|
735
|
+
name: @name, state: 'no', range: @smr,
|
736
|
+
val: '') if list.empty?
|
737
|
+
set_range_based_params(list, 'stp_mst_cost')
|
738
|
+
end
|
739
|
+
|
740
|
+
def default_stp_mst_cost
|
741
|
+
config_get_default('interface', 'stp_mst_cost')
|
742
|
+
end
|
743
|
+
|
744
|
+
# Getter: Builds an array of mst port-priority commands
|
745
|
+
# currently on the device.
|
746
|
+
# cli: spanning-tree mst 0,2-4,6,8-12 port-priority 64
|
747
|
+
# spanning-tree mst 4000-4020 port-priority 160
|
748
|
+
# array: [['0,2-4,6,8-12', '64'], ['4000-4020', '160']]
|
749
|
+
#
|
750
|
+
def stp_mst_port_priority
|
751
|
+
config_get('interface', 'stp_mst_port_priority', name: @name)
|
752
|
+
end
|
753
|
+
|
754
|
+
def stp_mst_port_priority=(list)
|
755
|
+
check_switchport([:access, :trunk])
|
756
|
+
config_set('interface', 'stp_mst_port_priority',
|
757
|
+
name: @name, state: 'no', range: @smr,
|
758
|
+
val: '') if list.empty?
|
759
|
+
set_range_based_params(list, 'stp_mst_port_priority')
|
760
|
+
end
|
761
|
+
|
762
|
+
def default_stp_mst_port_priority
|
763
|
+
config_get_default('interface', 'stp_mst_port_priority')
|
764
|
+
end
|
765
|
+
|
766
|
+
def stp_port_type
|
767
|
+
config_get('interface', 'stp_port_type', name: @name)
|
768
|
+
end
|
769
|
+
|
770
|
+
def stp_port_type=(val)
|
771
|
+
if val
|
772
|
+
state = ''
|
773
|
+
else
|
774
|
+
state = 'no'
|
775
|
+
val = ''
|
776
|
+
end
|
777
|
+
config_set('interface', 'stp_port_type', name: @name,
|
778
|
+
state: state, type: val)
|
779
|
+
end
|
780
|
+
|
781
|
+
def default_stp_port_type
|
782
|
+
config_get_default('interface', 'stp_port_type')
|
783
|
+
end
|
784
|
+
|
785
|
+
# Getter: Builds an array of vlan cost commands currently
|
786
|
+
# on the device.
|
787
|
+
# cli: spanning-tree vlan 1-4,6,8-12 cost 1000
|
788
|
+
# spanning-tree vlan 3000-3960 cost 2568
|
789
|
+
# array: [['1-4,6,8-12', '1000'], ['3000-3960', '2568']]
|
790
|
+
#
|
791
|
+
def stp_vlan_cost
|
792
|
+
config_get('interface', 'stp_vlan_cost', name: @name)
|
793
|
+
end
|
794
|
+
|
795
|
+
def stp_vlan_cost=(list)
|
796
|
+
check_switchport([:access, :trunk])
|
797
|
+
config_set('interface', 'stp_vlan_cost',
|
798
|
+
name: @name, state: 'no',
|
799
|
+
range: @svr, val: '') if list.empty?
|
800
|
+
set_range_based_params(list, 'stp_vlan_cost')
|
801
|
+
end
|
802
|
+
|
803
|
+
def default_stp_vlan_cost
|
804
|
+
config_get_default('interface', 'stp_vlan_cost')
|
805
|
+
end
|
806
|
+
|
807
|
+
# Getter: Builds an array of vlan port-priority commands
|
808
|
+
# currently on the device.
|
809
|
+
# cli: spanning-tree vlan 1-4,6,8-12 port-priority 64
|
810
|
+
# spanning-tree vlan 3000-3960 port-priority 160
|
811
|
+
# array: [['1-4,6,8-12', '64'], ['3000-3960', '160']]
|
812
|
+
#
|
813
|
+
def stp_vlan_port_priority
|
814
|
+
config_get('interface', 'stp_vlan_port_priority', name: @name)
|
815
|
+
end
|
816
|
+
|
817
|
+
def stp_vlan_port_priority=(list)
|
818
|
+
check_switchport([:access, :trunk])
|
819
|
+
config_set('interface', 'stp_vlan_port_priority',
|
820
|
+
name: @name, state: 'no',
|
821
|
+
range: @svr, val: '') if list.empty?
|
822
|
+
set_range_based_params(list, 'stp_vlan_port_priority')
|
823
|
+
end
|
824
|
+
|
825
|
+
def default_stp_vlan_port_priority
|
826
|
+
config_get_default('interface', 'stp_vlan_port_priority')
|
827
|
+
end
|
828
|
+
|
544
829
|
def switchport
|
545
830
|
# This is "switchport", not "switchport mode"
|
546
|
-
config_get('interface', 'switchport', @name)
|
831
|
+
config_get('interface', 'switchport', name: @name)
|
547
832
|
end
|
548
833
|
|
549
834
|
def switchport_enable(val=true)
|
550
|
-
config_set('interface', 'switchport', @name, val ? '' : 'no')
|
835
|
+
config_set('interface', 'switchport', name: @name, state: val ? '' : 'no')
|
551
836
|
end
|
552
837
|
|
553
838
|
# switchport_autostate_exclude is exclusive to switchport interfaces
|
554
839
|
def switchport_autostate_exclude
|
555
840
|
config_get('interface',
|
556
|
-
'switchport_autostate_exclude', @name)
|
841
|
+
'switchport_autostate_exclude', name: @name)
|
557
842
|
end
|
558
843
|
|
559
844
|
def switchport_autostate_exclude=(val)
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
845
|
+
if platform == :nexus
|
846
|
+
# cannot configure autostate unless feature vlan is enabled
|
847
|
+
fail('switchport mode must be configured before ' \
|
848
|
+
'switchport autostate') unless switchport
|
849
|
+
feature_vlan_set(true)
|
850
|
+
end
|
564
851
|
config_set('interface', 'switchport_autostate_exclude',
|
565
|
-
@name, val ? '' : 'no')
|
852
|
+
name: @name, state: val ? '' : 'no')
|
566
853
|
end
|
567
854
|
|
568
855
|
def default_switchport_autostate_exclude
|
@@ -571,9 +858,9 @@ module Cisco
|
|
571
858
|
|
572
859
|
def switchport_mode_lookup_string
|
573
860
|
case @name
|
574
|
-
when
|
861
|
+
when ETHERNET
|
575
862
|
return 'switchport_mode_ethernet'
|
576
|
-
when
|
863
|
+
when PORTCHANNEL
|
577
864
|
return 'switchport_mode_port_channel'
|
578
865
|
else
|
579
866
|
return 'switchport_mode_other_interfaces'
|
@@ -581,7 +868,8 @@ module Cisco
|
|
581
868
|
end
|
582
869
|
|
583
870
|
def switchport_mode
|
584
|
-
|
871
|
+
return nil if platform == :ios_xr
|
872
|
+
mode = config_get('interface', switchport_mode_lookup_string, name: @name)
|
585
873
|
|
586
874
|
return mode.nil? ? :disabled : IF_SWITCHPORT_MODE.key(mode)
|
587
875
|
|
@@ -589,6 +877,7 @@ module Cisco
|
|
589
877
|
# Assume this is an interface that doesn't support switchport.
|
590
878
|
# Do not raise exception since the providers will prefetch this property
|
591
879
|
# regardless of interface type.
|
880
|
+
# TODO: this should probably be nil instead
|
592
881
|
return :disabled
|
593
882
|
end
|
594
883
|
|
@@ -598,13 +887,10 @@ module Cisco
|
|
598
887
|
if :fabricpath == mode_set
|
599
888
|
fabricpath_feature_set(:enabled) unless :enabled == fabricpath_feature
|
600
889
|
elsif :fex_fabric == mode_set
|
601
|
-
|
890
|
+
Feature.fex_enable
|
602
891
|
end
|
603
|
-
config_set('interface', switchport_mode_lookup_string,
|
604
|
-
IF_SWITCHPORT_MODE[mode_set])
|
605
|
-
|
606
|
-
rescue RuntimeError
|
607
|
-
raise "[#{@name}] switchport_mode is not supported on this interface"
|
892
|
+
config_set('interface', switchport_mode_lookup_string,
|
893
|
+
name: @name, state: '', mode: IF_SWITCHPORT_MODE[mode_set])
|
608
894
|
end
|
609
895
|
|
610
896
|
def switchport_mode=(mode_set)
|
@@ -617,13 +903,13 @@ module Cisco
|
|
617
903
|
when :disabled
|
618
904
|
if switchport
|
619
905
|
# Note: turn off switchport command, not switchport mode
|
620
|
-
config_set('interface', 'switchport', @name, 'no')
|
906
|
+
config_set('interface', 'switchport', name: @name, state: 'no')
|
621
907
|
end
|
622
908
|
|
623
909
|
when :default
|
624
910
|
if :disabled == default_switchport_mode
|
625
911
|
config_set('interface', switchport_mode_lookup_string,
|
626
|
-
@name, 'no', '')
|
912
|
+
name: @name, state: 'no', mode: '')
|
627
913
|
else
|
628
914
|
switchport_enable_and_mode(mode_set)
|
629
915
|
end
|
@@ -631,31 +917,27 @@ module Cisco
|
|
631
917
|
else
|
632
918
|
switchport_enable_and_mode(mode_set)
|
633
919
|
end # case
|
634
|
-
|
635
|
-
rescue Cisco::CliError => e
|
636
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
637
920
|
end
|
638
921
|
|
639
922
|
def default_switchport_mode
|
923
|
+
return nil if platform == :ios_xr
|
640
924
|
return :disabled unless system_default_switchport
|
641
925
|
IF_SWITCHPORT_MODE.key(
|
642
926
|
config_get_default('interface', switchport_mode_lookup_string))
|
643
927
|
end
|
644
928
|
|
645
929
|
def switchport_trunk_allowed_vlan
|
646
|
-
config_get('interface', 'switchport_trunk_allowed_vlan', @name)
|
930
|
+
config_get('interface', 'switchport_trunk_allowed_vlan', name: @name)
|
647
931
|
end
|
648
932
|
|
649
933
|
def switchport_trunk_allowed_vlan=(val)
|
650
934
|
if val.nil?
|
651
|
-
config_set(
|
652
|
-
|
935
|
+
config_set('interface', 'switchport_trunk_allowed_vlan',
|
936
|
+
name: @name, state: 'no', vlan: '')
|
653
937
|
else
|
654
|
-
config_set(
|
655
|
-
|
938
|
+
config_set('interface', 'switchport_trunk_allowed_vlan',
|
939
|
+
name: @name, state: '', vlan: val)
|
656
940
|
end
|
657
|
-
rescue Cisco::CliError => e
|
658
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
659
941
|
end
|
660
942
|
|
661
943
|
def default_switchport_trunk_allowed_vlan
|
@@ -663,19 +945,488 @@ module Cisco
|
|
663
945
|
end
|
664
946
|
|
665
947
|
def switchport_trunk_native_vlan
|
666
|
-
config_get('interface', 'switchport_trunk_native_vlan', @name)
|
948
|
+
config_get('interface', 'switchport_trunk_native_vlan', name: @name)
|
667
949
|
end
|
668
950
|
|
669
951
|
def switchport_trunk_native_vlan=(val)
|
670
952
|
if val.nil?
|
671
|
-
config_set(
|
672
|
-
|
953
|
+
config_set('interface', 'switchport_trunk_native_vlan',
|
954
|
+
name: @name, state: 'no', vlan: '')
|
673
955
|
else
|
674
|
-
config_set(
|
675
|
-
|
956
|
+
config_set('interface', 'switchport_trunk_native_vlan',
|
957
|
+
name: @name, state: '', vlan: val)
|
676
958
|
end
|
677
|
-
|
678
|
-
|
959
|
+
end
|
960
|
+
|
961
|
+
# Interface private vlan configuration properties
|
962
|
+
# private vlan mode (host, promisc, trunk promisc , trunk sec)
|
963
|
+
# private vlan mapping
|
964
|
+
# private vlan native vlan
|
965
|
+
# private vlan allow vlan
|
966
|
+
|
967
|
+
def cli_error_check(result)
|
968
|
+
# The NXOS interface private vlan cli does not raise an exception
|
969
|
+
# in some conditions and instead just displays a STDOUT error message
|
970
|
+
# thus NXAPI does not detect the failure.
|
971
|
+
# We must catch it by inspecting the "body" hash entry
|
972
|
+
# returned by NXAPI. This vlan cli behavior is unlikely to change.
|
973
|
+
# Check for messages that can be safely ignored.
|
974
|
+
|
975
|
+
errors = /(ERROR:|VLAN:|Eth)/
|
976
|
+
return unless
|
977
|
+
result[1].is_a?(Hash) && errors.match(result[1]['body'].to_s)
|
978
|
+
# Split errors into a list, but keep the delimiter as part of the message.
|
979
|
+
error_list =
|
980
|
+
(result[1]['body'].split(errors) - ['']).each_slice(2).map(&:join)
|
981
|
+
error_list.each do |_msg|
|
982
|
+
fail result[1]['body']
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
986
|
+
def switchport_enable_and_mode_private_vlan_host(mode_set)
|
987
|
+
switchport_enable unless switchport
|
988
|
+
if mode_set[/(host|promiscuous)/]
|
989
|
+
config_set('interface', 'switchport_mode_private_vlan_host',
|
990
|
+
name: @name, state: '', mode: IF_SWITCHPORT_MODE[mode_set])
|
991
|
+
else
|
992
|
+
config_set('interface', 'switchport_mode_private_vlan_host',
|
993
|
+
name: @name, state: 'no', mode: IF_SWITCHPORT_MODE[mode_set])
|
994
|
+
end
|
995
|
+
end
|
996
|
+
|
997
|
+
def switchport_mode_private_vlan_host
|
998
|
+
mode = config_get('interface',
|
999
|
+
'switchport_mode_private_vlan_host',
|
1000
|
+
name: @name)
|
1001
|
+
unless mode == default_switchport_mode_private_vlan_host
|
1002
|
+
mode = IF_SWITCHPORT_MODE.key(mode)
|
1003
|
+
end
|
1004
|
+
mode
|
1005
|
+
rescue IndexError
|
1006
|
+
# Assume this is an interface that doesn't support switchport.
|
1007
|
+
# Do not raise exception since the providers will prefetch this property
|
1008
|
+
# regardless of interface type.
|
1009
|
+
# TODO: this should probably be nil instead
|
1010
|
+
return default_switchport_mode_private_vlan_host
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def switchport_mode_private_vlan_host=(mode_set)
|
1014
|
+
fail ArgumentError unless IF_SWITCHPORT_MODE.keys.include? mode_set
|
1015
|
+
Feature.private_vlan_enable
|
1016
|
+
switchport_enable_and_mode_private_vlan_host(mode_set)
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
def default_switchport_mode_private_vlan_host
|
1020
|
+
config_get_default('interface',
|
1021
|
+
'switchport_mode_private_vlan_host')
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
def switchport_mode_private_vlan_host_association
|
1025
|
+
result = config_get('interface',
|
1026
|
+
'switchport_mode_private_vlan_host_association',
|
1027
|
+
name: @name)
|
1028
|
+
unless result == default_switchport_mode_private_vlan_host_association
|
1029
|
+
result = result[0].split(' ')
|
1030
|
+
end
|
1031
|
+
result
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def switchport_mode_private_vlan_host_association=(vlans)
|
1035
|
+
fail TypeError unless vlans.is_a?(Array) || vlans.empty?
|
1036
|
+
switchport_enable unless switchport
|
1037
|
+
Feature.private_vlan_enable
|
1038
|
+
if vlans == default_switchport_mode_private_vlan_host_association
|
1039
|
+
result = config_set('interface',
|
1040
|
+
'switchport_mode_private_vlan_host_association',
|
1041
|
+
name: @name, state: 'no', vlan_pr: '', vlan_sec: '')
|
1042
|
+
|
1043
|
+
else
|
1044
|
+
result = config_set('interface',
|
1045
|
+
'switchport_mode_private_vlan_host_association',
|
1046
|
+
name: @name, state: '',
|
1047
|
+
vlan_pr: vlans[0], vlan_sec: vlans[1])
|
1048
|
+
|
1049
|
+
end
|
1050
|
+
cli_error_check(result)
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def default_switchport_mode_private_vlan_host_association
|
1054
|
+
config_get_default('interface',
|
1055
|
+
'switchport_mode_private_vlan_host_association')
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
# This api is used by private vlan to prepare the input to the setter
|
1059
|
+
# method. The input can be in the following formats for vlans:
|
1060
|
+
# 10-12,14. Prepare_array api is transforming this input into a flat array.
|
1061
|
+
# In the example above the returned array will be 10, 11, 12, 13. Prepare
|
1062
|
+
# array is first splitting the input on ',' and the than expanding the vlan
|
1063
|
+
# range element like 10-12 into a flat array. The final result will
|
1064
|
+
# be a flat array.
|
1065
|
+
# This way we can later used the lib utility to check the delta from
|
1066
|
+
# the input vlan value and the vlan configured to apply the right config.
|
1067
|
+
def prepare_array(is_list)
|
1068
|
+
new_list = []
|
1069
|
+
is_list.each do |item|
|
1070
|
+
if item.include?(',')
|
1071
|
+
new_list.push(item.split(','))
|
1072
|
+
else
|
1073
|
+
new_list.push(item)
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
new_list.flatten!
|
1077
|
+
new_list.sort!
|
1078
|
+
new_list.each { |item| item.gsub!('-', '..') }
|
1079
|
+
is_list_new = []
|
1080
|
+
new_list.each do |elem|
|
1081
|
+
if elem.include?('..')
|
1082
|
+
elema = elem.split('..').map { |d| Integer(d) }
|
1083
|
+
elema.sort!
|
1084
|
+
tr = elema[0]..elema[1]
|
1085
|
+
tr.to_a.each do |item|
|
1086
|
+
is_list_new.push(item.to_s)
|
1087
|
+
end
|
1088
|
+
else
|
1089
|
+
is_list_new.push(elem)
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
is_list_new
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
def configure_private_vlan_host_property(property, should_list_new,
|
1096
|
+
is_list_new, pr_vlan)
|
1097
|
+
delta_hash = Utils.delta_add_remove(should_list_new, is_list_new)
|
1098
|
+
[:add, :remove].each do |action|
|
1099
|
+
delta_hash[action].each do |vlans|
|
1100
|
+
state = (action == :add) ? '' : 'no'
|
1101
|
+
oper = (action == :add) ? 'add' : 'remove'
|
1102
|
+
if property[/(host_promisc|mapping_trunk)/]
|
1103
|
+
|
1104
|
+
result = config_set('interface', PVLAN_PROPERTY[property],
|
1105
|
+
name: @name, state: state,
|
1106
|
+
vlan_pr: pr_vlan, vlans: vlans)
|
1107
|
+
@match_found = true
|
1108
|
+
end
|
1109
|
+
if property[/allow_vlan/]
|
1110
|
+
result = config_set('interface',
|
1111
|
+
PVLAN_PROPERTY[property],
|
1112
|
+
name: @name, state: '',
|
1113
|
+
oper: oper, vlans: vlans)
|
1114
|
+
end
|
1115
|
+
if property[/vlan_mapping/]
|
1116
|
+
result = config_set('interface',
|
1117
|
+
PVLAN_PROPERTY[property],
|
1118
|
+
name: @name, state: state,
|
1119
|
+
vlans: vlans)
|
1120
|
+
end
|
1121
|
+
cli_error_check(result)
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
def configure_private_vlan_trunk_property(property, should_list_new,
|
1127
|
+
is_list, pr_vlan)
|
1128
|
+
case property
|
1129
|
+
when :trunk_assoc
|
1130
|
+
is_list.each do |vlans|
|
1131
|
+
vlans = vlans.split(' ')
|
1132
|
+
if vlans[0].eql? should_list_new[0]
|
1133
|
+
config_set('interface',
|
1134
|
+
'switchport_private_vlan_association_trunk',
|
1135
|
+
name: @name, state: 'no',
|
1136
|
+
vlan_pr: pr_vlan, vlan: vlans[1])
|
1137
|
+
break
|
1138
|
+
else
|
1139
|
+
next
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
result = config_set('interface', PVLAN_PROPERTY[property], name: @name,
|
1143
|
+
state: '', vlan_pr: should_list_new[0],
|
1144
|
+
vlan: should_list_new[1])
|
1145
|
+
when :mapping_trunk
|
1146
|
+
@match_found = false
|
1147
|
+
is_list.each do |vlans|
|
1148
|
+
vlans = vlans.split(' ')
|
1149
|
+
interf_vlan_list_delta(:mapping_trunk, vlans,
|
1150
|
+
should_list_new)
|
1151
|
+
if @match_found
|
1152
|
+
break
|
1153
|
+
else
|
1154
|
+
next
|
1155
|
+
end
|
1156
|
+
end
|
1157
|
+
result = config_set('interface', PVLAN_PROPERTY[property], name: @name,
|
1158
|
+
state: '', vlan_pr: should_list_new[0],
|
1159
|
+
vlans: should_list_new[1])
|
1160
|
+
end
|
1161
|
+
cli_error_check(result)
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
# --------------------------
|
1165
|
+
# interf_vlan_list_delta is a helper function for the private_vlan_mapping
|
1166
|
+
# property. It walks the delta hash and adds/removes each target private
|
1167
|
+
# vlan.
|
1168
|
+
|
1169
|
+
def interf_vlan_list_delta(property, is_list, should_list)
|
1170
|
+
pr_vlan = should_list[0]
|
1171
|
+
if is_list[0].eql? should_list[0]
|
1172
|
+
should_list = should_list[1].split(',')
|
1173
|
+
is_list = is_list[1].split(',')
|
1174
|
+
|
1175
|
+
should_list_new = prepare_array(should_list)
|
1176
|
+
is_list_new = prepare_array(is_list)
|
1177
|
+
configure_private_vlan_host_property(property, should_list_new,
|
1178
|
+
is_list_new, pr_vlan)
|
1179
|
+
else
|
1180
|
+
case property
|
1181
|
+
when :mapping_trunk
|
1182
|
+
return
|
1183
|
+
end
|
1184
|
+
# If primary vlan are different we can simply replacing the all
|
1185
|
+
# config
|
1186
|
+
if should_list == default_switchport_mode_private_vlan_host_promisc
|
1187
|
+
result = config_set('interface',
|
1188
|
+
'switchport_mode_private_vlan_host_promiscous',
|
1189
|
+
name: @name, state: 'no',
|
1190
|
+
vlan_pr: '', vlans: '')
|
1191
|
+
|
1192
|
+
else
|
1193
|
+
result = config_set('interface',
|
1194
|
+
'switchport_mode_private_vlan_host_promiscous',
|
1195
|
+
name: @name, state: '',
|
1196
|
+
vlan_pr: pr_vlan, vlans: should_list[1])
|
1197
|
+
|
1198
|
+
end
|
1199
|
+
cli_error_check(result)
|
1200
|
+
end
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
def switchport_mode_private_vlan_host_promisc
|
1204
|
+
result = config_get('interface',
|
1205
|
+
'switchport_mode_private_vlan_host_promiscous',
|
1206
|
+
name: @name)
|
1207
|
+
unless result == default_switchport_mode_private_vlan_host_promisc
|
1208
|
+
result = result[0].split(' ')
|
1209
|
+
end
|
1210
|
+
result
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
def switchport_mode_private_vlan_host_promisc=(vlans)
|
1214
|
+
fail TypeError unless vlans.is_a?(Array)
|
1215
|
+
fail TypeError unless vlans.empty? || vlans.length == 2
|
1216
|
+
switchport_enable unless switchport
|
1217
|
+
Feature.private_vlan_enable
|
1218
|
+
is_list = switchport_mode_private_vlan_host_promisc
|
1219
|
+
interf_vlan_list_delta(:host_promisc, is_list, vlans)
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
def default_switchport_mode_private_vlan_host_promisc
|
1223
|
+
config_get_default('interface',
|
1224
|
+
'switchport_mode_private_vlan_host_promiscous')
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
def switchport_mode_private_vlan_trunk_promiscuous
|
1228
|
+
config_get('interface',
|
1229
|
+
'switchport_mode_private_vlan_trunk_promiscuous',
|
1230
|
+
name: @name)
|
1231
|
+
rescue IndexError
|
1232
|
+
# Assume this is an interface that doesn't support switchport.
|
1233
|
+
# Do not raise exception since the providers will prefetch this property
|
1234
|
+
# regardless of interface type.
|
1235
|
+
# TODO: this should probably be nil instead
|
1236
|
+
return default_switchport_mode_private_vlan_trunk_promiscuous
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
def switchport_mode_private_vlan_trunk_promiscuous=(state)
|
1240
|
+
Feature.private_vlan_enable
|
1241
|
+
switchport_enable unless switchport
|
1242
|
+
if state == default_switchport_mode_private_vlan_trunk_promiscuous
|
1243
|
+
config_set('interface',
|
1244
|
+
'switchport_mode_private_vlan_trunk_promiscuous',
|
1245
|
+
name: @name, state: 'no')
|
1246
|
+
else
|
1247
|
+
config_set('interface',
|
1248
|
+
'switchport_mode_private_vlan_trunk_promiscuous',
|
1249
|
+
name: @name, state: '')
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
def default_switchport_mode_private_vlan_trunk_promiscuous
|
1254
|
+
config_get_default('interface',
|
1255
|
+
'switchport_mode_private_vlan_trunk_promiscuous')
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
def switchport_mode_private_vlan_trunk_secondary
|
1259
|
+
config_get('interface',
|
1260
|
+
'switchport_mode_private_vlan_trunk_secondary',
|
1261
|
+
name: @name)
|
1262
|
+
rescue IndexError
|
1263
|
+
# Assume this is an interface that doesn't support switchport.
|
1264
|
+
# Do not raise exception since the providers will prefetch this property
|
1265
|
+
# regardless of interface type.
|
1266
|
+
# TODO: this should probably be nil instead
|
1267
|
+
return default_switchport_mode_private_vlan_trunk_secondary
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
def switchport_mode_private_vlan_trunk_secondary=(state)
|
1271
|
+
Feature.private_vlan_enable
|
1272
|
+
switchport_enable unless switchport
|
1273
|
+
if state == default_switchport_mode_private_vlan_trunk_secondary
|
1274
|
+
config_set('interface', 'switchport_mode_private_vlan_trunk_secondary',
|
1275
|
+
name: @name, state: 'no')
|
1276
|
+
else
|
1277
|
+
config_set('interface', 'switchport_mode_private_vlan_trunk_secondary',
|
1278
|
+
name: @name, state: '')
|
1279
|
+
end
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
def default_switchport_mode_private_vlan_trunk_secondary
|
1283
|
+
config_get_default('interface',
|
1284
|
+
'switchport_mode_private_vlan_trunk_secondary')
|
1285
|
+
end
|
1286
|
+
|
1287
|
+
def switchport_private_vlan_trunk_allowed_vlan
|
1288
|
+
result = config_get('interface',
|
1289
|
+
'switchport_private_vlan_trunk_allowed_vlan',
|
1290
|
+
name: @name)
|
1291
|
+
|
1292
|
+
unless result == default_switchport_private_vlan_trunk_allowed_vlan
|
1293
|
+
if result[0].eql? 'none'
|
1294
|
+
result = default_switchport_private_vlan_trunk_allowed_vlan
|
1295
|
+
else
|
1296
|
+
result = result[0].split(',')
|
1297
|
+
end
|
1298
|
+
end
|
1299
|
+
result
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
def switchport_private_vlan_trunk_allowed_vlan=(vlans)
|
1303
|
+
fail TypeError unless vlans.is_a?(Array)
|
1304
|
+
Feature.private_vlan_enable
|
1305
|
+
switchport_enable unless switchport
|
1306
|
+
if vlans == default_switchport_private_vlan_trunk_allowed_vlan
|
1307
|
+
vlans = prepare_array(switchport_private_vlan_trunk_allowed_vlan)
|
1308
|
+
# If there are no vlan presently configured, we can simply return
|
1309
|
+
return if vlans == default_switchport_private_vlan_trunk_allowed_vlan
|
1310
|
+
configure_private_vlan_host_property(:allow_vlan, [],
|
1311
|
+
vlans, '')
|
1312
|
+
else
|
1313
|
+
vlans = prepare_array(vlans)
|
1314
|
+
is_list = prepare_array(switchport_private_vlan_trunk_allowed_vlan)
|
1315
|
+
configure_private_vlan_host_property(:allow_vlan, vlans,
|
1316
|
+
is_list, '')
|
1317
|
+
end
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
def default_switchport_private_vlan_trunk_allowed_vlan
|
1321
|
+
config_get_default('interface',
|
1322
|
+
'switchport_private_vlan_trunk_allowed_vlan')
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
def switchport_private_vlan_trunk_native_vlan
|
1326
|
+
config_get('interface',
|
1327
|
+
'switchport_private_vlan_trunk_native_vlan',
|
1328
|
+
name: @name)
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
def switchport_private_vlan_trunk_native_vlan=(vlan)
|
1332
|
+
Feature.private_vlan_enable
|
1333
|
+
switchport_enable unless switchport
|
1334
|
+
if vlan == default_switchport_private_vlan_trunk_native_vlan
|
1335
|
+
config_set('interface',
|
1336
|
+
'switchport_private_vlan_trunk_native_vlan',
|
1337
|
+
name: @name, state: 'no', vlan: '')
|
1338
|
+
|
1339
|
+
else
|
1340
|
+
config_set('interface',
|
1341
|
+
'switchport_private_vlan_trunk_native_vlan',
|
1342
|
+
name: @name, state: '', vlan: vlan)
|
1343
|
+
end
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
def default_switchport_private_vlan_trunk_native_vlan
|
1347
|
+
config_get_default('interface',
|
1348
|
+
'switchport_private_vlan_trunk_native_vlan')
|
1349
|
+
end
|
1350
|
+
|
1351
|
+
def switchport_private_vlan_association_trunk
|
1352
|
+
config_get('interface',
|
1353
|
+
'switchport_private_vlan_association_trunk',
|
1354
|
+
name: @name)
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
def switchport_private_vlan_association_trunk=(vlans)
|
1358
|
+
fail TypeError unless vlans.is_a?(Array) || vlans.empty?
|
1359
|
+
Feature.private_vlan_enable
|
1360
|
+
switchport_enable unless switchport
|
1361
|
+
if vlans == default_switchport_private_vlan_association_trunk
|
1362
|
+
config_set('interface', 'switchport_private_vlan_association_trunk',
|
1363
|
+
name: @name, state: 'no',
|
1364
|
+
vlan_pr: '', vlan: '')
|
1365
|
+
else
|
1366
|
+
is_list = switchport_private_vlan_association_trunk
|
1367
|
+
configure_private_vlan_trunk_property(:trunk_assoc, vlans,
|
1368
|
+
is_list, vlans[0])
|
1369
|
+
end
|
1370
|
+
end
|
1371
|
+
|
1372
|
+
def default_switchport_private_vlan_association_trunk
|
1373
|
+
config_get_default('interface',
|
1374
|
+
'switchport_private_vlan_association_trunk')
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
def switchport_private_vlan_mapping_trunk
|
1378
|
+
config_get('interface',
|
1379
|
+
'switchport_private_vlan_mapping_trunk',
|
1380
|
+
name: @name)
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
def switchport_private_vlan_mapping_trunk=(vlans)
|
1384
|
+
fail TypeError unless vlans.is_a?(Array) || vlans.empty?
|
1385
|
+
Feature.private_vlan_enable
|
1386
|
+
switchport_enable unless switchport
|
1387
|
+
if vlans == default_switchport_private_vlan_mapping_trunk
|
1388
|
+
config_set('interface', 'switchport_private_vlan_mapping_trunk',
|
1389
|
+
name: @name, state: 'no',
|
1390
|
+
vlan_pr: '', vlans: '')
|
1391
|
+
else
|
1392
|
+
is_list = switchport_private_vlan_mapping_trunk
|
1393
|
+
configure_private_vlan_trunk_property(:mapping_trunk, vlans,
|
1394
|
+
is_list, vlans[0])
|
1395
|
+
end
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
def default_switchport_private_vlan_mapping_trunk
|
1399
|
+
config_get_default('interface',
|
1400
|
+
'switchport_private_vlan_mapping_trunk')
|
1401
|
+
end
|
1402
|
+
|
1403
|
+
def private_vlan_mapping
|
1404
|
+
match = config_get('interface',
|
1405
|
+
'private_vlan_mapping',
|
1406
|
+
name: @name)
|
1407
|
+
match[0].delete!(' ') unless match == default_private_vlan_mapping
|
1408
|
+
match
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
def private_vlan_mapping=(vlans)
|
1412
|
+
fail TypeError unless vlans.is_a?(Array) || vlans.empty?
|
1413
|
+
Feature.private_vlan_enable
|
1414
|
+
feature_vlan_set(true)
|
1415
|
+
if vlans == default_private_vlan_mapping
|
1416
|
+
config_set('interface', 'private_vlan_mapping',
|
1417
|
+
name: @name, state: 'no', vlans: '')
|
1418
|
+
else
|
1419
|
+
is_list = private_vlan_mapping
|
1420
|
+
new_is_list = prepare_array(is_list)
|
1421
|
+
new_vlans = prepare_array(vlans)
|
1422
|
+
configure_private_vlan_host_property(:vlan_mapping, new_vlans,
|
1423
|
+
new_is_list, '')
|
1424
|
+
end
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
def default_private_vlan_mapping
|
1428
|
+
config_get_default('interface',
|
1429
|
+
'private_vlan_mapping')
|
679
1430
|
end
|
680
1431
|
|
681
1432
|
# vlan_mapping & vlan_mapping_enable
|
@@ -698,13 +1449,13 @@ module Cisco
|
|
698
1449
|
end
|
699
1450
|
|
700
1451
|
def vlan_mapping
|
701
|
-
match = config_get('interface', 'vlan_mapping', @name)
|
1452
|
+
match = config_get('interface', 'vlan_mapping', name: @name)
|
702
1453
|
match.each(&:compact!) unless match.nil?
|
703
1454
|
match
|
704
1455
|
end
|
705
1456
|
|
706
1457
|
def vlan_mapping=(should_list)
|
707
|
-
|
1458
|
+
Feature.vni_enable
|
708
1459
|
|
709
1460
|
# Process a hash of vlan_mapping cmds from delta_add_remove().
|
710
1461
|
# The vlan_mapping cli does not allow commands to be updated, they must
|
@@ -714,16 +1465,14 @@ module Cisco
|
|
714
1465
|
return if delta_hash.values.flatten.empty?
|
715
1466
|
# Process :remove first to ensure "update" commands will not fail.
|
716
1467
|
[:remove, :add].each do |action|
|
717
|
-
|
718
|
-
|
1468
|
+
Cisco::Logger.debug("vlan_mapping delta #{@get_args}\n"\
|
1469
|
+
"#{action}: #{delta_hash[action]}")
|
719
1470
|
delta_hash[action].each do |original, translated|
|
720
1471
|
state = (action == :add) ? '' : 'no'
|
721
|
-
config_set('interface', 'vlan_mapping', @name,
|
722
|
-
state, original, translated)
|
1472
|
+
config_set('interface', 'vlan_mapping', name: @name,
|
1473
|
+
state: state, original: original, translated: translated)
|
723
1474
|
end
|
724
1475
|
end
|
725
|
-
rescue Cisco::CliError => e
|
726
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
727
1476
|
end
|
728
1477
|
|
729
1478
|
# cli: switchport vlan mapping enable
|
@@ -732,12 +1481,12 @@ module Cisco
|
|
732
1481
|
end
|
733
1482
|
|
734
1483
|
def vlan_mapping_enable
|
735
|
-
config_get('interface', 'vlan_mapping_enable', @name)
|
1484
|
+
config_get('interface', 'vlan_mapping_enable', name: @name)
|
736
1485
|
end
|
737
1486
|
|
738
1487
|
def vlan_mapping_enable=(state)
|
739
|
-
config_set('interface', 'vlan_mapping_enable',
|
740
|
-
state ? '' : 'no')
|
1488
|
+
config_set('interface', 'vlan_mapping_enable',
|
1489
|
+
name: @name, state: state ? '' : 'no')
|
741
1490
|
end
|
742
1491
|
|
743
1492
|
def default_switchport_trunk_native_vlan
|
@@ -782,16 +1531,15 @@ module Cisco
|
|
782
1531
|
end
|
783
1532
|
|
784
1533
|
def switchport_vtp
|
785
|
-
return
|
786
|
-
config_get('interface', 'vtp', @name)
|
1534
|
+
return nil unless switchport_vtp_mode_capable?
|
1535
|
+
config_get('interface', 'vtp', name: @name)
|
787
1536
|
end
|
788
1537
|
|
789
1538
|
def switchport_vtp=(vtp_set)
|
1539
|
+
# TODO: throw UnsupportedError instead of returning false?
|
790
1540
|
return false unless switchport_vtp_mode_capable?
|
791
1541
|
no_cmd = (vtp_set) ? '' : 'no'
|
792
|
-
config_set('interface', 'vtp', @name, no_cmd)
|
793
|
-
rescue Cisco::CliError => e
|
794
|
-
raise "[#{@name}] '#{e.command}' : #{e.clierror}"
|
1542
|
+
config_set('interface', 'vtp', name: @name, state: no_cmd)
|
795
1543
|
end
|
796
1544
|
|
797
1545
|
def svi_cmd_allowed?(cmd)
|
@@ -802,13 +1550,14 @@ module Cisco
|
|
802
1550
|
# svi_autostate is exclusive to svi interfaces
|
803
1551
|
def svi_autostate
|
804
1552
|
return nil unless @name[/^vlan/i]
|
805
|
-
config_get('interface', 'svi_autostate', @name)
|
1553
|
+
config_get('interface', 'svi_autostate', name: @name)
|
806
1554
|
end
|
807
1555
|
|
808
1556
|
def svi_autostate=(val)
|
809
|
-
|
1557
|
+
check_switchport(:disabled)
|
810
1558
|
svi_cmd_allowed?('autostate')
|
811
|
-
config_set('interface', 'svi_autostate',
|
1559
|
+
config_set('interface', 'svi_autostate',
|
1560
|
+
name: @name, state: val ? '' : 'no')
|
812
1561
|
end
|
813
1562
|
|
814
1563
|
def default_svi_autostate
|
@@ -821,19 +1570,20 @@ module Cisco
|
|
821
1570
|
|
822
1571
|
def feature_vlan_set(val)
|
823
1572
|
return if feature_vlan? == val
|
824
|
-
config_set('interface', 'feature_vlan', val ? '' : 'no')
|
1573
|
+
config_set('interface', 'feature_vlan', state: val ? '' : 'no')
|
825
1574
|
end
|
826
1575
|
|
827
1576
|
# svi_management is exclusive to svi interfaces
|
828
1577
|
def svi_management
|
829
1578
|
return nil unless @name[/^vlan/i]
|
830
|
-
config_get('interface', 'svi_management', @name)
|
1579
|
+
config_get('interface', 'svi_management', name: @name)
|
831
1580
|
end
|
832
1581
|
|
833
1582
|
def svi_management=(val)
|
834
|
-
|
1583
|
+
check_switchport(:disabled)
|
835
1584
|
svi_cmd_allowed?('management')
|
836
|
-
config_set('interface', 'svi_management',
|
1585
|
+
config_set('interface', 'svi_management',
|
1586
|
+
name: @name, state: val ? '' : 'no')
|
837
1587
|
end
|
838
1588
|
|
839
1589
|
def default_svi_management
|
@@ -841,6 +1591,7 @@ module Cisco
|
|
841
1591
|
end
|
842
1592
|
|
843
1593
|
def default_switchport_vtp
|
1594
|
+
return nil unless switchport_vtp_mode_capable?
|
844
1595
|
config_get_default('interface', 'vtp')
|
845
1596
|
end
|
846
1597
|
|
@@ -848,22 +1599,36 @@ module Cisco
|
|
848
1599
|
config_get('vtp', 'feature')
|
849
1600
|
end
|
850
1601
|
|
851
|
-
def
|
852
|
-
|
853
|
-
|
1602
|
+
def switchport_status?(status)
|
1603
|
+
case status
|
1604
|
+
when :disabled
|
1605
|
+
return true if switchport_mode == status || switchport_mode.nil?
|
1606
|
+
when :access, :trunk
|
1607
|
+
return switchport_mode == status
|
1608
|
+
when Array
|
1609
|
+
return status.include?(switchport_mode)
|
1610
|
+
else
|
1611
|
+
return false
|
1612
|
+
end
|
1613
|
+
end
|
1614
|
+
|
1615
|
+
def check_switchport(status)
|
1616
|
+
return if switchport_status?(status)
|
1617
|
+
fail("#{caller[0][/`.*'/][1..-2]} cannot be set unless " \
|
1618
|
+
"switchport mode is #{status}")
|
854
1619
|
end
|
855
1620
|
|
856
1621
|
def vpc_id
|
857
|
-
config_get('interface', 'vpc_id', @name)
|
1622
|
+
config_get('interface', 'vpc_id', name: @name)
|
858
1623
|
end
|
859
1624
|
|
860
1625
|
def vpc_id=(num)
|
861
1626
|
if num
|
862
|
-
config_set('interface', 'vpc_id', @name, '', num)
|
1627
|
+
config_set('interface', 'vpc_id', name: @name, state: '', id: num)
|
863
1628
|
else
|
864
1629
|
# 'no vpc' doesn't work for phy ports, so do a get
|
865
1630
|
num = vpc_id
|
866
|
-
config_set('interface', 'vpc_id', @name, 'no', num)
|
1631
|
+
config_set('interface', 'vpc_id', name: @name, state: 'no', id: num)
|
867
1632
|
end
|
868
1633
|
end
|
869
1634
|
|
@@ -872,12 +1637,12 @@ module Cisco
|
|
872
1637
|
end
|
873
1638
|
|
874
1639
|
def vpc_peer_link
|
875
|
-
config_get('interface', 'vpc_peer_link', @name)
|
1640
|
+
config_get('interface', 'vpc_peer_link', name: @name)
|
876
1641
|
end
|
877
1642
|
|
878
1643
|
def vpc_peer_link=(state)
|
879
1644
|
no_cmd = (state ? '' : 'no')
|
880
|
-
config_set('interface', 'vpc_peer_link', @name, no_cmd)
|
1645
|
+
config_set('interface', 'vpc_peer_link', name: @name, state: no_cmd)
|
881
1646
|
end
|
882
1647
|
|
883
1648
|
def default_vpc_peer_link
|
@@ -885,22 +1650,48 @@ module Cisco
|
|
885
1650
|
end
|
886
1651
|
|
887
1652
|
def vrf
|
888
|
-
config_get('interface', 'vrf', @name)
|
889
|
-
end
|
890
|
-
|
891
|
-
def vrf=(
|
892
|
-
fail TypeError unless
|
893
|
-
if vrf
|
894
|
-
|
1653
|
+
config_get('interface', 'vrf', name: @name)
|
1654
|
+
end
|
1655
|
+
|
1656
|
+
def vrf=(v)
|
1657
|
+
fail TypeError unless v.is_a?(String)
|
1658
|
+
return if v == vrf
|
1659
|
+
# Changing the VRF can result in loss of IP address, so cache it
|
1660
|
+
addr_1 = ipv4_address
|
1661
|
+
mask_1 = ipv4_netmask_length
|
1662
|
+
addr_2 = ipv4_address_secondary
|
1663
|
+
mask_2 = ipv4_netmask_length_secondary
|
1664
|
+
# XR actually blocks you from changing the VRF if IP addr is present
|
1665
|
+
unless platform == :nexus
|
1666
|
+
ipv4_addr_mask_set(nil, nil, false) unless addr_1.nil?
|
1667
|
+
ipv4_addr_mask_set(nil, nil, true) unless addr_2.nil?
|
1668
|
+
end
|
1669
|
+
if v.empty?
|
1670
|
+
config_set('interface', 'vrf', name: @name, state: 'no', vrf: '')
|
895
1671
|
else
|
896
|
-
config_set('interface', 'vrf', @name, '', vrf)
|
1672
|
+
config_set('interface', 'vrf', name: @name, state: '', vrf: v)
|
897
1673
|
end
|
898
|
-
|
899
|
-
|
1674
|
+
ipv4_addr_mask_set(addr_1, mask_1, false) unless addr_1.nil?
|
1675
|
+
ipv4_addr_mask_set(addr_2, mask_2, true) unless addr_2.nil?
|
900
1676
|
end
|
901
1677
|
|
902
1678
|
def default_vrf
|
903
1679
|
config_get_default('interface', 'vrf')
|
904
1680
|
end
|
1681
|
+
|
1682
|
+
def set_range_based_params(list, param_name)
|
1683
|
+
list.each do |range, property_value|
|
1684
|
+
# if a particular range is set to default, use 'no' cmd
|
1685
|
+
if property_value == 'default'
|
1686
|
+
config_set('interface', param_name,
|
1687
|
+
name: @name, state: 'no',
|
1688
|
+
range: range, val: '')
|
1689
|
+
else
|
1690
|
+
config_set('interface', param_name,
|
1691
|
+
name: @name, state: '',
|
1692
|
+
range: range, val: property_value)
|
1693
|
+
end
|
1694
|
+
end
|
1695
|
+
end
|
905
1696
|
end # Class
|
906
1697
|
end # Module
|