mirror of
https://github.com/moby/moby.git
synced 2026-07-23 07:51:53 +00:00
libn/d/overlay: extract hashable address types
The macAddr and ipmac types are generally useful within libnetwork. Move them to a dedicated package and overhaul the API to be more like that of the net/netip package. Update the overlay driver to utilize these types, adapting to the new API. Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
@@ -6,12 +6,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/daemon/libnetwork/driverapi"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/hashable"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/daemon/libnetwork/netlabel"
|
||||
"github.com/docker/docker/daemon/libnetwork/ns"
|
||||
@@ -104,7 +104,7 @@ func (d *driver) Join(ctx context.Context, nid, eid string, sboxKey string, jinf
|
||||
return err
|
||||
}
|
||||
|
||||
if err = nlh.LinkSetHardwareAddr(veth, ep.mac); err != nil {
|
||||
if err = nlh.LinkSetHardwareAddr(veth, ep.mac.AsSlice()); err != nil {
|
||||
return fmt.Errorf("could not set mac address (%v) to the container interface: %v", ep.mac, err)
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri
|
||||
return
|
||||
}
|
||||
|
||||
mac, err := net.ParseMAC(peer.EndpointMAC)
|
||||
mac, err := hashable.ParseMAC(peer.EndpointMAC)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).WithError(err).Errorf("Invalid mac %s received in event notify", peer.EndpointMAC)
|
||||
return
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/daemon/libnetwork/driverapi"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/hashable"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/daemon/libnetwork/netutils"
|
||||
"github.com/docker/docker/daemon/libnetwork/ns"
|
||||
@@ -22,7 +22,7 @@ type endpoint struct {
|
||||
id string
|
||||
nid string
|
||||
ifName string
|
||||
mac net.HardwareAddr
|
||||
mac hashable.MACAddr
|
||||
addr netip.Prefix
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ func (d *driver) CreateEndpoint(_ context.Context, nid, eid string, ifInfo drive
|
||||
ep := &endpoint{
|
||||
id: eid,
|
||||
nid: n.id,
|
||||
mac: ifInfo.MacAddress(),
|
||||
}
|
||||
var ok bool
|
||||
ep.addr, ok = netiputil.ToPrefix(ifInfo.Address())
|
||||
@@ -60,9 +59,19 @@ func (d *driver) CreateEndpoint(_ context.Context, nid, eid string, ifInfo drive
|
||||
return fmt.Errorf("no matching subnet for IP %q in network %q", ep.addr, nid)
|
||||
}
|
||||
|
||||
if ep.mac == nil {
|
||||
ep.mac = netutils.GenerateMACFromIP(ep.addr.Addr().AsSlice())
|
||||
if err := ifInfo.SetMacAddress(ep.mac); err != nil {
|
||||
if ifmac := ifInfo.MacAddress(); ifmac != nil {
|
||||
var ok bool
|
||||
ep.mac, ok = hashable.MACAddrFromSlice(ifInfo.MacAddress())
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid MAC address %q assigned to endpoint: unexpected length", ifmac)
|
||||
}
|
||||
} else {
|
||||
var ok bool
|
||||
ep.mac, ok = hashable.MACAddrFromSlice(netutils.GenerateMACFromIP(ep.addr.Addr().AsSlice()))
|
||||
if !ok {
|
||||
panic("GenerateMACFromIP returned a HardwareAddress that is not a MAC-48")
|
||||
}
|
||||
if err := ifInfo.SetMacAddress(ep.mac.AsSlice()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/docker/docker/daemon/libnetwork/driverapi"
|
||||
"github.com/docker/docker/daemon/libnetwork/drivers/overlay/overlayutils"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/countmap"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/hashable"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/netiputil"
|
||||
"github.com/docker/docker/daemon/libnetwork/netlabel"
|
||||
"github.com/docker/docker/daemon/libnetwork/ns"
|
||||
@@ -65,7 +66,7 @@ type network struct {
|
||||
endpoints endpointTable
|
||||
joinCnt int
|
||||
// Ref count of VXLAN Forwarding Database entries programmed into the kernel
|
||||
fdbCnt countmap.Map[ipmac]
|
||||
fdbCnt countmap.Map[hashable.IPMAC]
|
||||
sboxInit bool
|
||||
initEpoch int
|
||||
initErr error
|
||||
@@ -110,7 +111,7 @@ func (d *driver) CreateNetwork(ctx context.Context, id string, option map[string
|
||||
driver: d,
|
||||
endpoints: endpointTable{},
|
||||
subnets: []*subnet{},
|
||||
fdbCnt: countmap.Map[ipmac]{},
|
||||
fdbCnt: countmap.Map[hashable.IPMAC]{},
|
||||
}
|
||||
|
||||
vnis := make([]uint32, 0, len(ipV4Data))
|
||||
@@ -607,7 +608,7 @@ func (n *network) initSandbox() error {
|
||||
|
||||
// this is needed to let the peerAdd configure the sandbox
|
||||
n.sbox = sbox
|
||||
n.fdbCnt = countmap.Map[ipmac]{}
|
||||
n.fdbCnt = countmap.Map[hashable.IPMAC]{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/hashable"
|
||||
"github.com/docker/docker/daemon/libnetwork/internal/setmatrix"
|
||||
"github.com/docker/docker/daemon/libnetwork/osl"
|
||||
)
|
||||
@@ -20,7 +20,7 @@ const ovPeerTable = "overlay_peer_table"
|
||||
|
||||
type peerEntry struct {
|
||||
eid string
|
||||
mac macAddr
|
||||
mac hashable.MACAddr
|
||||
vtep netip.Addr
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ func (pm *peerMap) Get(peerIP netip.Prefix) (peerEntry, bool) {
|
||||
return c[0], true
|
||||
}
|
||||
|
||||
func (pm *peerMap) Add(eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr) (bool, int) {
|
||||
func (pm *peerMap) Add(eid string, peerIP netip.Prefix, peerMac hashable.MACAddr, vtep netip.Addr) (bool, int) {
|
||||
pEntry := peerEntry{
|
||||
eid: eid,
|
||||
mac: macAddrOf(peerMac),
|
||||
mac: peerMac,
|
||||
vtep: vtep,
|
||||
}
|
||||
b, i := pm.mp.Insert(peerIP, pEntry)
|
||||
@@ -64,10 +64,10 @@ func (pm *peerMap) Add(eid string, peerIP netip.Prefix, peerMac net.HardwareAddr
|
||||
return b, i
|
||||
}
|
||||
|
||||
func (pm *peerMap) Delete(eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr) (bool, int) {
|
||||
func (pm *peerMap) Delete(eid string, peerIP netip.Prefix, peerMac hashable.MACAddr, vtep netip.Addr) (bool, int) {
|
||||
pEntry := peerEntry{
|
||||
eid: eid,
|
||||
mac: macAddrOf(peerMac),
|
||||
mac: peerMac,
|
||||
vtep: vtep,
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func (n *network) initSandboxPeerDB() error {
|
||||
var errs []error
|
||||
n.peerdb.Walk(func(peerIP netip.Prefix, pEntry peerEntry) {
|
||||
if !pEntry.isLocal() {
|
||||
if err := n.addNeighbor(peerIP, pEntry.mac.HardwareAddr(), pEntry.vtep); err != nil {
|
||||
if err := n.addNeighbor(peerIP, pEntry.mac, pEntry.vtep); err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to add neighbor entries for %s: %w", peerIP, err))
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ func (n *network) initSandboxPeerDB() error {
|
||||
// peerAdd adds a new entry to the peer database.
|
||||
//
|
||||
// Local peers are signified by an invalid vtep (i.e. netip.Addr{}).
|
||||
func (n *network) peerAdd(eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr) error {
|
||||
func (n *network) peerAdd(eid string, peerIP netip.Prefix, peerMac hashable.MACAddr, vtep netip.Addr) error {
|
||||
if eid == "" {
|
||||
return errors.New("invalid endpoint id")
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func (n *network) peerAdd(eid string, peerIP netip.Prefix, peerMac net.HardwareA
|
||||
}
|
||||
|
||||
// addNeighbor programs the kernel so the given peer is reachable through the VXLAN tunnel.
|
||||
func (n *network) addNeighbor(peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr) error {
|
||||
func (n *network) addNeighbor(peerIP netip.Prefix, peerMac hashable.MACAddr, vtep netip.Addr) error {
|
||||
if n.sbox == nil {
|
||||
// We are hitting this case for all the events that are arriving before that the sandbox
|
||||
// is being created. The peer got already added into the database and the sandbox init will
|
||||
@@ -154,13 +154,13 @@ func (n *network) addNeighbor(peerIP netip.Prefix, peerMac net.HardwareAddr, vte
|
||||
}
|
||||
|
||||
// Add neighbor entry for the peer IP
|
||||
if err := n.sbox.AddNeighbor(peerIP.Addr().AsSlice(), peerMac, osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
if err := n.sbox.AddNeighbor(peerIP.Addr().AsSlice(), peerMac.AsSlice(), osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
return fmt.Errorf("could not add neighbor entry into the sandbox: %w", err)
|
||||
}
|
||||
|
||||
// Add fdb entry to the bridge for the peer mac
|
||||
if n.fdbCnt.Add(ipmacOf(vtep, peerMac), 1) == 1 {
|
||||
if err := n.sbox.AddNeighbor(vtep.AsSlice(), peerMac, osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
if n.fdbCnt.Add(hashable.IPMACFrom(vtep, peerMac), 1) == 1 {
|
||||
if err := n.sbox.AddNeighbor(vtep.AsSlice(), peerMac.AsSlice(), osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
return fmt.Errorf("could not add fdb entry into the sandbox: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ func (n *network) addNeighbor(peerIP netip.Prefix, peerMac net.HardwareAddr, vte
|
||||
// peerDelete removes an entry from the peer database.
|
||||
//
|
||||
// Local peers are signified by an invalid vtep (i.e. netip.Addr{}).
|
||||
func (n *network) peerDelete(eid string, peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr) error {
|
||||
func (n *network) peerDelete(eid string, peerIP netip.Prefix, peerMac hashable.MACAddr, vtep netip.Addr) error {
|
||||
if eid == "" {
|
||||
return errors.New("invalid endpoint id")
|
||||
}
|
||||
@@ -207,7 +207,7 @@ func (n *network) peerDelete(eid string, peerIP netip.Prefix, peerMac net.Hardwa
|
||||
if !ok {
|
||||
return fmt.Errorf("peerDelete: unable to restore a configuration: no entry for %v found in the database", peerIP)
|
||||
}
|
||||
err := n.addNeighbor(peerIP, peerEntry.mac.HardwareAddr(), peerEntry.vtep)
|
||||
err := n.addNeighbor(peerIP, peerEntry.mac, peerEntry.vtep)
|
||||
if err != nil {
|
||||
return fmt.Errorf("peer delete operation failed: %w", err)
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func (n *network) peerDelete(eid string, peerIP netip.Prefix, peerMac net.Hardwa
|
||||
|
||||
// deleteNeighbor removes programming from the kernel for the given peer to be
|
||||
// reachable through the VXLAN tunnel. It is the inverse of [driver.addNeighbor].
|
||||
func (n *network) deleteNeighbor(peerIP netip.Prefix, peerMac net.HardwareAddr, vtep netip.Addr) error {
|
||||
func (n *network) deleteNeighbor(peerIP netip.Prefix, peerMac hashable.MACAddr, vtep netip.Addr) error {
|
||||
if n.sbox == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -233,14 +233,14 @@ func (n *network) deleteNeighbor(peerIP netip.Prefix, peerMac net.HardwareAddr,
|
||||
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 n.fdbCnt.Add(ipmacOf(vtep, peerMac), -1) == 0 {
|
||||
if err := n.sbox.DeleteNeighbor(vtep.AsSlice(), peerMac, osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
if n.fdbCnt.Add(hashable.IPMACFrom(vtep, peerMac), -1) == 0 {
|
||||
if err := n.sbox.DeleteNeighbor(vtep.AsSlice(), peerMac.AsSlice(), osl.WithLinkName(s.vxlanName), osl.WithFamily(syscall.AF_BRIDGE)); err != nil {
|
||||
return fmt.Errorf("could not delete fdb entry in the sandbox: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete neighbor entry for the peer IP
|
||||
if err := n.sbox.DeleteNeighbor(peerIP.Addr().AsSlice(), peerMac, osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
if err := n.sbox.DeleteNeighbor(peerIP.Addr().AsSlice(), peerMac.AsSlice(), osl.WithLinkName(s.vxlanName)); err != nil {
|
||||
return fmt.Errorf("could not delete neighbor entry in the sandbox:%v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
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}),
|
||||
},
|
||||
))
|
||||
}
|
||||
82
daemon/libnetwork/internal/hashable/net.go
Normal file
82
daemon/libnetwork/internal/hashable/net.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.23
|
||||
|
||||
// Package hashable provides handy utility types for making unhashable values
|
||||
// hashable.
|
||||
package hashable
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
// MACAddr is a hashable encoding of a MAC address.
|
||||
type MACAddr uint64
|
||||
|
||||
// MACAddrFromSlice parses the 6-byte slice as a MAC-48 address.
|
||||
// Note that a [net.HardwareAddr] can be passed directly as the []byte argument.
|
||||
// If slice's length is not 6, MACAddrFromSlice returns 0, false.
|
||||
func MACAddrFromSlice(slice net.HardwareAddr) (MACAddr, bool) {
|
||||
if len(slice) != 6 {
|
||||
return 0, false
|
||||
}
|
||||
return MACAddrFrom6([6]byte(slice)), true
|
||||
}
|
||||
|
||||
// MACAddrFrom6 returns the address of the MAC-48 address
|
||||
// given by the bytes in addr.
|
||||
func MACAddrFrom6(addr [6]byte) MACAddr {
|
||||
return MACAddr(addr[0])<<40 | MACAddr(addr[1])<<32 | MACAddr(addr[2])<<24 |
|
||||
MACAddr(addr[3])<<16 | MACAddr(addr[4])<<8 | MACAddr(addr[5])
|
||||
}
|
||||
|
||||
// ParseMAC parses s as an IEEE 802 MAC-48 address using one of the formats
|
||||
// accepted by [net.ParseMAC].
|
||||
func ParseMAC(s string) (MACAddr, error) {
|
||||
hw, err := net.ParseMAC(s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
mac, ok := MACAddrFromSlice(hw)
|
||||
if !ok {
|
||||
return 0, &net.AddrError{Err: "not a MAC-48 address", Addr: s}
|
||||
}
|
||||
return mac, nil
|
||||
}
|
||||
|
||||
// AsSlice returns a MAC address in its 6-byte representation.
|
||||
func (p MACAddr) AsSlice() []byte {
|
||||
mac := [6]byte{
|
||||
byte(p >> 40), byte(p >> 32), byte(p >> 24),
|
||||
byte(p >> 16), byte(p >> 8), byte(p),
|
||||
}
|
||||
return mac[:]
|
||||
}
|
||||
|
||||
// String returns net.HardwareAddr(p.AsSlice()).String().
|
||||
func (p MACAddr) String() string {
|
||||
return net.HardwareAddr(p.AsSlice()).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
|
||||
}
|
||||
|
||||
// IPMACFrom returns an [IPMAC] with the provided IP and MAC addresses.
|
||||
func IPMACFrom(ip netip.Addr, mac MACAddr) IPMAC {
|
||||
return IPMAC{ip: ip, mac: mac}
|
||||
}
|
||||
|
||||
func (i IPMAC) String() string {
|
||||
return i.ip.String() + " " + i.mac.String()
|
||||
}
|
||||
|
||||
func (i IPMAC) IP() netip.Addr {
|
||||
return i.ip
|
||||
}
|
||||
|
||||
func (i IPMAC) MAC() MACAddr {
|
||||
return i.mac
|
||||
}
|
||||
66
daemon/libnetwork/internal/hashable/net_test.go
Normal file
66
daemon/libnetwork/internal/hashable/net_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package hashable
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
// Assert that the types are hashable.
|
||||
var (
|
||||
_ map[MACAddr]bool
|
||||
_ map[IPMAC]bool
|
||||
)
|
||||
|
||||
func TestMACAddrFrom6(t *testing.T) {
|
||||
want := [6]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
|
||||
assert.DeepEqual(t, MACAddrFrom6(want).AsSlice(), want[:])
|
||||
}
|
||||
|
||||
func TestMACAddrFromSlice(t *testing.T) {
|
||||
mac, ok := MACAddrFromSlice(net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06})
|
||||
assert.Check(t, ok)
|
||||
assert.Check(t, is.DeepEqual(mac.AsSlice(), []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}))
|
||||
|
||||
// Invalid length
|
||||
for _, tc := range [][]byte{
|
||||
{0x01, 0x02, 0x03, 0x04, 0x05},
|
||||
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},
|
||||
{},
|
||||
nil,
|
||||
} {
|
||||
mac, ok = MACAddrFromSlice(net.HardwareAddr(tc))
|
||||
assert.Check(t, !ok, "want MACAddrFromSlice(%#v) ok=false, got true", tc)
|
||||
assert.Check(t, is.DeepEqual(mac.AsSlice(), []byte{0, 0, 0, 0, 0, 0}), "want MACAddrFromSlice(%#v) = %#v, got %#v", tc, []byte{0, 0, 0, 0, 0, 0}, mac.AsSlice())
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMAC(t *testing.T) {
|
||||
mac, err := ParseMAC("01:02:03:04:05:06")
|
||||
assert.Check(t, err)
|
||||
assert.Check(t, is.DeepEqual(mac.AsSlice(), []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}))
|
||||
|
||||
// Invalid MAC address
|
||||
_, err = ParseMAC("01:02:03:04:05:06:07:08")
|
||||
assert.Check(t, is.ErrorContains(err, "not a MAC-48 address"))
|
||||
}
|
||||
|
||||
func TestMACAddr_String(t *testing.T) {
|
||||
mac := MACAddrFrom6([6]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06})
|
||||
assert.Check(t, is.Equal(mac.String(), "01:02:03:04:05:06"))
|
||||
assert.Check(t, is.Equal(MACAddr(0).String(), "00:00:00:00:00:00"))
|
||||
}
|
||||
|
||||
func TestIPMACFrom(t *testing.T) {
|
||||
assert.Check(t, is.Equal(IPMACFrom(netip.Addr{}, 0), IPMAC{}))
|
||||
|
||||
ipm := IPMACFrom(
|
||||
netip.MustParseAddr("11.22.33.44"),
|
||||
MACAddrFrom6([6]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}),
|
||||
)
|
||||
assert.Check(t, is.Equal(ipm.IP(), netip.MustParseAddr("11.22.33.44")))
|
||||
assert.Check(t, is.Equal(ipm.MAC(), MACAddrFrom6([6]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06})))
|
||||
}
|
||||
Reference in New Issue
Block a user