mirror of
https://github.com/soypat/lneto.git
synced 2026-08-10 09:53:44 +00:00
e0ef681085
Signed-off-by: Marvin Drees <marvin.drees@9elements.com>
87 lines
3.1 KiB
Go
87 lines
3.1 KiB
Go
// Package linklocal4 implements dynamic configuration of IPv4 link-local addresses
|
|
// (a.k.a. APIPA, "self-assigned" 169.254.x.x addresses) as specified in [RFC3927].
|
|
//
|
|
// The [Handler] is a heapless state machine that claims and defends a link-local
|
|
// address using ARP probes and announcements. It performs no allocations during
|
|
// steady-state operation and holds no buffers of its own; the caller provides the
|
|
// scratch buffer on each call. This makes it suitable for memory constrained and
|
|
// bare-metal targets.
|
|
//
|
|
// [RFC3927]: https://datatracker.ietf.org/doc/html/rfc3927
|
|
package linklocal4
|
|
|
|
import "time"
|
|
|
|
// Protocol constants as defined in [RFC3927] section 9.
|
|
//
|
|
// [RFC3927]: https://datatracker.ietf.org/doc/html/rfc3927#section-9
|
|
const (
|
|
// probeWait is the initial random delay before sending the first probe.
|
|
probeWait = 1 * time.Second
|
|
// probeNum is the number of ARP probes to send.
|
|
probeNum = 3
|
|
// probeMin and probeMax bound the random spacing between probes.
|
|
probeMin = 1 * time.Second
|
|
probeMax = 2 * time.Second
|
|
// announceWait is the delay after the last probe before announcing.
|
|
announceWait = 2 * time.Second
|
|
// announceNum is the number of ARP announcements to send.
|
|
announceNum = 2
|
|
// announceInterval is the spacing between announcements.
|
|
announceInterval = 2 * time.Second
|
|
// maxConflicts is the number of conflicts after which probing is rate limited.
|
|
maxConflicts = 10
|
|
// rateLimitInterval bounds the rate of address claiming once maxConflicts is exceeded.
|
|
rateLimitInterval = 60 * time.Second
|
|
// defendInterval is the minimum spacing between defensive announcements before
|
|
// the address is abandoned to break an endless defense loop.
|
|
defendInterval = 10 * time.Second
|
|
)
|
|
|
|
// arpIPv4Size is the size of an ARP-over-Ethernet IPv4 packet (RFC826):
|
|
// 8 byte fixed header + 2*(6 byte hardware addr + 4 byte protocol addr).
|
|
const arpIPv4Size = 28
|
|
|
|
// State represents the stage of the link-local address autoconfiguration
|
|
// state machine. The transition order during a successful claim is:
|
|
//
|
|
// StateWaiting -> StateProbing -> StateAnnouncing -> StateBound
|
|
type State uint8
|
|
|
|
const (
|
|
// StateInvalid is the zero value; the handler has not been configured.
|
|
StateInvalid State = iota
|
|
// StateWaiting is the initial random delay before the first probe is sent.
|
|
StateWaiting
|
|
// StateProbing sends ARP probes to detect whether the candidate is in use.
|
|
StateProbing
|
|
// StateAnnouncing has claimed the candidate and is broadcasting announcements.
|
|
StateAnnouncing
|
|
// StateBound owns the address and defends it against conflicts.
|
|
StateBound
|
|
// StateRateLimited is waiting out rateLimitInterval after too many conflicts.
|
|
StateRateLimited
|
|
)
|
|
|
|
// IsBound reports whether the state machine has successfully claimed an address.
|
|
func (s State) IsBound() bool { return s == StateBound }
|
|
|
|
func (s State) String() string {
|
|
switch s {
|
|
case StateInvalid:
|
|
return "invalid"
|
|
case StateWaiting:
|
|
return "waiting"
|
|
case StateProbing:
|
|
return "probing"
|
|
case StateAnnouncing:
|
|
return "announcing"
|
|
case StateBound:
|
|
return "bound"
|
|
case StateRateLimited:
|
|
return "rate-limited"
|
|
default:
|
|
return "linklocal4.State(?)"
|
|
}
|
|
}
|