|
| 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 | + |
1 | 9 | require 'ipaddr' |
2 | | -# Usage: ix_tun.rb hnd br-01 |
3 | 10 |
|
4 | | -IFACES = %w(bvi0 bvi10 bvi1 bvi11 tun100 tun110 tun101 tun111) |
| 11 | +is_full = ARGV.delete('--full') |
5 | 12 |
|
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 |
10 | 22 | } |
11 | 23 |
|
12 | | -host_lines = File.read(File.join(__dir__, '..', 'hosts.txt')) |
13 | 24 |
|
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) |
21 | 26 |
|
| 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 | +] |
22 | 32 |
|
23 | | -target = ARGV[0,2] |
24 | 33 |
|
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} !!!!!!!!!" |
40 | 38 |
|
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 |
42 | 75 |
|
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 |
53 | 81 |
|
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 |
56 | 87 |
|
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 |
60 | 92 | end |
61 | | -puts "!" |
62 | 93 |
|
| 94 | +puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" |
| 95 | +puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" |
| 96 | +puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" |
63 | 97 |
|
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