From 3c770f6c6b6a6712507df00ebb96b525bc93faae Mon Sep 17 00:00:00 2001 From: kaiyou <dev@kaiyou.fr> Date: Sun, 5 Nov 2023 00:19:12 +0100 Subject: [PATCH] Switch massively to netip instead of net --- cmd/hepto/hepto.go | 2 +- services/apiserver.go | 9 +++++--- services/certs.go | 4 ++-- services/discovery.go | 4 ++-- services/kubelet.go | 48 +++++++++++++++++++++---------------------- services/manager.go | 22 +++++++++----------- services/meta.go | 14 ++++++------- utils/net.go | 24 ++++++++-------------- wg/peer.go | 26 +++++++++++++++-------- wg/wireguard.go | 19 +++++++++-------- 10 files changed, 88 insertions(+), 84 deletions(-) diff --git a/cmd/hepto/hepto.go b/cmd/hepto/hepto.go index da9991a..42b9a75 100644 --- a/cmd/hepto/hepto.go +++ b/cmd/hepto/hepto.go @@ -72,7 +72,7 @@ func Hepto() error { }) } return c.Run(func() error { - config.Node.PublicIP = config.Iface.Addresses[0].Addr().AsSlice() + config.Node.PublicIP = config.Iface.Addresses[0].Addr() return manager.Run() }) } diff --git a/services/apiserver.go b/services/apiserver.go index 3f614b7..00d8b2c 100644 --- a/services/apiserver.go +++ b/services/apiserver.go @@ -180,7 +180,7 @@ func buildConfig(c *Cluster) (config *server.Config, clients *k8s.Clients, err e Cert: cert, ClientCA: clientCA, // not setup upstream, might be an issue } - config.PublicAddress = c.networking.NodeAddress.IP + config.PublicAddress = c.networking.NodeAddress.Addr().AsSlice() // Setup loopback clients (no authorization at this point, handled later) clients, err = k8s.NewTokenClients(c.masterUrl, c.pki.TLS, c.loopbackToken) @@ -328,8 +328,11 @@ func buildApiConfig(c *Cluster, config server.Config, clients *k8s.Clients) (*co ReadOnlyPort: ports.KubeletReadOnlyPort, PreferredAddressTypes: []string{string(core.NodeInternalIP), string(core.NodeExternalIP)}, }, - ServiceIPRange: *c.networking.ServiceNet, - APIServerServiceIP: c.networking.APIAddress, + ServiceIPRange: net.IPNet{ + IP: c.networking.ServiceNet.Addr().AsSlice(), + Mask: net.CIDRMask(c.networking.ServiceNet.Bits(), c.networking.ServiceNet.Addr().BitLen()), + }, + APIServerServiceIP: c.networking.APIAddress.AsSlice(), APIServerServicePort: 443, ServiceNodePortRange: utilnet.PortRange{Base: 30000, Size: 2768}, EndpointReconcilerType: reconcilers.LeaseEndpointReconcilerType, diff --git a/services/certs.go b/services/certs.go index 0f189f1..4850f52 100644 --- a/services/certs.go +++ b/services/certs.go @@ -121,7 +121,7 @@ var pkiMaster = &Unit{ tlsCert, err := bundle.GetCertOrCSR("tls", pekahi.NewServerTemplate( []string{"kube-apiserver", "kubernetes.default", "apiserver-loopback-client"}, - []net.IP{c.networking.NodeAddress.IP, c.networking.APIAddress, net.ParseIP("::1")}, + []net.IP{c.networking.NodeAddress.Addr().AsSlice(), c.networking.APIAddress.AsSlice(), net.ParseIP("::1")}, ), ) if err != nil { @@ -146,7 +146,7 @@ var pkiMaster = &Unit{ } // Controller manager certificate controllersTLSCert, err := bundle.GetCertOrCSR("controllers-tls", - pekahi.NewServerTemplate([]string{"controllers"}, []net.IP{c.networking.NodeAddress.IP}), + pekahi.NewServerTemplate([]string{"controllers"}, []net.IP{c.networking.NodeAddress.Addr().AsSlice()}), ) if err != nil { return err diff --git a/services/discovery.go b/services/discovery.go index 4e9b3c3..861c1a8 100644 --- a/services/discovery.go +++ b/services/discovery.go @@ -13,7 +13,7 @@ var memberlist = &Unit{ Dependencies: []*Unit{}, Run: func(u *Unit, c *Cluster, ctx context.Context) error { ml := sml.New[HeptoMeta, HeptoState]( - c.thisNode.Name, c.thisNode.PublicIP, + c.thisNode.Name, c.thisNode.PublicIP.AsSlice(), c.settings.DiscoveryPort, c.settings.Anchors, c.settings.Key, c.settings.Logger, ) ml.Meta = c.thisNode @@ -36,7 +36,7 @@ var memberlist = &Unit{ if node.Role == "master" || node.Role == "full" { u.Manager.Logger.Info("found remote master", "name", node.Name) c.masterNode = node - c.masterUrl = fmt.Sprintf("https://[%s]:%d", node.VpnIP.String(), apiserverPort) + c.masterUrl = fmt.Sprintf("https://[%s]:%d", node.VpnIP.Addr().String(), apiserverPort) u.Markready() } } diff --git a/services/kubelet.go b/services/kubelet.go index 1f0c668..8362fae 100644 --- a/services/kubelet.go +++ b/services/kubelet.go @@ -156,30 +156,30 @@ var kubeKubelet = &Unit{ &config.ContainerRuntimeOptions{ PodSandboxImage: "registry.k8s.io/pause:3.9", }, - c.thisNode.Name, // Hostname - false, // Hostname overridden - types.NodeName(c.thisNode.Name), // Node name - []net.IP{c.networking.NodeAddress.IP}, // IP addresses - c.thisNode.Name, // Provider ID (unused) - "", // Cloud provider - path.Join(kubeletRoot, "pki"), // PKI path - kubeletRoot, // Root directory - "", // Image creds config file - "", // Image creds bin path - true, // Register node - []core.Taint{}, // Taints - []string{}, // Unsafe sysctl - "", // Mounter path - false, // Kernel memcg notifications - false, // Allocatable ignore eviction threshold - meta.Duration{Duration: 0}, // Max gc duration - 1, // Max per pod container count - -1, // Max container count - true, // Register schedulable - false, // Keep terminated pod volumes - map[string]string{}, // Node labels - -1, // Node status max images - false, // Seccomp default + c.thisNode.Name, // Hostname + false, // Hostname overridden + types.NodeName(c.thisNode.Name), // Node name + []net.IP{c.networking.NodeAddress.Addr().AsSlice()}, // IP addresses + c.thisNode.Name, // Provider ID (unused) + "", // Cloud provider + path.Join(kubeletRoot, "pki"), // PKI path + kubeletRoot, // Root directory + "", // Image creds config file + "", // Image creds bin path + true, // Register node + []core.Taint{}, // Taints + []string{}, // Unsafe sysctl + "", // Mounter path + false, // Kernel memcg notifications + false, // Allocatable ignore eviction threshold + meta.Duration{Duration: 0}, // Max gc duration + 1, // Max per pod container count + -1, // Max container count + true, // Register schedulable + false, // Keep terminated pod volumes + map[string]string{}, // Node labels + -1, // Node status max images + false, // Seccomp default ) if err != nil { return fmt.Errorf("could not instantiate kubelet: %w", err) diff --git a/services/manager.go b/services/manager.go index dbcefe7..9dad1ca 100644 --- a/services/manager.go +++ b/services/manager.go @@ -3,7 +3,6 @@ package services import ( - "net" "net/netip" "github.com/containerd/containerd/services/server" @@ -38,12 +37,12 @@ type ClusterSettings struct { } type ClusterNetworking struct { - NodeNet *net.IPNet - NodeAddress *net.IPNet - ServiceNet *net.IPNet - PodNet *net.IPNet - APIAddress net.IP - DNSAddress net.IP + NodeNet netip.Prefix + NodeAddress netip.Prefix + ServiceNet netip.Prefix + PodNet netip.Prefix + APIAddress netip.Addr + DNSAddress netip.Addr MTU int } @@ -74,7 +73,7 @@ type Unit = daeman.Unit[*Cluster] func NewManager(settings *ClusterSettings, node *HeptoMeta, logger logr.Logger) *daeman.Manager[*Cluster] { networking := NewClusterNetworking(settings.Name, node.Name) - node.VpnIP = networking.NodeAddress.IP + node.VpnIP = networking.NodeAddress cluster := &Cluster{ settings: settings, thisNode: node, @@ -116,9 +115,8 @@ func NewClusterNetworking(clusterName string, nodeName string) *ClusterNetworkin podNet := utils.ULA(clusterName, 56, 2) // Services are hosted on a /112 at :3, e.g. fd00:0:0:0:0:0:0::/112 serviceNet := utils.ULA(clusterName, 112, 3) - // API address is the first service address - apiAddress, _ := netip.AddrFromSlice(serviceNet.IP) - apiIP := net.IP(apiAddress.Next().AsSlice()) - dnsIP := net.IP(apiAddress.Next().Next().AsSlice()) + // API address is the first service address, dns is the next one + apiIP := serviceNet.Addr().Next() + dnsIP := apiIP.Next() return &ClusterNetworking{nodeNet, nodeAddress, serviceNet, podNet, apiIP, dnsIP, 1500} } diff --git a/services/meta.go b/services/meta.go index 104425e..79836fd 100644 --- a/services/meta.go +++ b/services/meta.go @@ -2,7 +2,7 @@ package services import ( "encoding/json" - "net" + "net/netip" "go.acides.org/pekahi" ) @@ -12,9 +12,9 @@ type HeptoMeta struct { // Rencoding of node name Name string `json:"name"` // Public address of the node - PublicIP net.IP `json:"ip"` + PublicIP netip.Addr `json:"ip"` // Address of the node over the VPN - VpnIP net.IP `json:"vpnIP"` + VpnIP netip.Prefix `json:"vpnIP"` // Public key for the wireguard mesh VPN VpnKey string `json:"vpnKey"` // Node role inside the cluster @@ -26,16 +26,16 @@ func (m *HeptoMeta) Hostname() string { return m.Name } -func (m *HeptoMeta) IP() net.IP { +func (m *HeptoMeta) IP() netip.Addr { return m.PublicIP } -func (m *HeptoMeta) OverlayIP() net.IP { +func (m *HeptoMeta) OverlayIP() netip.Prefix { return m.VpnIP } -func (m *HeptoMeta) Routes() []net.IPNet { - return []net.IPNet{} +func (m *HeptoMeta) Routes() []netip.Prefix { + return []netip.Prefix{} } func (m *HeptoMeta) Key() string { diff --git a/utils/net.go b/utils/net.go index 926276b..c2deb5e 100644 --- a/utils/net.go +++ b/utils/net.go @@ -3,31 +3,27 @@ package utils import ( "crypto/sha256" "encoding/binary" - "net" + "net/netip" ) // Derive an address inside a pool network, based on a name -func DeriveAddress(pool *net.IPNet, name string) *net.IPNet { +func DeriveAddress(pool netip.Prefix, name string) netip.Prefix { // Compute a hash from the node name h := sha256.New() h.Write([]byte(name)) hb := h.Sum(nil) // Copy the hash to the address part of the IPNet - ones, _ := pool.Mask.Size() - bytes := ones / 8 - ip := make(net.IP, len(pool.IP)) - copy(ip, pool.IP) + bytes := pool.Bits() / 8 + ip := pool.Addr().AsSlice() copy(ip[bytes:], hb[:16-bytes]) - return &net.IPNet{ - IP: ip, - Mask: pool.Mask, - } + addr, _ := netip.AddrFromSlice(ip) + return netip.PrefixFrom(addr, pool.Bits()) } // Derive a fc::/7 network including a pseudo-random global id // generated from the network name and the provided local id -func ULA(name string, length int, id uint16) *net.IPNet { +func ULA(name string, length int, id uint16) netip.Prefix { ip := make([]byte, 16) // Compute a hash for the network name @@ -44,8 +40,6 @@ func ULA(name string, length int, id uint16) *net.IPNet { // global ID binary.LittleEndian.PutUint16(ip[6:], id) - return &net.IPNet{ - IP: ip, - Mask: net.CIDRMask(length, 128), - } + addr, _ := netip.AddrFromSlice(ip) + return netip.PrefixFrom(addr, length) } diff --git a/wg/peer.go b/wg/peer.go index 908c845..6750023 100644 --- a/wg/peer.go +++ b/wg/peer.go @@ -2,6 +2,7 @@ package wg import ( "net" + "net/netip" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) @@ -9,28 +10,35 @@ import ( type Peer interface { Hostname() string Key() string - IP() net.IP - OverlayIP() net.IP - Routes() []net.IPNet + IP() netip.Addr + OverlayIP() netip.Prefix + Routes() []netip.Prefix } func (w *Wireguard) peerToWgConfig(p Peer) (wgtypes.PeerConfig, error) { - bits := 8 * len(p.OverlayIP()) pubKey, err := wgtypes.ParseKey(p.Key()) if err != nil { return wgtypes.PeerConfig{}, err } + overlay := p.OverlayIP() + allowed := []net.IPNet{{ + IP: overlay.Addr().AsSlice(), + Mask: net.CIDRMask(overlay.Bits(), overlay.Addr().BitLen()), + }} + for _, route := range p.Routes() { + allowed = append(allowed, net.IPNet{ + IP: route.Addr().AsSlice(), + Mask: net.CIDRMask(route.Bits(), route.Addr().BitLen()), + }) + } return wgtypes.PeerConfig{ PublicKey: pubKey, ReplaceAllowedIPs: true, Endpoint: &net.UDPAddr{ - IP: p.IP(), + IP: p.IP().AsSlice(), Port: w.port, }, - AllowedIPs: append(p.Routes(), net.IPNet{ - IP: p.OverlayIP(), - Mask: net.CIDRMask(bits, bits), - }), + AllowedIPs: allowed, PersistentKeepaliveInterval: &w.keepalive, }, nil } diff --git a/wg/wireguard.go b/wg/wireguard.go index 915d38d..bc02928 100644 --- a/wg/wireguard.go +++ b/wg/wireguard.go @@ -3,6 +3,7 @@ package wg import ( "fmt" "net" + "net/netip" "os" "strings" "time" @@ -18,7 +19,7 @@ import ( // Wireguard interface config type Wireguard struct { iface string - ipnet *net.IPNet + ipnet netip.Prefix logger logr.Logger client *wgctrl.Client port int @@ -27,7 +28,7 @@ type Wireguard struct { PubKey wgtypes.Key } -func New(iface string, port int, ipnet *net.IPNet, logger logr.Logger) (*Wireguard, error) { +func New(iface string, port int, ipnet netip.Prefix, logger logr.Logger) (*Wireguard, error) { client, err := wgctrl.New() if err != nil { return nil, errors.Wrap(err, "could not instantiate wireguard client") @@ -88,7 +89,10 @@ func (w *Wireguard) Update(peers []Peer, mtu int) error { } w.logger.Info("adding VPN address", "address", w.ipnet.String()) err = netlink.AddrAdd(link, &netlink.Addr{ - IPNet: w.ipnet, + IPNet: &net.IPNet{ + IP: w.ipnet.Addr().AsSlice(), + Mask: net.CIDRMask(w.ipnet.Bits(), w.ipnet.Addr().BitLen()), + }, }) if err != nil && !os.IsExist(err) { return fmt.Errorf("could not setup wg address: %w", err) @@ -102,15 +106,12 @@ func (w *Wireguard) Update(peers []Peer, mtu int) error { return fmt.Errorf("could not enable wg iface: %w", err) } for _, peer := range configs { - overlay := net.IPNet{ - IP: w.ipnet.IP.Mask(w.ipnet.Mask), - Mask: w.ipnet.Mask, - } - var gw net.IP for _, route := range peer.AllowedIPs { + var gw net.IP w.logger.Info("new route", "dest", route.String()) scope := netlink.SCOPE_UNIVERSE - if overlay.Contains(route.IP) { + routeAddr, _ := netip.AddrFromSlice(route.IP) + if w.ipnet.Contains(routeAddr) { gw = route.IP scope = netlink.SCOPE_LINK } -- GitLab