mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
libn/d/overlay: use netip types more
The netip types are really useful for tracking state in the overlay
driver as they are hashable, unlike net.IP and friends, making them
directly useable as map keys. Converting between netip and net types is
fairly trivial, but fewer conversions is more ergonomic.
The NetworkDB entries for the overlay peer table encode the IP addresses
as strings. We need to parse them to some representation before
processing them further. Parse directly into netip types and pass those
values around to cut down on the number of conversions needed.
The peerDB needs to marshal the keys and entries to structs of hashable
values to be able to insert them into the SetMatrix. Use netip.Addr in
peerEntry so that peerEntry values can be directly inserted into the
SetMatrix without conversions. Use a hashable struct type as the
SetMatrix key to avoid having to marshal the whole struct to a string
and parse it back out.
Use netip.Addr as the map key for the driver's encryption map so the
values do not need to be converted to and from strings. Change the
encryption configuration methods to take netip types so the peerDB code
can pass netip values directly.
Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit d188df0039)
Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -90,7 +91,7 @@ func (s *spi) String() string {
|
||||
}
|
||||
|
||||
type encrMap struct {
|
||||
nodes map[string][]*spi
|
||||
nodes map[netip.Addr][]*spi
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@@ -100,7 +101,7 @@ func (e *encrMap) String() string {
|
||||
b := new(bytes.Buffer)
|
||||
for k, v := range e.nodes {
|
||||
b.WriteString("\n")
|
||||
b.WriteString(k)
|
||||
b.WriteString(k.String())
|
||||
b.WriteString(":")
|
||||
b.WriteString("[")
|
||||
for _, s := range v {
|
||||
@@ -112,7 +113,7 @@ func (e *encrMap) String() string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (d *driver) checkEncryption(nid string, rIP net.IP, isLocal, add bool) error {
|
||||
func (d *driver) checkEncryption(nid string, rIP netip.Addr, isLocal, add bool) error {
|
||||
log.G(context.TODO()).Debugf("checkEncryption(%.7s, %v, %t)", nid, rIP, isLocal)
|
||||
|
||||
n := d.network(nid)
|
||||
@@ -126,13 +127,13 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, isLocal, add bool) erro
|
||||
|
||||
lIP := d.bindAddress
|
||||
aIP := d.advertiseAddress
|
||||
nodes := map[string]net.IP{}
|
||||
nodes := map[netip.Addr]struct{}{}
|
||||
|
||||
switch {
|
||||
case isLocal:
|
||||
if err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
|
||||
if !aIP.Equal(pEntry.vtep) {
|
||||
nodes[pEntry.vtep.String()] = pEntry.vtep
|
||||
if err := d.peerDbNetworkWalk(nid, func(_ netip.Addr, _ net.HardwareAddr, pEntry *peerEntry) bool {
|
||||
if aIP != pEntry.vtep {
|
||||
nodes[pEntry.vtep] = struct{}{}
|
||||
}
|
||||
return false
|
||||
}); err != nil {
|
||||
@@ -140,14 +141,14 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, isLocal, add bool) erro
|
||||
}
|
||||
default:
|
||||
if len(d.network(nid).endpoints) > 0 {
|
||||
nodes[rIP.String()] = rIP
|
||||
nodes[rIP] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
log.G(context.TODO()).Debugf("List of nodes: %s", nodes)
|
||||
|
||||
if add {
|
||||
for _, rIP := range nodes {
|
||||
for rIP := range nodes {
|
||||
if err := setupEncryption(lIP, aIP, rIP, d.secMap, d.keys); err != nil {
|
||||
log.G(context.TODO()).Warnf("Failed to program network encryption between %s and %s: %v", lIP, rIP, err)
|
||||
}
|
||||
@@ -165,19 +166,18 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, isLocal, add bool) erro
|
||||
|
||||
// setupEncryption programs the encryption parameters for secure communication
|
||||
// between the local node and a remote node.
|
||||
func setupEncryption(localIP, advIP, remoteIP net.IP, em *encrMap, keys []*key) error {
|
||||
func setupEncryption(localIP, advIP, remoteIP netip.Addr, em *encrMap, keys []*key) error {
|
||||
log.G(context.TODO()).Debugf("Programming encryption between %s and %s", localIP, remoteIP)
|
||||
rIPs := remoteIP.String()
|
||||
|
||||
indices := make([]*spi, 0, len(keys))
|
||||
|
||||
for i, k := range keys {
|
||||
spis := &spi{buildSPI(advIP, remoteIP, k.tag), buildSPI(remoteIP, advIP, k.tag)}
|
||||
spis := &spi{buildSPI(advIP.AsSlice(), remoteIP.AsSlice(), k.tag), buildSPI(remoteIP.AsSlice(), advIP.AsSlice(), k.tag)}
|
||||
dir := reverse
|
||||
if i == 0 {
|
||||
dir = bidir
|
||||
}
|
||||
fSA, rSA, err := programSA(localIP, remoteIP, spis, k, dir, true)
|
||||
fSA, rSA, err := programSA(localIP.AsSlice(), remoteIP.AsSlice(), spis, k, dir, true)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).Warn(err)
|
||||
}
|
||||
@@ -192,15 +192,15 @@ func setupEncryption(localIP, advIP, remoteIP net.IP, em *encrMap, keys []*key)
|
||||
}
|
||||
|
||||
em.Lock()
|
||||
em.nodes[rIPs] = indices
|
||||
em.nodes[remoteIP] = indices
|
||||
em.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeEncryption(localIP, remoteIP net.IP, em *encrMap) error {
|
||||
func removeEncryption(localIP, remoteIP netip.Addr, em *encrMap) error {
|
||||
em.Lock()
|
||||
indices, ok := em.nodes[remoteIP.String()]
|
||||
indices, ok := em.nodes[remoteIP]
|
||||
em.Unlock()
|
||||
if !ok {
|
||||
return nil
|
||||
@@ -210,7 +210,7 @@ func removeEncryption(localIP, remoteIP net.IP, em *encrMap) error {
|
||||
if i == 0 {
|
||||
dir = bidir
|
||||
}
|
||||
fSA, rSA, err := programSA(localIP, remoteIP, idxs, nil, dir, false)
|
||||
fSA, rSA, err := programSA(localIP.AsSlice(), remoteIP.AsSlice(), idxs, nil, dir, false)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).Warn(err)
|
||||
}
|
||||
@@ -475,7 +475,7 @@ func buildAeadAlgo(k *key, s int) *netlink.XfrmStateAlgo {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) secMapWalk(f func(string, []*spi) ([]*spi, bool)) error {
|
||||
func (d *driver) secMapWalk(f func(netip.Addr, []*spi) ([]*spi, bool)) error {
|
||||
d.secMap.Lock()
|
||||
for node, indices := range d.secMap.nodes {
|
||||
idxs, stop := f(node, indices)
|
||||
@@ -496,7 +496,7 @@ func (d *driver) setKeys(keys []*key) error {
|
||||
// Accept the encryption keys and clear any stale encryption map
|
||||
d.Lock()
|
||||
d.keys = keys
|
||||
d.secMap = &encrMap{nodes: map[string][]*spi{}}
|
||||
d.secMap = &encrMap{nodes: map[netip.Addr][]*spi{}}
|
||||
d.Unlock()
|
||||
log.G(context.TODO()).Debugf("Initial encryption keys: %v", keys)
|
||||
return nil
|
||||
@@ -545,9 +545,8 @@ func (d *driver) updateKeys(newKey, primary, pruneKey *key) error {
|
||||
return types.InvalidParameterErrorf("attempting to both make a key (index %d) primary and delete it", priIdx)
|
||||
}
|
||||
|
||||
d.secMapWalk(func(rIPs string, spis []*spi) ([]*spi, bool) {
|
||||
rIP := net.ParseIP(rIPs)
|
||||
return updateNodeKey(lIP, aIP, rIP, spis, d.keys, newIdx, priIdx, delIdx), false
|
||||
d.secMapWalk(func(rIP netip.Addr, spis []*spi) ([]*spi, bool) {
|
||||
return updateNodeKey(lIP.AsSlice(), aIP.AsSlice(), rIP.AsSlice(), spis, d.keys, newIdx, priIdx, delIdx), false
|
||||
})
|
||||
|
||||
// swap primary
|
||||
|
||||
@@ -6,10 +6,12 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/libnetwork/driverapi"
|
||||
"github.com/docker/docker/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/libnetwork/ns"
|
||||
"github.com/docker/docker/libnetwork/osl"
|
||||
"github.com/docker/docker/libnetwork/types"
|
||||
@@ -95,7 +97,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
|
||||
if sub == s {
|
||||
continue
|
||||
}
|
||||
if err = jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil {
|
||||
if err = jinfo.AddStaticRoute(netiputil.ToIPNet(sub.subnetIP), types.NEXTHOP, s.gwIP.Addr().AsSlice()); err != nil {
|
||||
log.G(context.TODO()).Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id)
|
||||
}
|
||||
}
|
||||
@@ -107,9 +109,9 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
|
||||
}
|
||||
}
|
||||
|
||||
d.peerAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac, d.advertiseAddress, true)
|
||||
d.peerAdd(nid, eid, ep.addr, ep.mac, d.advertiseAddress, true)
|
||||
|
||||
if err = d.checkEncryption(nid, nil, true, true); err != nil {
|
||||
if err = d.checkEncryption(nid, netip.Addr{}, true, true); err != nil {
|
||||
log.G(context.TODO()).Warn(err)
|
||||
}
|
||||
|
||||
@@ -162,34 +164,34 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri
|
||||
|
||||
// Ignore local peers. We already know about them and they
|
||||
// should not be added to vxlan fdb.
|
||||
if net.ParseIP(peer.TunnelEndpointIP).Equal(d.advertiseAddress) {
|
||||
if addr, _ := netip.ParseAddr(peer.TunnelEndpointIP); addr == d.advertiseAddress {
|
||||
return
|
||||
}
|
||||
|
||||
addr, err := types.ParseCIDR(peer.EndpointIP)
|
||||
addr, err := netip.ParsePrefix(peer.EndpointIP)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP)
|
||||
log.G(context.TODO()).WithError(err).Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP)
|
||||
return
|
||||
}
|
||||
|
||||
mac, err := net.ParseMAC(peer.EndpointMAC)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).Errorf("Invalid mac %s received in event notify", peer.EndpointMAC)
|
||||
log.G(context.TODO()).WithError(err).Errorf("Invalid mac %s received in event notify", peer.EndpointMAC)
|
||||
return
|
||||
}
|
||||
|
||||
vtep := net.ParseIP(peer.TunnelEndpointIP)
|
||||
if vtep == nil {
|
||||
log.G(context.TODO()).Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP)
|
||||
vtep, err := netip.ParseAddr(peer.TunnelEndpointIP)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).WithError(err).Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP)
|
||||
return
|
||||
}
|
||||
|
||||
if etype == driverapi.Delete {
|
||||
d.peerDelete(nid, eid, addr.IP, addr.Mask, mac, vtep, false)
|
||||
d.peerDelete(nid, eid, addr, mac, vtep, false)
|
||||
return
|
||||
}
|
||||
|
||||
d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, false)
|
||||
d.peerAdd(nid, eid, addr, mac, vtep, false)
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
@@ -209,7 +211,7 @@ func (d *driver) Leave(nid, eid string) error {
|
||||
return types.InternalMaskableErrorf("could not find endpoint with id %s", eid)
|
||||
}
|
||||
|
||||
d.peerDelete(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac, d.advertiseAddress, true)
|
||||
d.peerDelete(nid, eid, ep.addr, ep.mac, d.advertiseAddress, true)
|
||||
|
||||
n.leaveSandbox()
|
||||
|
||||
|
||||
@@ -6,9 +6,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/libnetwork/driverapi"
|
||||
"github.com/docker/docker/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/libnetwork/netutils"
|
||||
"github.com/docker/docker/libnetwork/ns"
|
||||
)
|
||||
@@ -20,7 +22,7 @@ type endpoint struct {
|
||||
nid string
|
||||
ifName string
|
||||
mac net.HardwareAddr
|
||||
addr *net.IPNet
|
||||
addr netip.Prefix
|
||||
}
|
||||
|
||||
func (n *network) endpoint(eid string) *endpoint {
|
||||
@@ -61,12 +63,13 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
|
||||
}
|
||||
|
||||
ep := &endpoint{
|
||||
id: eid,
|
||||
nid: n.id,
|
||||
addr: ifInfo.Address(),
|
||||
mac: ifInfo.MacAddress(),
|
||||
id: eid,
|
||||
nid: n.id,
|
||||
mac: ifInfo.MacAddress(),
|
||||
}
|
||||
if ep.addr == nil {
|
||||
var ok bool
|
||||
ep.addr, ok = netiputil.ToPrefix(ifInfo.Address())
|
||||
if !ok {
|
||||
return fmt.Errorf("create endpoint was not passed interface IP address")
|
||||
}
|
||||
|
||||
@@ -75,7 +78,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
|
||||
}
|
||||
|
||||
if ep.mac == nil {
|
||||
ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
|
||||
ep.mac = netutils.GenerateMACFromIP(ep.addr.Addr().AsSlice())
|
||||
if err := ifInfo.SetMacAddress(ep.mac); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/libnetwork/driverapi"
|
||||
"github.com/docker/docker/libnetwork/drivers/overlay/overlayutils"
|
||||
"github.com/docker/docker/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
"github.com/docker/docker/libnetwork/ns"
|
||||
"github.com/docker/docker/libnetwork/osl"
|
||||
@@ -41,8 +42,8 @@ type subnet struct {
|
||||
brName string
|
||||
vni uint32
|
||||
initErr error
|
||||
subnetIP *net.IPNet
|
||||
gwIP *net.IPNet
|
||||
subnetIP netip.Prefix
|
||||
gwIP netip.Prefix
|
||||
}
|
||||
|
||||
type network struct {
|
||||
@@ -137,11 +138,9 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
||||
}
|
||||
|
||||
for i, ipd := range ipV4Data {
|
||||
s := &subnet{
|
||||
subnetIP: ipd.Pool,
|
||||
gwIP: ipd.Gateway,
|
||||
vni: vnis[i],
|
||||
}
|
||||
s := &subnet{vni: vnis[i]}
|
||||
s.subnetIP, _ = netiputil.ToPrefix(ipd.Pool)
|
||||
s.gwIP, _ = netiputil.ToPrefix(ipd.Gateway)
|
||||
|
||||
n.subnets = append(n.subnets, s)
|
||||
}
|
||||
@@ -425,7 +424,7 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
|
||||
// create a bridge and vxlan device for this subnet and move it to the sandbox
|
||||
sbox := n.sbox
|
||||
|
||||
if err := sbox.AddInterface(brName, "br", osl.WithIPv4Address(s.gwIP), osl.WithIsBridge(true)); err != nil {
|
||||
if err := sbox.AddInterface(brName, "br", osl.WithIPv4Address(netiputil.ToIPNet(s.gwIP)), osl.WithIsBridge(true)); err != nil {
|
||||
return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.String(), err)
|
||||
}
|
||||
|
||||
@@ -612,15 +611,13 @@ func (n *network) sandbox() *osl.Namespace {
|
||||
}
|
||||
|
||||
// getSubnetforIP returns the subnet to which the given IP belongs
|
||||
func (n *network) getSubnetforIP(ip *net.IPNet) *subnet {
|
||||
func (n *network) getSubnetforIP(ip netip.Prefix) *subnet {
|
||||
for _, s := range n.subnets {
|
||||
// first check if the mask lengths are the same
|
||||
i, _ := s.subnetIP.Mask.Size()
|
||||
j, _ := ip.Mask.Size()
|
||||
if i != j {
|
||||
if s.subnetIP.Bits() != ip.Bits() {
|
||||
continue
|
||||
}
|
||||
if s.subnetIP.Contains(ip.IP) {
|
||||
if s.subnetIP.Contains(ip.Addr()) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package overlay
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/log"
|
||||
@@ -28,7 +28,7 @@ const (
|
||||
var _ discoverapi.Discover = (*driver)(nil)
|
||||
|
||||
type driver struct {
|
||||
bindAddress, advertiseAddress net.IP
|
||||
bindAddress, advertiseAddress netip.Addr
|
||||
|
||||
config map[string]interface{}
|
||||
peerDb peerNetworkMap
|
||||
@@ -48,7 +48,7 @@ func Register(r driverapi.Registerer, config map[string]interface{}) error {
|
||||
peerDb: peerNetworkMap{
|
||||
mp: map[string]*peerMap{},
|
||||
},
|
||||
secMap: &encrMap{nodes: map[string][]*spi{}},
|
||||
secMap: &encrMap{nodes: map[netip.Addr][]*spi{}},
|
||||
config: config,
|
||||
}
|
||||
return r.RegisterDriver(NetworkType, d, driverapi.Capability{
|
||||
@@ -78,16 +78,17 @@ func (d *driver) isIPv6Transport() (bool, error) {
|
||||
// from the address family of our own advertise address. This is a
|
||||
// reasonable inference to make as Linux VXLAN links do not support
|
||||
// mixed-address-family remote peers.
|
||||
if d.advertiseAddress == nil {
|
||||
if !d.advertiseAddress.IsValid() {
|
||||
return false, fmt.Errorf("overlay: cannot determine address family of transport: the local data-plane address is not currently known")
|
||||
}
|
||||
return d.advertiseAddress.To4() == nil, nil
|
||||
return d.advertiseAddress.Is6(), nil
|
||||
}
|
||||
|
||||
func (d *driver) nodeJoin(data discoverapi.NodeDiscoveryData) error {
|
||||
if data.Self {
|
||||
advAddr, bindAddr := net.ParseIP(data.Address), net.ParseIP(data.BindAddress)
|
||||
if advAddr == nil {
|
||||
advAddr, _ := netip.ParseAddr(data.Address)
|
||||
bindAddr, _ := netip.ParseAddr(data.BindAddress)
|
||||
if !advAddr.IsValid() {
|
||||
return fmt.Errorf("invalid discovery data")
|
||||
}
|
||||
d.Lock()
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
@@ -17,52 +18,16 @@ import (
|
||||
|
||||
const ovPeerTable = "overlay_peer_table"
|
||||
|
||||
type peerKey struct {
|
||||
peerIP net.IP
|
||||
peerMac net.HardwareAddr
|
||||
}
|
||||
|
||||
type peerEntry struct {
|
||||
eid string
|
||||
vtep net.IP
|
||||
peerIPMask net.IPMask
|
||||
vtep netip.Addr
|
||||
prefixBits int // number of 1-bits in network mask of peerIP
|
||||
isLocal bool
|
||||
}
|
||||
|
||||
func (p *peerEntry) MarshalDB() peerEntryDB {
|
||||
ones, bits := p.peerIPMask.Size()
|
||||
return peerEntryDB{
|
||||
eid: p.eid,
|
||||
vtep: p.vtep.String(),
|
||||
peerIPMaskOnes: ones,
|
||||
peerIPMaskBits: bits,
|
||||
isLocal: p.isLocal,
|
||||
}
|
||||
}
|
||||
|
||||
// This the structure saved into the set (SetMatrix), due to the implementation of it
|
||||
// the value inserted in the set has to be Hashable so the []byte had to be converted into
|
||||
// strings
|
||||
type peerEntryDB struct {
|
||||
eid string
|
||||
vtep string
|
||||
peerIPMaskOnes int
|
||||
peerIPMaskBits int
|
||||
isLocal bool
|
||||
}
|
||||
|
||||
func (p *peerEntryDB) UnMarshalDB() peerEntry {
|
||||
return peerEntry{
|
||||
eid: p.eid,
|
||||
vtep: net.ParseIP(p.vtep),
|
||||
peerIPMask: net.CIDRMask(p.peerIPMaskOnes, p.peerIPMaskBits),
|
||||
isLocal: p.isLocal,
|
||||
}
|
||||
}
|
||||
|
||||
type peerMap struct {
|
||||
// set of peerEntry, note the values have to be objects and not pointers to maintain the proper equality checks
|
||||
mp setmatrix.SetMatrix[string, peerEntryDB]
|
||||
mp setmatrix.SetMatrix[ipmac, peerEntry]
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@@ -72,28 +37,7 @@ type peerNetworkMap struct {
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (pKey peerKey) String() string {
|
||||
return fmt.Sprintf("%s %s", pKey.peerIP, pKey.peerMac)
|
||||
}
|
||||
|
||||
func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
|
||||
ipB, err := state.Token(true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pKey.peerIP = net.ParseIP(string(ipB))
|
||||
|
||||
macB, err := state.Token(true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pKey.peerMac, err = net.ParseMAC(string(macB))
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *driver) peerDbWalk(f func(string, *peerKey, *peerEntry) bool) error {
|
||||
func (d *driver) peerDbWalk(f func(string, netip.Addr, net.HardwareAddr, *peerEntry) bool) error {
|
||||
d.peerDb.Lock()
|
||||
nids := []string{}
|
||||
for nid := range d.peerDb.mp {
|
||||
@@ -102,14 +46,14 @@ func (d *driver) peerDbWalk(f func(string, *peerKey, *peerEntry) bool) error {
|
||||
d.peerDb.Unlock()
|
||||
|
||||
for _, nid := range nids {
|
||||
d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
|
||||
return f(nid, pKey, pEntry)
|
||||
d.peerDbNetworkWalk(nid, func(peerIP netip.Addr, peerMac net.HardwareAddr, pEntry *peerEntry) bool {
|
||||
return f(nid, peerIP, peerMac, pEntry)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool) error {
|
||||
func (d *driver) peerDbNetworkWalk(nid string, f func(netip.Addr, net.HardwareAddr, *peerEntry) bool) error {
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
d.peerDb.Unlock()
|
||||
@@ -118,24 +62,18 @@ func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool
|
||||
return nil
|
||||
}
|
||||
|
||||
mp := map[string]peerEntry{}
|
||||
mp := map[ipmac]peerEntry{}
|
||||
pMap.Lock()
|
||||
for _, pKeyStr := range pMap.mp.Keys() {
|
||||
entryDBList, ok := pMap.mp.Get(pKeyStr)
|
||||
for _, pKey := range pMap.mp.Keys() {
|
||||
entryDBList, ok := pMap.mp.Get(pKey)
|
||||
if ok {
|
||||
peerEntryDB := entryDBList[0]
|
||||
mp[pKeyStr] = peerEntryDB.UnMarshalDB()
|
||||
mp[pKey] = entryDBList[0]
|
||||
}
|
||||
}
|
||||
pMap.Unlock()
|
||||
|
||||
for pKeyStr, pEntry := range mp {
|
||||
var pKey peerKey
|
||||
pEntry := pEntry
|
||||
if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil {
|
||||
log.G(context.TODO()).Warnf("Peer key scan on network %s failed: %v", nid, err)
|
||||
}
|
||||
if f(&pKey, &pEntry) {
|
||||
for pKey, pEntry := range mp {
|
||||
if f(pKey.ip, pKey.mac.HardwareAddr(), &pEntry) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -143,12 +81,14 @@ func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbSearch(nid string, peerIP net.IP) (*peerKey, *peerEntry, error) {
|
||||
var pKeyMatched *peerKey
|
||||
func (d *driver) peerDbSearch(nid string, peerIP netip.Addr) (netip.Addr, net.HardwareAddr, *peerEntry, error) {
|
||||
var peerIPMatched netip.Addr
|
||||
var peerMacMatched net.HardwareAddr
|
||||
var pEntryMatched *peerEntry
|
||||
err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
|
||||
if pKey.peerIP.Equal(peerIP) {
|
||||
pKeyMatched = pKey
|
||||
err := d.peerDbNetworkWalk(nid, func(ip netip.Addr, mac net.HardwareAddr, pEntry *peerEntry) bool {
|
||||
if ip == peerIP {
|
||||
peerIPMatched = ip
|
||||
peerMacMatched = mac
|
||||
pEntryMatched = pEntry
|
||||
return true
|
||||
}
|
||||
@@ -156,17 +96,17 @@ func (d *driver) peerDbSearch(nid string, peerIP net.IP) (*peerKey, *peerEntry,
|
||||
return false
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err)
|
||||
return netip.Addr{}, nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err)
|
||||
}
|
||||
|
||||
if pKeyMatched == nil || pEntryMatched == nil {
|
||||
return nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP)
|
||||
if !peerIPMatched.IsValid() || pEntryMatched == nil {
|
||||
return netip.Addr{}, nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP)
|
||||
}
|
||||
|
||||
return pKeyMatched, pEntryMatched, nil
|
||||
return peerIPMatched, peerMacMatched, pEntryMatched, nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, isLocal bool) (bool, int) {
|
||||
func (d *driver) peerDbAdd(nid, eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr, isLocal bool) (bool, int) {
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
@@ -175,30 +115,27 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
|
||||
}
|
||||
d.peerDb.Unlock()
|
||||
|
||||
pKey := peerKey{
|
||||
peerIP: peerIP,
|
||||
peerMac: peerMac,
|
||||
}
|
||||
pKey := ipmacOf(peerIP.Addr(), peerMac)
|
||||
|
||||
pEntry := peerEntry{
|
||||
eid: eid,
|
||||
vtep: vtep,
|
||||
peerIPMask: peerIPMask,
|
||||
prefixBits: peerIP.Bits(),
|
||||
isLocal: isLocal,
|
||||
}
|
||||
|
||||
pMap.Lock()
|
||||
defer pMap.Unlock()
|
||||
b, i := pMap.mp.Insert(pKey.String(), pEntry.MarshalDB())
|
||||
b, i := pMap.mp.Insert(pKey, pEntry)
|
||||
if i != 1 {
|
||||
// Transient case, there is more than one endpoint that is using the same IP,MAC pair
|
||||
s, _ := pMap.mp.String(pKey.String())
|
||||
s, _ := pMap.mp.String(pKey)
|
||||
log.G(context.TODO()).Warnf("peerDbAdd transient condition - Key:%s cardinality:%d db state:%s", pKey.String(), i, s)
|
||||
}
|
||||
return b, i
|
||||
}
|
||||
|
||||
func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, isLocal bool) (bool, int) {
|
||||
func (d *driver) peerDbDelete(nid, eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr, isLocal bool) (bool, int) {
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
@@ -207,25 +144,22 @@ func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPM
|
||||
}
|
||||
d.peerDb.Unlock()
|
||||
|
||||
pKey := peerKey{
|
||||
peerIP: peerIP,
|
||||
peerMac: peerMac,
|
||||
}
|
||||
pKey := ipmacOf(peerIP.Addr(), peerMac)
|
||||
|
||||
pEntry := peerEntry{
|
||||
eid: eid,
|
||||
vtep: vtep,
|
||||
peerIPMask: peerIPMask,
|
||||
prefixBits: peerIP.Bits(),
|
||||
isLocal: isLocal,
|
||||
}
|
||||
|
||||
pMap.Lock()
|
||||
defer pMap.Unlock()
|
||||
b, i := pMap.mp.Remove(pKey.String(), pEntry.MarshalDB())
|
||||
b, i := pMap.mp.Remove(pKey, pEntry)
|
||||
if i != 0 {
|
||||
// Transient case, there is more than one endpoint that is using the same IP,MAC pair
|
||||
s, _ := pMap.mp.String(pKey.String())
|
||||
log.G(context.TODO()).Warnf("peerDbDelete transient condition - Key:%s cardinality:%d db state:%s", pKey.String(), i, s)
|
||||
s, _ := pMap.mp.String(pKey)
|
||||
log.G(context.TODO()).Warnf("peerDbDelete transient condition - Key:%s cardinality:%d db state:%s", pKey, i, s)
|
||||
}
|
||||
return b, i
|
||||
}
|
||||
@@ -250,28 +184,28 @@ func (d *driver) initSandboxPeerDB(nid string) {
|
||||
}
|
||||
|
||||
func (d *driver) peerInitOp(nid string) error {
|
||||
return d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
|
||||
return d.peerDbNetworkWalk(nid, func(peerIP netip.Addr, peerMac net.HardwareAddr, pEntry *peerEntry) bool {
|
||||
// Local entries do not need to be added
|
||||
if pEntry.isLocal {
|
||||
return false
|
||||
}
|
||||
|
||||
d.peerAddOp(nid, pEntry.eid, pKey.peerIP, pEntry.peerIPMask, pKey.peerMac, pEntry.vtep, false, pEntry.isLocal)
|
||||
d.peerAddOp(nid, pEntry.eid, netip.PrefixFrom(peerIP, pEntry.prefixBits), peerMac, pEntry.vtep, false, pEntry.isLocal)
|
||||
// return false to loop on all entries
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, localPeer bool) {
|
||||
func (d *driver) peerAdd(nid, eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr, localPeer bool) {
|
||||
d.peerOpMu.Lock()
|
||||
defer d.peerOpMu.Unlock()
|
||||
err := d.peerAddOp(nid, eid, peerIP, peerIPMask, peerMac, vtep, true, localPeer)
|
||||
err := d.peerAddOp(nid, eid, peerIP, peerMac, vtep, true, localPeer)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).WithError(err).Warn("Peer add operation failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) peerAddOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, updateDB, localPeer bool) error {
|
||||
func (d *driver) peerAddOp(nid, eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr, updateDB, localPeer bool) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -279,7 +213,7 @@ func (d *driver) peerAddOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
|
||||
var dbEntries int
|
||||
var inserted bool
|
||||
if updateDB {
|
||||
inserted, dbEntries = d.peerDbAdd(nid, eid, peerIP, peerIPMask, peerMac, vtep, localPeer)
|
||||
inserted, dbEntries = d.peerDbAdd(nid, eid, peerIP, peerMac, vtep, localPeer)
|
||||
if !inserted {
|
||||
log.G(context.TODO()).Warnf("Entry already present in db: nid:%s eid:%s peerIP:%v peerMac:%v isLocal:%t vtep:%v",
|
||||
nid, eid, peerIP, peerMac, localPeer, vtep)
|
||||
@@ -304,14 +238,9 @@ func (d *driver) peerAddOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
|
||||
return nil
|
||||
}
|
||||
|
||||
IP := &net.IPNet{
|
||||
IP: peerIP,
|
||||
Mask: peerIPMask,
|
||||
}
|
||||
|
||||
s := n.getSubnetforIP(IP)
|
||||
s := n.getSubnetforIP(peerIP)
|
||||
if s == nil {
|
||||
return fmt.Errorf("couldn't find the subnet %q in network %q", IP.String(), n.id)
|
||||
return fmt.Errorf("couldn't find the subnet %q in network %q", peerIP.String(), n.id)
|
||||
}
|
||||
|
||||
if err := n.joinSandbox(s, false); err != nil {
|
||||
@@ -323,7 +252,7 @@ func (d *driver) peerAddOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
|
||||
}
|
||||
|
||||
// Add neighbor entry for the peer IP
|
||||
if err := sbox.AddNeighbor(peerIP, peerMac, osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
if err := sbox.AddNeighbor(peerIP.Addr().AsSlice(), peerMac, osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
if _, ok := err.(osl.NeighborSearchError); ok && dbEntries > 1 {
|
||||
// We are in the transient case so only the first configuration is programmed into the kernel
|
||||
// Upon deletion if the active configuration is deleted the next one from the database will be restored
|
||||
@@ -334,28 +263,28 @@ func (d *driver) peerAddOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
|
||||
}
|
||||
|
||||
// Add fdb entry to the bridge for the peer mac
|
||||
if err := sbox.AddNeighbor(vtep, peerMac, osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
if err := sbox.AddNeighbor(vtep.AsSlice(), peerMac, osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
return fmt.Errorf("could not add fdb entry for nid:%s eid:%s into the sandbox:%v", nid, eid, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, localPeer bool) {
|
||||
func (d *driver) peerDelete(nid, eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr, localPeer bool) {
|
||||
d.peerOpMu.Lock()
|
||||
defer d.peerOpMu.Unlock()
|
||||
err := d.peerDeleteOp(nid, eid, peerIP, peerIPMask, peerMac, vtep, localPeer)
|
||||
err := d.peerDeleteOp(nid, eid, peerIP, peerMac, vtep, localPeer)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).WithError(err).Warn("Peer delete operation failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) peerDeleteOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, peerMac net.HardwareAddr, vtep net.IP, localPeer bool) error {
|
||||
func (d *driver) peerDeleteOp(nid, eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr, localPeer bool) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deleted, dbEntries := d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep, localPeer)
|
||||
deleted, dbEntries := d.peerDbDelete(nid, eid, peerIP, peerMac, vtep, localPeer)
|
||||
if !deleted {
|
||||
log.G(context.TODO()).Warnf("Entry was not in db: nid:%s eid:%s peerIP:%v peerMac:%v isLocal:%t vtep:%v",
|
||||
nid, eid, peerIP, peerMac, localPeer, vtep)
|
||||
@@ -377,16 +306,12 @@ func (d *driver) peerDeleteOp(nid, eid string, peerIP net.IP, peerIPMask net.IPM
|
||||
|
||||
// Local peers do not have any local configuration to delete
|
||||
if !localPeer {
|
||||
IP := &net.IPNet{
|
||||
IP: peerIP,
|
||||
Mask: peerIPMask,
|
||||
}
|
||||
s := n.getSubnetforIP(IP)
|
||||
s := n.getSubnetforIP(peerIP)
|
||||
if s == nil {
|
||||
return fmt.Errorf("could not find the subnet %q in network %q", IP.String(), n.id)
|
||||
return fmt.Errorf("could not find the subnet %q in network %q", peerIP.String(), n.id)
|
||||
}
|
||||
// Remove fdb entry to the bridge for the peer mac
|
||||
if err := sbox.DeleteNeighbor(vtep, peerMac, osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
if err := sbox.DeleteNeighbor(vtep.AsSlice(), peerMac, osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
if _, ok := err.(osl.NeighborSearchError); ok && dbEntries > 0 {
|
||||
// We fall in here if there is a transient state and if the neighbor that is being deleted
|
||||
// was never been configured into the kernel (we allow only 1 configuration at the time per <ip,mac> mapping)
|
||||
@@ -396,7 +321,7 @@ func (d *driver) peerDeleteOp(nid, eid string, peerIP net.IP, peerIPMask net.IPM
|
||||
}
|
||||
|
||||
// Delete neighbor entry for the peer IP
|
||||
if err := sbox.DeleteNeighbor(peerIP, peerMac, osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
if err := sbox.DeleteNeighbor(peerIP.Addr().AsSlice(), peerMac, osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
return fmt.Errorf("could not delete neighbor entry for nid:%s eid:%s into the sandbox:%v", nid, eid, err)
|
||||
}
|
||||
}
|
||||
@@ -408,12 +333,12 @@ func (d *driver) peerDeleteOp(nid, eid string, peerIP net.IP, peerIPMask net.IPM
|
||||
// If there is still an entry into the database and the deletion went through without errors means that there is now no
|
||||
// configuration active in the kernel.
|
||||
// Restore one configuration for the <ip,mac> directly from the database, note that is guaranteed that there is one
|
||||
peerKey, peerEntry, err := d.peerDbSearch(nid, peerIP)
|
||||
peerIPAddr, peerMac, peerEntry, err := d.peerDbSearch(nid, peerIP.Addr())
|
||||
if err != nil {
|
||||
log.G(context.TODO()).Errorf("peerDeleteOp unable to restore a configuration for nid:%s ip:%v mac:%v err:%s", nid, peerIP, peerMac, err)
|
||||
return err
|
||||
}
|
||||
return d.peerAddOp(nid, peerEntry.eid, peerIP, peerEntry.peerIPMask, peerKey.peerMac, peerEntry.vtep, false, peerEntry.isLocal)
|
||||
return d.peerAddOp(nid, peerEntry.eid, netip.PrefixFrom(peerIPAddr, peerEntry.prefixBits), peerMac, peerEntry.vtep, false, peerEntry.isLocal)
|
||||
}
|
||||
|
||||
func (d *driver) peerFlush(nid string) {
|
||||
@@ -436,7 +361,7 @@ func (d *driver) peerFlushOp(nid string) error {
|
||||
}
|
||||
|
||||
func (d *driver) peerDBUpdateSelf() {
|
||||
d.peerDbWalk(func(nid string, pkey *peerKey, pEntry *peerEntry) bool {
|
||||
d.peerDbWalk(func(nid string, _ netip.Addr, _ net.HardwareAddr, pEntry *peerEntry) bool {
|
||||
if pEntry.isLocal {
|
||||
pEntry.vtep = d.advertiseAddress
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
//go:build linux
|
||||
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPeerMarshal(t *testing.T) {
|
||||
_, ipNet, _ := net.ParseCIDR("192.168.0.1/24")
|
||||
p := &peerEntry{
|
||||
eid: "eid",
|
||||
isLocal: true,
|
||||
peerIPMask: ipNet.Mask,
|
||||
vtep: ipNet.IP,
|
||||
}
|
||||
entryDB := p.MarshalDB()
|
||||
x := entryDB.UnMarshalDB()
|
||||
if x.eid != p.eid {
|
||||
t.Fatalf("Incorrect Unmarshalling for eid: %v != %v", x.eid, p.eid)
|
||||
}
|
||||
if x.isLocal != p.isLocal {
|
||||
t.Fatalf("Incorrect Unmarshalling for isLocal: %v != %v", x.isLocal, p.isLocal)
|
||||
}
|
||||
if x.peerIPMask.String() != p.peerIPMask.String() {
|
||||
t.Fatalf("Incorrect Unmarshalling for eid: %v != %v", x.peerIPMask, p.peerIPMask)
|
||||
}
|
||||
if x.vtep.String() != p.vtep.String() {
|
||||
t.Fatalf("Incorrect Unmarshalling for eid: %v != %v", x.vtep, p.vtep)
|
||||
}
|
||||
}
|
||||
52
libnetwork/drivers/overlay/types.go
Normal file
52
libnetwork/drivers/overlay/types.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package overlay
|
||||
|
||||
// Handy utility types for making unhashable values hashable.
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
// macAddr is a hashable encoding of a MAC address.
|
||||
type macAddr uint64
|
||||
|
||||
// macAddrOf converts a net.HardwareAddr to a macAddr.
|
||||
func macAddrOf(mac net.HardwareAddr) macAddr {
|
||||
if len(mac) != 6 {
|
||||
return 0
|
||||
}
|
||||
return macAddr(mac[0])<<40 | macAddr(mac[1])<<32 | macAddr(mac[2])<<24 |
|
||||
macAddr(mac[3])<<16 | macAddr(mac[4])<<8 | macAddr(mac[5])
|
||||
}
|
||||
|
||||
// HardwareAddr converts a macAddr back to a net.HardwareAddr.
|
||||
func (p macAddr) HardwareAddr() net.HardwareAddr {
|
||||
mac := [6]byte{
|
||||
byte(p >> 40), byte(p >> 32), byte(p >> 24),
|
||||
byte(p >> 16), byte(p >> 8), byte(p),
|
||||
}
|
||||
return mac[:]
|
||||
}
|
||||
|
||||
// String returns p.HardwareAddr().String().
|
||||
func (p macAddr) String() string {
|
||||
return p.HardwareAddr().String()
|
||||
}
|
||||
|
||||
// ipmac is a hashable tuple of an IP address and a MAC address suitable for use as a map key.
|
||||
type ipmac struct {
|
||||
ip netip.Addr
|
||||
mac macAddr
|
||||
}
|
||||
|
||||
// ipmacOf is a convenience constructor for creating an ipmac from a [net.HardwareAddr].
|
||||
func ipmacOf(ip netip.Addr, mac net.HardwareAddr) ipmac {
|
||||
return ipmac{
|
||||
ip: ip,
|
||||
mac: macAddrOf(mac),
|
||||
}
|
||||
}
|
||||
|
||||
func (i ipmac) String() string {
|
||||
return i.ip.String() + " " + i.mac.String()
|
||||
}
|
||||
29
libnetwork/drivers/overlay/types_test.go
Normal file
29
libnetwork/drivers/overlay/types_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestMACAddrOf(t *testing.T) {
|
||||
want := net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
|
||||
assert.DeepEqual(t, macAddrOf(want).HardwareAddr(), want)
|
||||
}
|
||||
|
||||
func TestIPMACOf(t *testing.T) {
|
||||
assert.Check(t, is.Equal(ipmacOf(netip.Addr{}, nil), ipmac{}))
|
||||
assert.Check(t, is.Equal(
|
||||
ipmacOf(
|
||||
netip.MustParseAddr("11.22.33.44"),
|
||||
net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
|
||||
),
|
||||
ipmac{
|
||||
ip: netip.MustParseAddr("11.22.33.44"),
|
||||
mac: macAddrOf(net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}),
|
||||
},
|
||||
))
|
||||
}
|
||||
Reference in New Issue
Block a user