vxlan 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/README-zh.md +8 -0
- data/README.md +8 -0
- data/docs/architecture-zh.md +1 -1
- data/lib/vxlan/bgp_neighbors.rb +4 -1
- data/lib/vxlan/cisco_nxos/configuration.rb +3 -77
- data/lib/vxlan/cisco_nxos/configuration_state.rb +87 -0
- data/lib/vxlan/cisco_nxos/document.rb +1 -1
- data/lib/vxlan/cisco_nxos/evpn_l2route.rb +32 -23
- data/lib/vxlan/cisco_nxos/parser.rb +9 -9
- data/lib/vxlan/cisco_nxos/parsers/show_bgp_l2vpn_evpn_summary.rb +7 -7
- data/lib/vxlan/cisco_nxos/parsers/show_cdp_neighbors_detail.rb +7 -7
- data/lib/vxlan/cisco_nxos/parsers/show_interface_brief.rb +8 -8
- data/lib/vxlan/cisco_nxos/parsers/show_ip_ospf_neighbors.rb +4 -4
- data/lib/vxlan/cisco_nxos/parsers/show_mac_address_table.rb +4 -4
- data/lib/vxlan/cisco_nxos/parsers/show_nve_peers.rb +4 -4
- data/lib/vxlan/cisco_nxos/parsers/show_nve_vni.rb +3 -3
- data/lib/vxlan/cisco_nxos/parsers/show_port_channel_summary.rb +7 -7
- data/lib/vxlan/cisco_nxos/parsers/show_running_config.rb +74 -37
- data/lib/vxlan/cisco_nxos/parsers/show_vpc_brief.rb +10 -10
- data/lib/vxlan/cisco_nxos/syntax/interfaces.rb +3 -3
- data/lib/vxlan/cisco_nxos/syntax/policies.rb +35 -13
- data/lib/vxlan/cisco_nxos/syntax/routing.rb +45 -6
- data/lib/vxlan/cisco_nxos/terminal.rb +3 -1
- data/lib/vxlan/collector.rb +4 -4
- data/lib/vxlan/configuration_review.rb +13 -2
- data/lib/vxlan/prefix_list_references.rb +3 -3
- data/lib/vxlan/version.rb +1 -1
- metadata +2 -1
|
@@ -5,18 +5,28 @@ module Vxlan
|
|
|
5
5
|
module Syntax
|
|
6
6
|
# 路由作用域保留邻居、模板、VRF 与地址族的归属。
|
|
7
7
|
module Routing
|
|
8
|
+
BGP_LEAF = /\A(?:no )?(?:remote-as|inherit peer|update-source|route-map|next-hop-self|route-reflector-client|advertise-pip|advertise l2vpn evpn|send-community|retain route-target)\b/
|
|
9
|
+
private_constant :BGP_LEAF
|
|
10
|
+
|
|
8
11
|
private
|
|
9
12
|
|
|
10
13
|
# 解析支持的路由作用域及协议关系。
|
|
11
|
-
def routing(block, protocol, context = :process)
|
|
14
|
+
def routing(block, protocol, context = :process, family: nil, parent: nil)
|
|
12
15
|
values = { vrfs: {}, neighbors: {}, templates: {}, address_families: {}, redistribute: [] }
|
|
13
16
|
analyze_children(block) do |child|
|
|
17
|
+
next issue(child) if protocol != :bgp && BGP_LEAF.match?(child.text)
|
|
18
|
+
next issue(child) unless routing_leaf?(child.text, protocol, context, family, parent)
|
|
19
|
+
|
|
14
20
|
case child.text
|
|
15
21
|
when /\Avrf (\S+)\z/ then routing_scope(values, :vrfs, $1, child, protocol, context)
|
|
16
22
|
when /\Atemplate peer (\S+)\z/ then routing_scope(values, :templates, $1, child, protocol, context)
|
|
17
23
|
when /\Aneighbor (\S+)\z/ then routing_scope(values, :neighbors, $1, child, protocol, context)
|
|
18
24
|
when /\Aaddress-family (.+)\z/ then routing_scope(values, :address_families, $1, child, protocol, context)
|
|
19
|
-
when /\Arouter-id (\S+)\z/
|
|
25
|
+
when /\Arouter-id (\S+)\z/
|
|
26
|
+
router_id = ip_address($1)
|
|
27
|
+
raise ArgumentError unless IPAddr.new(router_id).ipv4?
|
|
28
|
+
|
|
29
|
+
assign(values, :router_id, router_id, child)
|
|
20
30
|
when /\Aremote-as (\S+)\z/
|
|
21
31
|
value = $1
|
|
22
32
|
integer(value, 1..4_294_967_295) unless %w[internal external].include?(value)
|
|
@@ -42,9 +52,12 @@ module Vxlan
|
|
|
42
52
|
assign(values, :extended_community, enabled, child) if kind
|
|
43
53
|
when /\Anetwork (\S+)(?: route-map (\S+))?\z/
|
|
44
54
|
subnet, route_map = $1, $2
|
|
45
|
-
|
|
55
|
+
unless protocol == :bgp && context == :address_families && %i[process vrfs].include?(parent) &&
|
|
56
|
+
/\Aipv[46] (?:unicast|multicast)\z/.match?(family)
|
|
57
|
+
next issue(child)
|
|
58
|
+
end
|
|
46
59
|
|
|
47
|
-
(values[:networks] ||= []) << { prefix: network_prefix(subnet), route_map: route_map }.compact
|
|
60
|
+
(values[:networks] ||= []) << { prefix: network_prefix(subnet, family: family.split.first), route_map: route_map }.compact
|
|
48
61
|
when /\Aredistribute (\S+)(?: (?!route-map\b)(\S+))?(?: route-map (\S+))?\z/
|
|
49
62
|
values[:redistribute] << { protocol: $1, process: $2, route_map: $3 }.compact
|
|
50
63
|
when /\Aretain route-target (all|route-map \S+)\z/ then assign(values, :retain_route_target, $1, child)
|
|
@@ -56,18 +69,44 @@ module Vxlan
|
|
|
56
69
|
values
|
|
57
70
|
end
|
|
58
71
|
|
|
72
|
+
# 已建模叶子必须位于其使用方作用域,不能只因文字可解析就接受事实。
|
|
73
|
+
def routing_leaf?(text, protocol, context, family, parent)
|
|
74
|
+
process_family = context == :address_families && %i[process vrfs].include?(parent)
|
|
75
|
+
case text
|
|
76
|
+
when /\A(?:remote-as|inherit peer|update-source)\b/
|
|
77
|
+
protocol == :bgp && %i[neighbors templates].include?(context)
|
|
78
|
+
when /\Aroute-map\b/
|
|
79
|
+
protocol == :bgp && context == :address_families && %i[neighbors templates].include?(parent)
|
|
80
|
+
when /\Aredistribute\b/
|
|
81
|
+
if protocol == :ospf
|
|
82
|
+
%i[process vrfs].include?(context)
|
|
83
|
+
else
|
|
84
|
+
process_family && /\Aipv[46] (?:unicast|multicast)\z/.match?(family)
|
|
85
|
+
end
|
|
86
|
+
when /\Aretain route-target\b/
|
|
87
|
+
protocol == :bgp && process_family && family == "l2vpn evpn"
|
|
88
|
+
when /\Arouter-id\b/
|
|
89
|
+
%i[process vrfs].include?(context)
|
|
90
|
+
else true
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
59
94
|
# 只进入当前事实模型可表达的子作用域,阻止任意递归及跨协议误归属。
|
|
60
95
|
def routing_scope(values, kind, name, block, protocol, context)
|
|
61
96
|
supported = case kind
|
|
62
97
|
when :vrfs then context == :process
|
|
63
98
|
when :templates then protocol == :bgp && context == :process
|
|
64
99
|
when :neighbors then protocol == :bgp && %i[process vrfs].include?(context)
|
|
65
|
-
when :address_families
|
|
100
|
+
when :address_families
|
|
101
|
+
protocol == :bgp && %i[process vrfs neighbors templates].include?(context) &&
|
|
102
|
+
/\A(?:ipv[46] (?:unicast|multicast)|vpnv[46] unicast|l2vpn evpn)\z/.match?(name)
|
|
66
103
|
end
|
|
67
104
|
return issue(block) unless supported
|
|
68
105
|
|
|
69
106
|
conflicts_before = @configuration_conflict_count
|
|
70
|
-
|
|
107
|
+
store_unique_fact(values[kind], name, block, path: @source_path + [ kind, name ]) do
|
|
108
|
+
routing(block, protocol, kind, family: kind == :address_families ? name : nil, parent: context)
|
|
109
|
+
end
|
|
71
110
|
# 邻居及模板的子地址族冲突也使继承身份失效;保留同进程其他邻居。
|
|
72
111
|
if protocol == :bgp && %i[neighbors templates].include?(kind) && @configuration_conflict_count > conflicts_before
|
|
73
112
|
exclude_conflicted_scope(values[kind], name, block)
|
|
@@ -8,7 +8,9 @@ module Vxlan
|
|
|
8
8
|
private_constant :INVALID
|
|
9
9
|
|
|
10
10
|
# 检查原始正文,避免 strip 或字段解析先吞掉控制字符。
|
|
11
|
-
def self.invalid_output?(text
|
|
11
|
+
def self.invalid_output?(text, allow_cr_newlines: false)
|
|
12
|
+
INVALID.match?(text) || (!allow_cr_newlines && /\r(?!\n)/.match?(text))
|
|
13
|
+
end
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
end
|
data/lib/vxlan/collector.rb
CHANGED
|
@@ -34,7 +34,7 @@ module Vxlan
|
|
|
34
34
|
begin
|
|
35
35
|
connector.open do |session|
|
|
36
36
|
reader = CtxDriver::Reader.new(session: session, clock: @clock)
|
|
37
|
-
if (code =
|
|
37
|
+
if (code = prepare_terminal(reader))
|
|
38
38
|
dimensions.each { |name| observations[name] = failure(name, code) }
|
|
39
39
|
observations[:collection] = failure(:collection, code)
|
|
40
40
|
next
|
|
@@ -45,7 +45,7 @@ module Vxlan
|
|
|
45
45
|
observations[name] = Observation.new(name: name, status: :complete, completed_at: @clock.call,
|
|
46
46
|
issues: [ { code: :vpc_not_configured } ])
|
|
47
47
|
else
|
|
48
|
-
observations[name] =
|
|
48
|
+
observations[name] = collect_observation(reader, name, config, profile)
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
session_finished = true
|
|
@@ -72,7 +72,7 @@ module Vxlan
|
|
|
72
72
|
private
|
|
73
73
|
|
|
74
74
|
# 采集设备回显前,禁用分页并归一化终端宽度。
|
|
75
|
-
def
|
|
75
|
+
def prepare_terminal(reader)
|
|
76
76
|
PREPARATION_COMMANDS.each do |command|
|
|
77
77
|
capture = reader.read(command)
|
|
78
78
|
return capture.failure.fetch(:code) unless capture.success?
|
|
@@ -81,7 +81,7 @@ module Vxlan
|
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
# 解析失败限定在单条查询内;Reader 负责传输与回执校验。
|
|
84
|
-
def
|
|
84
|
+
def collect_observation(reader, name, configuration, profile)
|
|
85
85
|
command = profile.command(name)
|
|
86
86
|
capture = reader.read(command)
|
|
87
87
|
metadata = { started_at: capture.started_at, completed_at: capture.completed_at, evidence: capture.evidence }
|
|
@@ -15,6 +15,7 @@ module Vxlan
|
|
|
15
15
|
|
|
16
16
|
nve_members_by_vni = @configuration.fetch(:nve).fetch(:members, {})
|
|
17
17
|
vlan_mappings_by_vni = @configuration.fetch(:vlan_vnis).group_by { |_vlan, vni| vni }
|
|
18
|
+
vrf_vnis = @configuration.fetch(:vrfs).values.filter_map { |settings| settings[:vni] }.to_set
|
|
18
19
|
evpn_vnis = @configuration.fetch(:evpn)
|
|
19
20
|
findings = []
|
|
20
21
|
vlan_mappings_by_vni.each do |vni, entries|
|
|
@@ -23,14 +24,24 @@ module Vxlan
|
|
|
23
24
|
findings << { code: :vlan_vni_without_nve, vni: vni, vlan_ids: entries.map(&:first).sort }
|
|
24
25
|
end
|
|
25
26
|
nve_members_by_vni.each do |vni, settings|
|
|
26
|
-
|
|
27
|
+
if settings[:associate_vrf]
|
|
28
|
+
findings << { code: :nve_l3_without_vrf, vni: vni } unless vrf_vnis.include?(vni)
|
|
29
|
+
next
|
|
30
|
+
end
|
|
27
31
|
|
|
28
32
|
findings << { code: :nve_l2_without_vlan, vni: vni } unless vlan_mappings_by_vni.key?(vni)
|
|
29
33
|
if @configuration[:nv_overlay_evpn] && !evpn_vnis.key?(vni)
|
|
30
34
|
findings << { code: :nve_l2_without_evpn, vni: vni }
|
|
31
35
|
end
|
|
32
36
|
end
|
|
33
|
-
evpn_vnis.
|
|
37
|
+
evpn_vnis.each do |vni, settings|
|
|
38
|
+
member = nve_members_by_vni[vni]
|
|
39
|
+
if !member
|
|
40
|
+
findings << { code: :evpn_vni_without_nve, vni: vni }
|
|
41
|
+
elsif (settings[:type] == "l3") != member[:associate_vrf]
|
|
42
|
+
findings << { code: :vni_layer_conflict, vni: vni, evpn_type: settings[:type] }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
34
45
|
@configuration.fetch(:vrfs).each do |name, settings|
|
|
35
46
|
next unless settings[:vni]
|
|
36
47
|
member = nve_members_by_vni[settings[:vni]]
|
|
@@ -14,7 +14,7 @@ module Vxlan
|
|
|
14
14
|
def call(address_family: "ipv4")
|
|
15
15
|
raise ArgumentError, "Unsupported address family" unless %w[ipv4 ipv6].include?(address_family)
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
consumers_by_route_map = route_map_consumers.transform_values(&:uniq)
|
|
18
18
|
references = @configuration.fetch(:route_maps).each_with_object({}) do |(name, entries), result|
|
|
19
19
|
entries.sort_by { |entry| entry.fetch(:sequence) }.each do |entry|
|
|
20
20
|
matches = entry.fetch(:prefix_list_matches) do
|
|
@@ -22,7 +22,7 @@ module Vxlan
|
|
|
22
22
|
end
|
|
23
23
|
matches.select { |match| match[:address_family] == address_family }.each do |match|
|
|
24
24
|
route_map_reference = { type: "route_map", name: name, sequence: entry.fetch(:sequence), action: entry.fetch(:action),
|
|
25
|
-
bindings:
|
|
25
|
+
bindings: consumers_by_route_map.fetch(name, []).dup }
|
|
26
26
|
route_map_reference[:selector] = match[:selector] unless match[:selector] == "address"
|
|
27
27
|
match.fetch(:names).uniq.each do |prefix_list|
|
|
28
28
|
(result[prefix_list] ||= []) << route_map_reference
|
|
@@ -37,7 +37,7 @@ module Vxlan
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
39
|
# 关联关系保留协议、VRF、地址族及对等体,避免共享策略被混用。
|
|
40
|
-
def
|
|
40
|
+
def route_map_consumers
|
|
41
41
|
result = Hash.new { |hash, key| hash[key] = [] }
|
|
42
42
|
bgp = @configuration.fetch(:bgp)
|
|
43
43
|
{ "default" => bgp }.merge(bgp.fetch(:vrfs, {})).each do |vrf, settings|
|
data/lib/vxlan/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vxlan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gatework contributors
|
|
@@ -81,6 +81,7 @@ files:
|
|
|
81
81
|
- lib/vxlan.rb
|
|
82
82
|
- lib/vxlan/bgp_neighbors.rb
|
|
83
83
|
- lib/vxlan/cisco_nxos/configuration.rb
|
|
84
|
+
- lib/vxlan/cisco_nxos/configuration_state.rb
|
|
84
85
|
- lib/vxlan/cisco_nxos/document.rb
|
|
85
86
|
- lib/vxlan/cisco_nxos/evpn_l2route.rb
|
|
86
87
|
- lib/vxlan/cisco_nxos/parser.rb
|