Skip to content

Refactor addr.HostAddr types #4149

@matzf

Description

@matzf

The addr.HostAddr type hierarchy is currently organized around this base interface:

type HostAddr interface {
	Size() int
	Type() HostAddrType
	Pack() []byte
	IP() net.IP
	Copy() HostAddr
	Equal(HostAddr) bool
	fmt.Stringer
}

This interface is implemented by the types HostNone, HostIPv4, HostIPv6 and HostSVC.
The Pack and Size methods are not really used, as slayers uses separate serialization logic, based on separate types. The same is true for the HostFromRaw parsing function.

The slayers library does not generally use these HostAddr types. Instead, it relies on net.Addr with explicit type assertions to net.IPAddr and addr.HostSVC. The net.Addr interface here is merely a convention, none of the interface methods are actually used.

This situation is not ideal:

  • creating HostAddr always allocates -- this cannot be fixed with the interface type.
  • the HostIPv4/HostIPv6 split is unnecessary as the IP is already aware of the type
  • HostAddr is not a value type, cannot be used as map key etc.
  • different "world" of address types in slayers and everywhere else
  • arbitrarily pretends that HostSVC is a net.Addr

Proposal

Replace the HostAddr type hierarchy with a single value type Host.
This type is opaque, allowing to internally change or extend the representation.

type Host struct {
	ip  netaddr.IP
	svc SVC         // could squeeze this into ip, is it worth it?
	t   HostAddrType
}

func (h Host) Type() HostAddrType {
	return h.t
}

func (h Host) IP() netaddr.IP {
	if h.t != HostTypeIP {
		panic("IP called on non-IP address")
	}
	return h.ip
}

func (h Host) SVC() SVC {
	if h.t != HostTypeSVC {
		panic("SVC called on non-SVC address")
	}
	return h.svc
}

func (h Host) String() string { ... }

// HostIP creates a Host address of type IP
func HostIP(ip netaddr.IP) Host {
	return Host{t: HostTypeIP, ip: ip}
}

// HostIPFromStd is a hopefully temporary conversion function to create a Host of type IP from net.IP.
// Panics if ip does not have length 4 or 16.
// Unmaps IPv6-mapped IPv4 addresses.
func HostIPFromStd(ip net.IP) Host {
	a, ok := netaddr.FromStdIP(ip)
	if !ok {
		panic("invalid ip")
	}
	return HostIP(a)
}

func HostSVC(svc SVC) Host {
	return Host{t: HostTypeSVC, svc: svc}
}


type HostAddrType uint8
const (
	HostTypeNone HostAddrType = iota
	HostTypeIP   // merged IPv4/IPv6
	HostTypeSVC
)

// SVC -- renamed from HostSVC, without the HostAddr methods
type SVC uint16
const (
	SvcDS       SVC = 0x0001
	SvcCS       SVC = 0x0002
	SvcWildcard SVC = 0x0010
	SvcNone     SVC = 0xffff

	SVCMcast SVC = 0x8000
)

This Host type is adopted in

  • snet.SCIONAddress and so snet.Packet
  • slayers.SCION in {Get,Set}{Src,Dst}Addr, getting rid of internal type assertions

The HostAddressType enum is used in the dispatcher's "reliable" protocol. To allow combining
HostTypeIPv4 and HostTypeIPv6 without breaking compatibility, the enum is re-defined with the
old values in the dispatcher package.

This allows the router dataplane to use slayers.SCION.GetDstAddr without allocations.
We do need to introduce a number of conversion from net.IP to netaddr.IP -- as we gradually adopt
netaddr.IP et al (or in the future net/netip.Addr), these conversions should disappear.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions