Skip to content

Commit 7f39f08

Browse files
committed
misc/ix_tun.rb: generate tunnel destination config
1 parent b90cd4a commit 7f39f08

1 file changed

Lines changed: 82 additions & 61 deletions

File tree

misc/ix_tun.rb

Lines changed: 82 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,98 @@
1+
2+
# Generate NEC IX commnads to configure venue tunnels
3+
#
4+
# Interfaces:
5+
# "Tunnel#{pop_num}.0" etherip-ipsec to pop (not in scope of this script)
6+
# "Tunnel1#{peer_tun_num}0.0" etherip-ipsec to venue
7+
# "Tunnel1#{peer_tun_num}1.0" etherip to venue
8+
19
require 'ipaddr'
2-
# Usage: ix_tun.rb hnd br-01
310

4-
IFACES = %w(bvi0 bvi10 bvi1 bvi11 tun100 tun110 tun101 tun111)
11+
is_full = ARGV.delete('--full')
512

6-
ASNS = {
7-
hnd: 65001,
8-
itm: 65002,
9-
venue: 65010,
13+
peer_address_chars = ('a'..'f').to_a + ('0'..'9').to_a
14+
peer_addresses = ARGV.map.with_index { |arg,i|
15+
a = IPAddr.new(arg)
16+
b = IPAddr.new(a.cidr)
17+
if a == b
18+
b | IPAddr.new("::dddd:#{peer_address_chars.fetch(i)*4}:0:1")
19+
else
20+
a
21+
end
1022
}
1123

12-
host_lines = File.read(File.join(__dir__, '..', 'hosts.txt'))
1324

14-
HostInfo = Struct.new(:dc, :network, :cidr, :ip, :name, :iface, :mac, :primary)
15-
hosts = host_lines.lines.
16-
map { |l| HostInfo.new(*l.chomp.split(?\t, 7).map(&:strip), false) }.
17-
reject { |_| _.ip.nil? || _.ip.empty? }.
18-
group_by { |_| [_.dc, _.name, _.ip.include?(?:)] }.
19-
map { |k, ips| ips[0].primary = true; [k, ips] }.
20-
to_h
25+
SiteTun = Data.define(:num, :site, :nexthop, :interface)
2126

27+
SITE_TUNS = [
28+
SiteTun.new(1, 'hnd', 'fe80::208:e3ff:feff:fd90%GigaEthernet0.1', 'GigaEthernet0.1'),
29+
SiteTun.new(2, 'nrt', 'fe80::a%GigaEthernet0.0', 'GigaEthernet0.0'),
30+
SiteTun.new(3, 'itm', 'fe80::a%GigaEthernet0.0', 'GigaEthernet0.0'),
31+
]
2232

23-
target = ARGV[0,2]
2433

25-
BgpPeer = Struct.new(:ip, :asn, :desc, :mapin, :mapout, :default, keyword_init: true)
26-
bgp_peers = []
27-
ospf3_ifaces = []
28-
IFACES.each do |iface|
29-
v4 = (hosts[[*target, false]] || []).find { |is| is.iface == iface }
30-
v6 = (hosts[[*target, true]] || []).find { |is| is.iface == iface }
31-
canonical = iface.sub(/bvi/,'BVI').sub(/tun(\d+)/, 'Tunnel\1.0')
32-
puts "interface #{canonical}"
33-
puts " ip address #{v4.ip}/30"
34-
puts " ipv6 enable"
35-
puts " ipv6 address #{v6.ip}/124"
36-
puts " ipv6 ospf cost #{iface.start_with?('tun') ? 400 : 200}"
37-
puts " ipv6 ospf hello-interval 6"
38-
puts " ipv6 ospf dead-interval 30"
39-
puts "!"
34+
negates = []
35+
SITE_TUNS.each do |site_tun|
36+
puts "!!!!!!!!! #{site_tun.site} !!!!!!!!!"
37+
negates << "!!!!!!!!! #{site_tun.site} !!!!!!!!!"
4038

41-
ospf3_ifaces << [canonical, v6] if v6
39+
peer_addresses.each do |peer_address|
40+
route = IPAddr.new(peer_address.cidr)
41+
puts "ipv6 route #{route}/#{route.prefix} #{site_tun.nexthop}"
42+
negates << "no ipv6 route #{route}/#{route.prefix} #{site_tun.nexthop}"
43+
end
44+
puts
45+
peer_addresses.each_with_index do |peer_address, idx|
46+
num = (idx+1) * 10
47+
rendered = <<-EOF
48+
*interface Tunnel#{num}.0
49+
- description Downstream: Tun#{site_tun.num}0.0@tun-0#{idx+1}.venue, Gi2.#{site_tun.num}0 [etherip-ipsec]
50+
- tunnel mode ether-ip ipsec-ikev2
51+
- no ip address
52+
- bridge-group #{num+1}
53+
- bridge ip tcp adjust-mss 1330
54+
- bridge ipv6 tcp adjust-mss 1330
55+
- ikev2 connect-type auto
56+
- ikev2 ipsec pre-fragment
57+
- ikev2 outgoing-interface #{site_tun.interface} #{site_tun.nexthop.sub(/%.+$/, '')}
58+
- ikev2 source-address ###TODO###
59+
- ikev2 ipsec-mode transport
60+
- ikev2 peer any authentication psk id fqdn tun-0#{idx+1}.venue.rubykaigi.net
61+
* no shutdown
62+
*!
63+
*interface Tunnel#{num+1}.0
64+
- description Downstream: Tun#{site_tun.num}1.0@tun-0#{idx+1}.venue, Gi2.#{site_tun.num}1 [etherip]
65+
- tunnel mode ether-ip ipv6
66+
* tunnel destination #{peer_address.to_s}
67+
- tunnel source ###TODO###
68+
- no ip address
69+
- bridge-group #{num+1}
70+
- bridge ip tcp adjust-mss 1330
71+
- bridge ipv6 tcp adjust-mss 1330
72+
* no shutdown
73+
-!
74+
EOF
4275

43-
bgppeer = BgpPeer.new
44-
v4a = IPAddr.new("#{v4.ip}/30")
45-
v4as = v4a.to_range.to_a
46-
bgppeer.ip = v4as.index{ |_| _.to_s == v4.ip } == 1 ? v4as[2] : v4as[1]
47-
peerinfo = hosts.each_value.to_a.flatten.find { |_| _.ip == bgppeer.ip.to_s }
48-
bgppeer.asn = ASNS.fetch(peerinfo.dc.to_sym)
49-
bgppeer.desc = canonical
50-
bgppeer.mapin = iface.start_with?('tun') ? 'private-in' : 'public-in'
51-
bgppeer.mapout = iface.start_with?('tun') ? 'private-out' : 'public-out'
52-
bgppeer.default = iface.start_with?('bvi')
76+
if is_full
77+
puts rendered.gsub(/^./, '')
78+
else
79+
puts rendered.each_line.grep(/^\*/).join.gsub(/^./, '')
80+
end
5381

54-
bgp_peers << bgppeer
55-
end
82+
negates << "interface Tunnel#{num}.0"
83+
negates << " shutdown"
84+
negates << "interface Tunnel#{num+1}.0"
85+
negates << " shutdown"
86+
end
5687

57-
puts "ipv6 router ospf 1"
58-
ospf3_ifaces.each do |(canonical, _)|
59-
puts " network #{canonical} area 0"
88+
puts
89+
puts
90+
negates << nil
91+
negates << nil
6092
end
61-
puts "!"
6293

94+
puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
95+
puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
96+
puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
6397

64-
puts "router bgp #{ASNS[ARGV[0].to_sym]}"
65-
bgp_peers.each do |peer|
66-
puts " neighbor #{peer.ip} remote-as #{peer.asn}"
67-
puts " neighbor #{peer.ip} description #{peer.desc}"
68-
puts " neighbor #{peer.ip} connect-interval 10"
69-
puts " neighbor #{peer.ip} advertisement-interval 6"
70-
puts " neighbor #{peer.ip} timers 6 30"
71-
end
72-
puts " address-family ipv4 unicast"
73-
bgp_peers.each do |peer|
74-
puts " neighbor #{peer.ip} route-map #{peer.mapin} in"
75-
puts " neighbor #{peer.ip} route-map #{peer.mapout} out"
76-
puts " no neighbor #{peer.ip} send-default "unless peer.default
77-
end
98+
puts negates.join("\n")

0 commit comments

Comments
 (0)