From cb8f2518628679de9ee096fa42711ba385a30b83 Mon Sep 17 00:00:00 2001 From: Nathan Skrzypczak Date: Fri, 13 Oct 2023 19:26:23 +0200 Subject: [PATCH] wireguard: use allowed_ips only for nodes Signed-off-by: Nathan Skrzypczak --- calico-vpp-agent/connectivity/wireguard.go | 396 ++++++++++----------- vpplink/helpers.go | 7 + 2 files changed, 197 insertions(+), 206 deletions(-) diff --git a/calico-vpp-agent/connectivity/wireguard.go b/calico-vpp-agent/connectivity/wireguard.go index 47470005..e880f3fe 100644 --- a/calico-vpp-agent/connectivity/wireguard.go +++ b/calico-vpp-agent/connectivity/wireguard.go @@ -28,351 +28,335 @@ import ( "github.com/projectcalico/vpp-dataplane/v3/calico-vpp-agent/common" "github.com/projectcalico/vpp-dataplane/v3/config" + "github.com/projectcalico/vpp-dataplane/v3/vpplink" "github.com/projectcalico/vpp-dataplane/v3/vpplink/types" ) type WireguardProvider struct { *ConnectivityProviderData wireguardTunnels map[string]*vpptypes.WireguardTunnel - wireguardPeers map[string]vpptypes.WireguardPeer + wireguardPeers map[string]*vpptypes.WireguardPeer nodesToWGPublicKey map[string]string + wireguardRoutes map[uint32]map[string]map[string]bool } func NewWireguardProvider(d *ConnectivityProviderData) *WireguardProvider { return &WireguardProvider{ ConnectivityProviderData: d, wireguardTunnels: make(map[string]*vpptypes.WireguardTunnel), - wireguardPeers: make(map[string]vpptypes.WireguardPeer), + wireguardPeers: make(map[string]*vpptypes.WireguardPeer), nodesToWGPublicKey: make(map[string]string), + wireguardRoutes: make(map[uint32]map[string]map[string]bool), } } -func (p *WireguardProvider) Enabled(cn *common.NodeConnectivity) bool { - felixConfig := p.GetFelixConfig() +func (self *WireguardProvider) Enabled(cn *common.NodeConnectivity) bool { + felixConfig := self.GetFelixConfig() if !felixConfig.WireguardEnabled { return false } - node := p.GetNodeByIp(cn.NextHop) - return p.nodesToWGPublicKey[node.Name] != "" + node := self.GetNodeByIp(cn.NextHop) + return self.nodesToWGPublicKey[node.Name] != "" } -func (p *WireguardProvider) getWireguardPort() uint16 { - felixConfig := p.GetFelixConfig() +func (self *WireguardProvider) getWireguardPort() uint16 { + felixConfig := self.GetFelixConfig() if felixConfig.WireguardListeningPort == 0 { return uint16(config.DefaultWireguardPort) } return uint16(felixConfig.WireguardListeningPort) } -func (p *WireguardProvider) getNodePublicKey(cn *common.NodeConnectivity) ([]byte, error) { - node := p.GetNodeByIp(cn.NextHop) - if p.nodesToWGPublicKey[node.Name] == "" { +func (self *WireguardProvider) getNodePublicKey(cn *common.NodeConnectivity) ([]byte, error) { + node := self.GetNodeByIp(cn.NextHop) + if self.nodesToWGPublicKey[node.Name] == "" { return nil, fmt.Errorf("no public key for node=%s", node.Name) } - p.log.Infof("connectivity(add) Wireguard nodeName=%s pubKey=%s", node.Name, p.nodesToWGPublicKey[node.Name]) - key, err := base64.StdEncoding.DecodeString(p.nodesToWGPublicKey[node.Name]) + self.log.Infof("connectivity(add) Wireguard nodeName=%s pubKey=%s", node.Name, self.nodesToWGPublicKey[node.Name]) + key, err := base64.StdEncoding.DecodeString(self.nodesToWGPublicKey[node.Name]) if err != nil { - return nil, errors.Wrapf(err, "Error decoding wireguard public key %s", p.nodesToWGPublicKey[node.Name]) + return nil, errors.Wrapf(err, "Error decoding wireguard public key %s", self.nodesToWGPublicKey[node.Name]) } return key, nil } -func (p *WireguardProvider) publishWireguardPublicKey(pubKey string) error { +func (self *WireguardProvider) publishWireguardPublicKey(pubKey string) error { // Ref: felix/daemon/daemon.go:1056 - node, err := p.Clientv3().Nodes().Get(context.Background(), *config.NodeName, options.GetOptions{}) + node, err := self.Clientv3().Nodes().Get(context.Background(), *config.NodeName, options.GetOptions{}) if err != nil { return errors.Wrapf(err, "Error getting node config") } - p.log.Infof("connectivity(add) Wireguard publishing nodeName=%s pubKey=%s", *config.NodeName, pubKey) + self.log.Infof("connectivity(add) Wireguard publishing nodeName=%s pubKey=%s", *config.NodeName, pubKey) node.Status.WireguardPublicKey = pubKey - _, err = p.Clientv3().Nodes().Update(context.Background(), node, options.SetOptions{}) + _, err = self.Clientv3().Nodes().Update(context.Background(), node, options.SetOptions{}) if err != nil { return errors.Wrapf(err, "Error updating node config") } return nil } -func (p *WireguardProvider) RescanState() { - p.wireguardPeers = make(map[string]vpptypes.WireguardPeer) - p.wireguardTunnels = make(map[string]*vpptypes.WireguardTunnel) +func (self *WireguardProvider) RescanState() { + self.wireguardPeers = make(map[string]*vpptypes.WireguardPeer) + self.wireguardTunnels = make(map[string]*vpptypes.WireguardTunnel) + self.wireguardRoutes = make(map[uint32]map[string]map[string]bool) - p.log.Debugf("Wireguard: Rescanning existing tunnels") - tunnels, err := p.vpp.ListWireguardTunnels() + self.log.Debugf("Wireguard: Rescanning existing tunnels") + tunnels, err := self.vpp.ListWireguardTunnels() if err != nil { - p.log.Errorf("Error listing wireguard tunnels: %v", err) + self.log.Errorf("Error listing wireguard tunnels: %v", err) } - ip4, ip6 := p.server.GetNodeIPs() for _, tunnel := range tunnels { - if ip4 != nil && tunnel.Addr.Equal(*ip4) { - p.log.Infof("Found existing v4 tunnel: %s", tunnel) - p.wireguardTunnels["ip4"] = tunnel - } - if ip6 != nil && tunnel.Addr.Equal(*ip6) { - p.log.Infof("Found existing v6 tunnel: %s", tunnel) - p.wireguardTunnels["ip6"] = tunnel - } + self.log.Infof("Found existing tunnel: %s", tunnel) + self.wireguardTunnels[tunnel.Addr.String()] = tunnel + self.wireguardRoutes[tunnel.SwIfIndex] = make(map[string]map[string]bool) } - p.log.Debugf("Wireguard: Rescanning existing peers") - peers, err := p.vpp.ListWireguardPeers() + self.log.Debugf("Wireguard: Rescanning existing peers") + peers, err := self.vpp.ListWireguardPeers() if err != nil { - p.log.Errorf("Error listing wireguard peers: %v", err) + self.log.Errorf("Error listing wireguard peers: %v", err) } for _, peer := range peers { - p.wireguardPeers[peer.Addr.String()] = *peer + self.wireguardPeers[peer.Addr.String()] = peer + if _, exist := self.wireguardRoutes[peer.SwIfIndex]; !exist { + self.log.Errorf("Peer found for non WG tunnel: %v", peer) + continue + } + self.wireguardRoutes[peer.SwIfIndex][peer.Addr.String()] = make(map[string]bool) + } + + routes, err := self.vpp.GetRoutes(0, false) + if err != nil { + self.log.Errorf("Error listing routes: %v", err) + } + for _, route := range routes { + for _, routePath := range route.Paths { + _, exists := self.wireguardRoutes[routePath.SwIfIndex] + if exists { + self.wireguardRoutes[routePath.SwIfIndex][routePath.Gw.String()][route.Dst.String()] = true + } + } } } -func (p *WireguardProvider) errorCleanup(tunnel *vpptypes.WireguardTunnel) { - err := p.vpp.DelWireguardTunnel(tunnel) +func (self *WireguardProvider) errorCleanup(tunnel *vpptypes.WireguardTunnel) { + err := self.vpp.DelWireguardTunnel(tunnel) if err != nil { - p.log.Errorf("Error deleting wireguard tunnel %s after error: %v", tunnel.String(), err) + self.log.Errorf("Error deleting wireguard tunnel %s after error: %v", tunnel.String(), err) } } -func (p *WireguardProvider) EnableDisable(isEnable bool) { +func (self *WireguardProvider) EnableDisable(isEnable bool) { if isEnable { - if len(p.wireguardTunnels) == 0 { - err := p.createWireguardTunnels() + if len(self.wireguardTunnels) == 0 { + err := self.createWireguardTunnels() if err != nil { - p.log.Errorf("Wireguard: Error creating v4 tunnel %s", err) + self.log.Errorf("Wireguard: Error creating v4 tunnel %s", err) return } } - for _, tun := range p.wireguardTunnels { + for _, tun := range self.wireguardTunnels { key := base64.StdEncoding.EncodeToString(tun.PublicKey) - err := p.publishWireguardPublicKey(key) + err := self.publishWireguardPublicKey(key) if err != nil { - p.log.Errorf("Wireguard: publish PublicKey error %s", err) + self.log.Errorf("Wireguard: publish PublicKey error %s", err) } // should be the same for all, so one publishing is enough break } } else { /* disable wireguard */ - err := p.publishWireguardPublicKey("") + err := self.publishWireguardPublicKey("") if err != nil { - p.log.Errorf("Wireguard: publish PublicKey error %s", err) + self.log.Errorf("Wireguard: publish PublicKey error %s", err) } } } -func (p *WireguardProvider) createWireguardTunnels() error { +func (self *WireguardProvider) createWireguardTunnels() error { + ip4, ip6 := self.server.GetNodeIPs() + for _, nodeIp := range []*net.IP{ip4, ip6} { + if nodeIp == nil { + continue + } + tunnel := &vpptypes.WireguardTunnel{ + Addr: *nodeIp, + Port: self.getWireguardPort(), + } + generateKey := true + for _, tun := range self.wireguardTunnels { + // If we already have tunnel (v4 or v6), use the same public + // key for the other one + tunnel.PrivateKey = tun.PrivateKey + generateKey = false + break + } + swIfIndex, err := self.vpp.AddWireguardTunnel(tunnel, generateKey) + if err != nil { + self.errorCleanup(tunnel) + return errors.Wrapf(err, "Error creating wireguard tunnel") + } + // fetch public key of created tunnel + createdTunnel, err := self.vpp.GetWireguardTunnel(swIfIndex) + if err != nil { + self.errorCleanup(tunnel) + return errors.Wrapf(err, "Error fetching wireguard tunnel after creation") + } + tunnel.PublicKey = createdTunnel.PublicKey + tunnel.PrivateKey = createdTunnel.PrivateKey - var nodeIp4, nodeIp6 net.IP - ip4, ip6 := p.server.GetNodeIPs() - if ip6 != nil { - nodeIp6 = *ip6 - } - if ip4 != nil { - nodeIp4 = *ip4 - } else { - return fmt.Errorf("Missing node address") - } - nodeIps := map[string]net.IP{"ip4": nodeIp4, "ip6": nodeIp6} - for ipfamily, nodeIp := range nodeIps { - if nodeIp != nil { - p.log.Debugf("Adding wireguard Tunnel to VPP") - tunnel := &vpptypes.WireguardTunnel{ - Addr: nodeIp, - Port: p.getWireguardPort(), - } - var swIfIndex uint32 - var err error - if len(p.wireguardTunnels) != 0 { // we already have one, use same public key - for _, tun := range p.wireguardTunnels { - tunnel.PrivateKey = tun.PrivateKey - break - } - swIfIndex, err = p.vpp.AddWireguardTunnel(tunnel, false /* generateKey */) - } else { - swIfIndex, err = p.vpp.AddWireguardTunnel(tunnel, true /* generateKey */) - } + err = self.vpp.InterfaceSetUnnumbered(swIfIndex, common.VppManagerInfo.GetMainSwIfIndex()) + if err != nil { + self.errorCleanup(tunnel) + return errors.Wrapf(err, "Error setting wireguard tunnel unnumbered") + } - if err != nil { - p.errorCleanup(tunnel) - return errors.Wrapf(err, "Error creating wireguard tunnel") - } - // fetch public key of created tunnel - createdTunnel, err := p.vpp.GetWireguardTunnel(swIfIndex) - if err != nil { - p.errorCleanup(tunnel) - return errors.Wrapf(err, "Error fetching wireguard tunnel after creation") - } - tunnel.PublicKey = createdTunnel.PublicKey - tunnel.PrivateKey = createdTunnel.PrivateKey + err = self.vpp.EnableGSOFeature(swIfIndex) + if err != nil { + self.errorCleanup(tunnel) + return errors.Wrapf(err, "Error enabling gso for wireguard interface") + } - err = p.vpp.InterfaceSetUnnumbered(swIfIndex, common.VppManagerInfo.GetMainSwIfIndex()) - if err != nil { - p.errorCleanup(tunnel) - return errors.Wrapf(err, "Error setting wireguard tunnel unnumbered") - } + err = self.vpp.CnatEnableFeatures(swIfIndex) + if err != nil { + self.errorCleanup(tunnel) + return errors.Wrapf(err, "Error enabling nat for wireguard interface") + } - err = p.vpp.EnableGSOFeature(swIfIndex) - if err != nil { - p.errorCleanup(tunnel) - return errors.Wrapf(err, "Error enabling gso for wireguard interface") - } + err = self.vpp.InterfaceAdminUp(swIfIndex) + if err != nil { + self.errorCleanup(tunnel) + return errors.Wrapf(err, "Error setting wireguard interface up") + } - err = p.vpp.CnatEnableFeatures(swIfIndex) - if err != nil { - p.errorCleanup(tunnel) - return errors.Wrapf(err, "Error enabling nat for wireguard interface") - } + common.SendEvent(common.CalicoVppEvent{ + Type: common.TunnelAdded, + New: swIfIndex, + }) - err = p.vpp.InterfaceAdminUp(swIfIndex) - if err != nil { - p.errorCleanup(tunnel) - return errors.Wrapf(err, "Error setting wireguard interface up") - } + self.wireguardTunnels[nodeIp.String()] = tunnel - common.SendEvent(common.CalicoVppEvent{ - Type: common.TunnelAdded, - New: swIfIndex, - }) + self.wireguardRoutes[tunnel.SwIfIndex] = make(map[string]map[string]bool) + } + self.log.Infof("connectivity(add) Wireguard Done tunnel=%s", self.wireguardTunnels) + return nil +} - p.wireguardTunnels[ipfamily] = tunnel +func (self *WireguardProvider) getTunnelForIpFamily(cn *common.NodeConnectivity) *vpptypes.WireguardTunnel { + for _, tun := range self.wireguardTunnels { + if vpplink.IpFamilyFromIP(&tun.Addr) == vpplink.IpFamilyFromIP(&cn.NextHop) { + return tun } } - p.log.Infof("connectivity(add) Wireguard Done tunnel=%s", p.wireguardTunnels) return nil + } -func (p *WireguardProvider) AddConnectivity(cn *common.NodeConnectivity) error { - ipfamily := "ip4" - if cn.NextHop.To4() == nil { - ipfamily = "ip6" - } - if _, exists := p.wireguardTunnels[ipfamily]; !exists { - return fmt.Errorf("Wireguard: missing tunnel for ip family %s", ipfamily) +func (self *WireguardProvider) AddConnectivity(cn *common.NodeConnectivity) error { + wireguardTunnel := self.getTunnelForIpFamily(cn) + if wireguardTunnel == nil { + return fmt.Errorf("Wireguard: missing tunnel for ip family %s", cn) } - key, err := p.getNodePublicKey(cn) + key, err := self.getNodePublicKey(cn) if err != nil { return errors.Wrapf(err, "Error Getting node %s publicKey", cn.NextHop) } - peer := &vpptypes.WireguardPeer{ - PublicKey: key, - Port: p.getWireguardPort(), - Addr: cn.NextHop, - SwIfIndex: p.wireguardTunnels[ipfamily].SwIfIndex, - AllowedIps: []net.IPNet{cn.Dst, *common.ToMaxLenCIDR(cn.NextHop)}, - } - existingPeer, found := p.wireguardPeers[cn.NextHop.String()] - p.log.Infof("connectivity(add) Wireguard: NH=%s Dst=%s found=%t", cn.NextHop, cn.Dst, found) - if found { - peer.AllowedIps = existingPeer.AllowedIps - peer.AddAllowedIp(cn.Dst) - /* Only update if we need to */ - if !existingPeer.Equal(peer) { - p.log.Infof("connectivity(add) Wireguard: Delete (update) peer=%s", existingPeer.String()) - err := p.vpp.DelWireguardPeer(&existingPeer) - if err != nil { - return errors.Wrapf(err, "Error deleting (update) wireguard peer=%s", existingPeer.String()) - } - p.log.Infof("connectivity(add) Wireguard: Add back (update) peer=%s", peer) - peer.Index, err = p.vpp.AddWireguardPeer(peer) - if err != nil { - return errors.Wrapf(err, "Error adding (update) wireguard peer=%s", peer) - } + + peer, found := self.wireguardPeers[cn.NextHop.String()] + self.log.Infof("connectivity(add) Wireguard: NH=%s Dst=%s found=%t", cn.NextHop, cn.Dst, found) + if !found { + peer = &vpptypes.WireguardPeer{ + PublicKey: key, + Port: self.getWireguardPort(), + Addr: cn.NextHop, + SwIfIndex: wireguardTunnel.SwIfIndex, + AllowedIps: []net.IPNet{cn.Dst, *common.ToMaxLenCIDR(cn.NextHop)}, } - } else { - p.log.Infof("connectivity(add) Wireguard: Add peer=%s", peer) - peer.Index, err = p.vpp.AddWireguardPeer(peer) + + self.log.Infof("connectivity(add) Wireguard: Add peer=%s", peer) + peer.Index, err = self.vpp.AddWireguardPeer(peer) if err != nil { return errors.Wrapf(err, "Error adding wireguard peer [%s]", peer) } + self.wireguardRoutes[wireguardTunnel.SwIfIndex][cn.NextHop.String()] = make(map[string]bool) - p.log.Debugf("Routing pod->node %s traffic into wg tunnel (swIfIndex %d)", cn.NextHop.String(), p.wireguardTunnels[ipfamily].SwIfIndex) - err = p.vpp.RouteAdd(&types.Route{ + self.log.Debugf("Routing pod->node %s traffic into wg tunnel (swIfIndex %d)", cn.NextHop.String(), wireguardTunnel.SwIfIndex) + err = self.vpp.RouteAdd(&types.Route{ Dst: common.ToMaxLenCIDR(cn.NextHop), Paths: []types.RoutePath{{ - SwIfIndex: p.wireguardTunnels[ipfamily].SwIfIndex, - Gw: nil, + SwIfIndex: wireguardTunnel.SwIfIndex, + Gw: cn.NextHop, }}, Table: common.PodVRFIndex, }) if err != nil { - return errors.Wrapf(err, "Error adding route to %s in wg tunnel %d for pods", cn.NextHop.String(), p.wireguardTunnels[ipfamily].SwIfIndex) + return errors.Wrapf(err, "Error adding route to %s in wg tunnel %d for pods", cn.NextHop.String(), wireguardTunnel.SwIfIndex) } + self.wireguardPeers[cn.NextHop.String()] = peer } - p.log.Infof("connectivity(add) Wireguard tunnel done peer=%s", peer) - p.wireguardPeers[cn.NextHop.String()] = *peer + self.log.Infof("connectivity(add) Wireguard tunnel done peer=%s", peer) - p.log.Debugf("Adding wireguard tunnel route to %s via swIfIndex %d", cn.Dst.IP, p.wireguardTunnels[ipfamily].SwIfIndex) - err = p.vpp.RouteAdd(&types.Route{ + self.log.Debugf("Adding wireguard tunnel route to %s via swIfIndex %d", cn.Dst.IP, wireguardTunnel.SwIfIndex) + err = self.vpp.RouteAdd(&types.Route{ Dst: &cn.Dst, + // This picks the adjacency defined in peer.AllowedIps Paths: []types.RoutePath{{ - SwIfIndex: p.wireguardTunnels[ipfamily].SwIfIndex, - Gw: cn.Dst.IP, + SwIfIndex: wireguardTunnel.SwIfIndex, + Gw: cn.NextHop, }}, }) if err != nil { return errors.Wrapf(err, "Error Adding route to wireguard tunnel") } + self.wireguardRoutes[wireguardTunnel.SwIfIndex][cn.NextHop.String()][cn.Dst.String()] = true return nil } -func (p *WireguardProvider) DelConnectivity(cn *common.NodeConnectivity) (err error) { - ipfamily := "ip4" - if cn.NextHop.To4() == nil { - ipfamily = "ip6" - } - if _, exists := p.wireguardTunnels[ipfamily]; !exists { - return fmt.Errorf("Wireguard: missing tunnel for ip family %s", ipfamily) +func (self *WireguardProvider) DelConnectivity(cn *common.NodeConnectivity) (err error) { + wireguardTunnel := self.getTunnelForIpFamily(cn) + if wireguardTunnel == nil { + return fmt.Errorf("Wireguard: missing tunnel for ip family %s", cn) } - peer, found := p.wireguardPeers[cn.NextHop.String()] + peer, found := self.wireguardPeers[cn.NextHop.String()] if !found { return errors.Errorf("Deleting unknown wireguard tunnel %s", cn.NextHop.String()) } - p.log.Infof("connectivity(del) Wireguard cn=%s peer-index=%d", cn.String(), peer.Index) - peer.DelAllowedIp(cn.Dst) + self.log.Infof("connectivity(del) Wireguard cn=%s peer-index=%d", cn.String(), peer.Index) - if len(peer.AllowedIps) == 1 { - err = p.vpp.DelWireguardPeer(&peer) + err = self.vpp.RouteDel(&types.Route{ + Dst: &cn.Dst, + Paths: []types.RoutePath{{ + SwIfIndex: peer.SwIfIndex, + Gw: cn.NextHop, + }}, + }) + if err != nil { + return errors.Wrapf(err, "Error deleting wireguard tunnel route") + } + delete(self.wireguardRoutes[wireguardTunnel.SwIfIndex][cn.NextHop.String()], cn.Dst.String()) + if len(self.wireguardRoutes[wireguardTunnel.SwIfIndex][cn.NextHop.String()]) == 0 { + err = self.vpp.DelWireguardPeer(peer) if err != nil { return errors.Wrapf(err, "Error deleting wireguard peer %s", peer.String()) } - err = p.vpp.RouteDel(&types.Route{ + delete(self.wireguardRoutes[wireguardTunnel.SwIfIndex], cn.NextHop.String()) + + err = self.vpp.RouteDel(&types.Route{ Dst: common.ToMaxLenCIDR(cn.NextHop), Paths: []types.RoutePath{{ - SwIfIndex: p.wireguardTunnels[ipfamily].SwIfIndex, - Gw: nil, + SwIfIndex: wireguardTunnel.SwIfIndex, + Gw: cn.NextHop, }}, Table: common.PodVRFIndex, }) if err != nil { - return errors.Wrapf(err, "Error deleting route to %s in ipip tunnel %d for pods", cn.NextHop.String(), p.wireguardTunnels[ipfamily].SwIfIndex) - } - delete(p.wireguardPeers, cn.NextHop.String()) - } else { - /* for now delete + recreate using modified object as delete - * doesn't consider AllowedIps */ - p.log.Infof("connectivity(del) Wireguard: Delete (update) peer=%s", peer.String()) - err = p.vpp.DelWireguardPeer(&peer) - if err != nil { - return errors.Wrapf(err, "Error deleting (update) wireguard peer %s", peer.String()) - } - p.log.Infof("connectivity(del) Wireguard: Addback (update) peer=%s", peer.String()) - _, err = p.vpp.AddWireguardPeer(&peer) - if err != nil { - return errors.Wrapf(err, "Error adding (update) wireguard peer=%s", peer.String()) + return errors.Wrapf(err, "Error deleting route to %s in ipip tunnel %d for pods", cn.NextHop.String(), wireguardTunnel.SwIfIndex) } - p.wireguardPeers[cn.NextHop.String()] = peer - } - err = p.vpp.RouteDel(&types.Route{ - Dst: &cn.Dst, - Paths: []types.RoutePath{{ - SwIfIndex: peer.SwIfIndex, - Gw: cn.Dst.IP, - }}, - }) - if err != nil { - return errors.Wrapf(err, "Error deleting wireguard tunnel route") + delete(self.wireguardPeers, cn.NextHop.String()) } - // We don't delete the interface so keep it in the map - // p.wireguardV[46]Tunnel + return nil } diff --git a/vpplink/helpers.go b/vpplink/helpers.go index 042a88dc..99100e13 100644 --- a/vpplink/helpers.go +++ b/vpplink/helpers.go @@ -39,6 +39,13 @@ var ( IpFamilies = []IpFamily{IpFamilyV4, IpFamilyV6} ) +func IpFamilyFromIP(addr *net.IP) IpFamily { + if addr.To4() == nil { + return IpFamilyV6 + } + return IpFamilyV4 +} + func IpFamilyFromIPNet(ipNet *net.IPNet) IpFamily { if ipNet == nil { return IpFamilyV4