We were expecting the prefix to be shorter than 68 bits but the latest leaseweb hosts came with ipv6 blocks like: 2607:f5b7:1:64:1::_112/64 2607:f5b7:1:64:2::_112/64 2607:f5b7:1:64:3::_112/64 As you can see, they give /64 but the address space is not actually as big as /64. Because, the :1, :2, :3 at the end of the prefix is actually to 80th bit. We must see them like the following for it to make sense; 2607:f5b7:1:64:0001::/64 2607:f5b7:1:64:0002::/64 Here, the differentiating bit is in the residue part of a /64 network. So, if we use them as they are, we need to actually map them to 2607:f5b7:1:64::/64 which would not work because then we would have multiple hosts with the same prefix and we cannot assign ipv6 addresses to the VMs correctly. To solve this issue, we assign the prefixes correctly using /80. So, the hosts become 2607:f5b7:1:64:0001::/80 2607:f5b7:1:64:0002::/80 This requires modification in learn_network prog because it was previously expecting at least /68. We increase the condition to 112 bits. The main idea of /68 was that so that we can deleget prefixes at the size of /80 which doesn't really work because dnsmasq cannot delegate the prefixes anyway. So, in any case, we simply give /128 to anyone. However, we still keep it at least 112 bits because we need 2 bytes of entropy.
51 lines
1.6 KiB
Ruby
51 lines
1.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "json"
|
|
|
|
class Prog::LearnNetwork < Prog::Base
|
|
subject_is :sshable, :vm_host
|
|
|
|
label def start
|
|
ip6 = parse_ip_addr_j(sshable.cmd("/usr/sbin/ip -j -6 addr show scope global"))
|
|
|
|
# While it would be ideal for NetAddr's IPv6 support to convey
|
|
# both address and prefix information together as `ip` does, it's
|
|
# designed in a more IPv4-centric way where IP addresses and CIDRs
|
|
# tend to be disaggregated.
|
|
#
|
|
# Postgres's "inet" does support this IPv6-style mixture of
|
|
# addresses and prefixlens, the "cidr" type requires masked-out
|
|
# bits to be zero. NetAddr's IPv6Net type clears low bits beyond
|
|
# the prefix.
|
|
#
|
|
# Maybe we can improve support for inet in a fork later, NetAddr
|
|
# is not a fast moving project, there is room to improve it, but
|
|
# some would be backwards-incompatible.
|
|
vm_host.update(
|
|
ip6: ip6.addr,
|
|
net6: NetAddr::IPv6Net.new(NetAddr.parse_ip(ip6.addr), NetAddr::Mask128.new(ip6.prefixlen)).to_s
|
|
)
|
|
pop "learned network information"
|
|
end
|
|
|
|
Ip6 = Struct.new(:addr, :prefixlen)
|
|
|
|
def parse_ip_addr_j(s)
|
|
case JSON.parse(s)
|
|
in [iface]
|
|
case iface.fetch("addr_info").filter_map { |info|
|
|
if (local = info["local"]) && (prefixlen = info["prefixlen"]) && prefixlen <= 112
|
|
Ip6.new(local, prefixlen)
|
|
end
|
|
}
|
|
in [net6]
|
|
net6
|
|
else
|
|
fail "only one global unique address prefix supported on interface"
|
|
end
|
|
else
|
|
fail "only one one interface supported"
|
|
end
|
|
end
|
|
end
|