mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Refactor default router state to off-link route state
This change prepares for a later change which supports the NDP Route Information option to discover more-specific routes, as per RFC 4191. The newly introduced off-link route state will be used to hold both the state for default routers (which is a default (off-link) route through the router, and more-specific routes (which are routes through some router to some destination subnet more specific than the IPv6 empty subnet). Updates #6172. PiperOrigin-RevId: 381403761
This commit is contained in:
committed by
gVisor bot
parent
ccd2d607e5
commit
49986674aa
@@ -344,7 +344,10 @@ func (e *endpoint) onAddressAssignedLocked(addr tcpip.Address) {
|
||||
func (e *endpoint) InvalidateDefaultRouter(rtr tcpip.Address) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
e.mu.ndp.invalidateDefaultRouter(rtr)
|
||||
|
||||
// We represent default routers with a default (off-link) route through the
|
||||
// router.
|
||||
e.mu.ndp.invalidateOffLinkRoute(offLinkRoute{dest: header.IPv6EmptySubnet, router: rtr})
|
||||
}
|
||||
|
||||
// SetNDPConfigurations implements NDPEndpoint.
|
||||
|
||||
@@ -78,13 +78,13 @@ const (
|
||||
// we cannot have a negative delay.
|
||||
minimumMaxRtrSolicitationDelay = 0
|
||||
|
||||
// MaxDiscoveredDefaultRouters is the maximum number of discovered
|
||||
// default routers. The stack should stop discovering new routers after
|
||||
// discovering MaxDiscoveredDefaultRouters routers.
|
||||
// MaxDiscoveredOffLinkRoutes is the maximum number of discovered off-link
|
||||
// routes. The stack should stop discovering new off-link routes after
|
||||
// this limit is reached.
|
||||
//
|
||||
// This value MUST be at minimum 2 as per RFC 4861 section 6.3.4, and
|
||||
// SHOULD be more.
|
||||
MaxDiscoveredDefaultRouters = 10
|
||||
MaxDiscoveredOffLinkRoutes = 10
|
||||
|
||||
// MaxDiscoveredOnLinkPrefixes is the maximum number of discovered
|
||||
// on-link prefixes. The stack should stop discovering new on-link
|
||||
@@ -448,6 +448,11 @@ type timer struct {
|
||||
timer tcpip.Timer
|
||||
}
|
||||
|
||||
type offLinkRoute struct {
|
||||
dest tcpip.Subnet
|
||||
router tcpip.Address
|
||||
}
|
||||
|
||||
// ndpState is the per-Interface NDP state.
|
||||
type ndpState struct {
|
||||
// Do not allow overwriting this state.
|
||||
@@ -462,8 +467,8 @@ type ndpState struct {
|
||||
// The DAD timers to send the next NS message, or resolve the address.
|
||||
dad ip.DAD
|
||||
|
||||
// The default routers discovered through Router Advertisements.
|
||||
defaultRouters map[tcpip.Address]defaultRouterState
|
||||
// The off-link routes discovered through Router Advertisements.
|
||||
offLinkRoutes map[offLinkRoute]offLinkRouteState
|
||||
|
||||
// rtrSolicitTimer is the timer used to send the next router solicitation
|
||||
// message.
|
||||
@@ -491,12 +496,12 @@ type ndpState struct {
|
||||
temporaryAddressDesyncFactor time.Duration
|
||||
}
|
||||
|
||||
// defaultRouterState holds data associated with a default router discovered by
|
||||
// offLinkRouteState holds data associated with an off-link route discovered by
|
||||
// a Router Advertisement (RA).
|
||||
type defaultRouterState struct {
|
||||
type offLinkRouteState struct {
|
||||
prf header.NDPRoutePreference
|
||||
|
||||
// Job to invalidate the default router.
|
||||
// Job to invalidate the route.
|
||||
//
|
||||
// Must not be nil.
|
||||
invalidationJob *tcpip.Job
|
||||
@@ -727,38 +732,9 @@ func (ndp *ndpState) handleRA(ip tcpip.Address, ra header.NDPRouterAdvert) {
|
||||
prf = header.MediumRoutePreference
|
||||
}
|
||||
|
||||
rtr, ok := ndp.defaultRouters[ip]
|
||||
rl := ra.RouterLifetime()
|
||||
switch {
|
||||
case !ok && rl != 0:
|
||||
// This is a new default router we are discovering.
|
||||
//
|
||||
// Only remember it if we currently know about less than
|
||||
// MaxDiscoveredDefaultRouters routers.
|
||||
if len(ndp.defaultRouters) < MaxDiscoveredDefaultRouters {
|
||||
ndp.rememberDefaultRouter(ip, rl, prf)
|
||||
}
|
||||
|
||||
case ok && rl != 0:
|
||||
// This is an already discovered default router. Update
|
||||
// the invalidation job.
|
||||
rtr.invalidationJob.Cancel()
|
||||
rtr.invalidationJob.Schedule(rl)
|
||||
|
||||
if prf != rtr.prf {
|
||||
rtr.prf = prf
|
||||
|
||||
// Inform the integrator about router preference updates.
|
||||
ndp.ep.protocol.options.NDPDisp.OnOffLinkRouteUpdated(ndp.ep.nic.ID(), header.IPv6EmptySubnet, ip, prf)
|
||||
}
|
||||
|
||||
ndp.defaultRouters[ip] = rtr
|
||||
|
||||
case ok && rl == 0:
|
||||
// We know about the router but it is no longer to be
|
||||
// used as a default router so invalidate it.
|
||||
ndp.invalidateDefaultRouter(ip)
|
||||
}
|
||||
// We represent default routers with a default (off-link) route through the
|
||||
// router.
|
||||
ndp.handleOffLinkRouteDiscovery(offLinkRoute{dest: header.IPv6EmptySubnet, router: ip}, ra.RouterLifetime(), prf)
|
||||
}
|
||||
|
||||
// TODO(b/141556115): Do (RetransTimer, ReachableTime)) Parameter
|
||||
@@ -816,52 +792,75 @@ func (ndp *ndpState) handleRA(ip tcpip.Address, ra header.NDPRouterAdvert) {
|
||||
}
|
||||
}
|
||||
|
||||
// invalidateDefaultRouter invalidates a discovered default router.
|
||||
// invalidateOffLinkRoute invalidates a discovered off-link route.
|
||||
//
|
||||
// The IPv6 endpoint that ndp belongs to MUST be locked.
|
||||
func (ndp *ndpState) invalidateDefaultRouter(ip tcpip.Address) {
|
||||
rtr, ok := ndp.defaultRouters[ip]
|
||||
|
||||
// Is the router still discovered?
|
||||
func (ndp *ndpState) invalidateOffLinkRoute(route offLinkRoute) {
|
||||
state, ok := ndp.offLinkRoutes[route]
|
||||
if !ok {
|
||||
// ...Nope, do nothing further.
|
||||
return
|
||||
}
|
||||
|
||||
rtr.invalidationJob.Cancel()
|
||||
delete(ndp.defaultRouters, ip)
|
||||
state.invalidationJob.Cancel()
|
||||
delete(ndp.offLinkRoutes, route)
|
||||
|
||||
// Let the integrator know a discovered default router is invalidated.
|
||||
// Let the integrator know a discovered off-link route is invalidated.
|
||||
if ndpDisp := ndp.ep.protocol.options.NDPDisp; ndpDisp != nil {
|
||||
ndpDisp.OnOffLinkRouteInvalidated(ndp.ep.nic.ID(), header.IPv6EmptySubnet, ip)
|
||||
ndpDisp.OnOffLinkRouteInvalidated(ndp.ep.nic.ID(), route.dest, route.router)
|
||||
}
|
||||
}
|
||||
|
||||
// rememberDefaultRouter remembers a newly discovered default router with IPv6
|
||||
// link-local address ip with lifetime rl.
|
||||
// handleOffLinkRouteDiscovery handles the discovery of an off-link route.
|
||||
//
|
||||
// The router identified by ip MUST NOT already be known by the IPv6 endpoint.
|
||||
//
|
||||
// The IPv6 endpoint that ndp belongs to MUST be locked.
|
||||
func (ndp *ndpState) rememberDefaultRouter(ip tcpip.Address, rl time.Duration, prf header.NDPRoutePreference) {
|
||||
// Precondition: ndp.ep.mu must be locked.
|
||||
func (ndp *ndpState) handleOffLinkRouteDiscovery(route offLinkRoute, lifetime time.Duration, prf header.NDPRoutePreference) {
|
||||
ndpDisp := ndp.ep.protocol.options.NDPDisp
|
||||
if ndpDisp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Inform the integrator when we discovered a default router.
|
||||
ndpDisp.OnOffLinkRouteUpdated(ndp.ep.nic.ID(), header.IPv6EmptySubnet, ip, prf)
|
||||
state, ok := ndp.offLinkRoutes[route]
|
||||
switch {
|
||||
case !ok && lifetime != 0:
|
||||
// This is a new route we are discovering.
|
||||
//
|
||||
// Only remember it if we currently know about less than
|
||||
// MaxDiscoveredOffLinkRoutes routers.
|
||||
if len(ndp.offLinkRoutes) < MaxDiscoveredOffLinkRoutes {
|
||||
// Inform the integrator when we discovered an off-link route.
|
||||
ndpDisp.OnOffLinkRouteUpdated(ndp.ep.nic.ID(), route.dest, route.router, prf)
|
||||
|
||||
state := defaultRouterState{
|
||||
prf: prf,
|
||||
invalidationJob: ndp.ep.protocol.stack.NewJob(&ndp.ep.mu, func() {
|
||||
ndp.invalidateDefaultRouter(ip)
|
||||
}),
|
||||
state := offLinkRouteState{
|
||||
prf: prf,
|
||||
invalidationJob: ndp.ep.protocol.stack.NewJob(&ndp.ep.mu, func() {
|
||||
ndp.invalidateOffLinkRoute(route)
|
||||
}),
|
||||
}
|
||||
|
||||
state.invalidationJob.Schedule(lifetime)
|
||||
|
||||
ndp.offLinkRoutes[route] = state
|
||||
}
|
||||
|
||||
case ok && lifetime != 0:
|
||||
// This is an already discovered off-link route. Update the lifetime.
|
||||
state.invalidationJob.Cancel()
|
||||
state.invalidationJob.Schedule(lifetime)
|
||||
|
||||
if prf != state.prf {
|
||||
state.prf = prf
|
||||
|
||||
// Inform the integrator about route preference updates.
|
||||
ndpDisp.OnOffLinkRouteUpdated(ndp.ep.nic.ID(), route.dest, route.router, prf)
|
||||
}
|
||||
|
||||
ndp.offLinkRoutes[route] = state
|
||||
|
||||
case ok && lifetime == 0:
|
||||
// The already discovered off-link route is no longer considered valid so we
|
||||
// invalidate it immediately.
|
||||
ndp.invalidateOffLinkRoute(route)
|
||||
}
|
||||
|
||||
state.invalidationJob.Schedule(rl)
|
||||
|
||||
ndp.defaultRouters[ip] = state
|
||||
}
|
||||
|
||||
// rememberOnLinkPrefix remembers a newly discovered on-link prefix with IPv6
|
||||
@@ -1677,12 +1676,12 @@ func (ndp *ndpState) cleanupState() {
|
||||
panic(fmt.Sprintf("ndp: still have discovered on-link prefixes after cleaning up; found = %d", got))
|
||||
}
|
||||
|
||||
for router := range ndp.defaultRouters {
|
||||
ndp.invalidateDefaultRouter(router)
|
||||
for route := range ndp.offLinkRoutes {
|
||||
ndp.invalidateOffLinkRoute(route)
|
||||
}
|
||||
|
||||
if got := len(ndp.defaultRouters); got != 0 {
|
||||
panic(fmt.Sprintf("ndp: still have discovered default routers after cleaning up; found = %d", got))
|
||||
if got := len(ndp.offLinkRoutes); got != 0 {
|
||||
panic(fmt.Sprintf("ndp: still have discovered off-link routes after cleaning up; found = %d", got))
|
||||
}
|
||||
|
||||
ndp.dhcpv6Configuration = 0
|
||||
@@ -1845,14 +1844,14 @@ func (ndp *ndpState) stopSolicitingRouters() {
|
||||
}
|
||||
|
||||
func (ndp *ndpState) init(ep *endpoint, dadOptions ip.DADOptions) {
|
||||
if ndp.defaultRouters != nil {
|
||||
if ndp.offLinkRoutes != nil {
|
||||
panic("attempted to initialize NDP state twice")
|
||||
}
|
||||
|
||||
ndp.ep = ep
|
||||
ndp.configs = ep.protocol.options.NDPConfigs
|
||||
ndp.dad.Init(&ndp.ep.mu, ep.protocol.options.DADConfigs, dadOptions)
|
||||
ndp.defaultRouters = make(map[tcpip.Address]defaultRouterState)
|
||||
ndp.offLinkRoutes = make(map[offLinkRoute]offLinkRouteState)
|
||||
ndp.onLinkPrefixes = make(map[tcpip.Subnet]onLinkPrefixState)
|
||||
ndp.slaacPrefixes = make(map[tcpip.Subnet]slaacPrefixState)
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ func TestStackNDPEndpointInvalidateDefaultRouter(t *testing.T) {
|
||||
|
||||
ipv6EP := ep.(*endpoint)
|
||||
ipv6EP.mu.Lock()
|
||||
ipv6EP.mu.ndp.rememberDefaultRouter(lladdr1, time.Hour, header.MediumRoutePreference)
|
||||
ipv6EP.mu.ndp.handleOffLinkRouteDiscovery(offLinkRoute{dest: header.IPv6EmptySubnet, router: lladdr1}, time.Hour, header.MediumRoutePreference)
|
||||
ipv6EP.mu.Unlock()
|
||||
|
||||
if ndpDisp.addr != lladdr1 {
|
||||
|
||||
@@ -1461,7 +1461,7 @@ func TestRouterDiscovery(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestRouterDiscoveryMaxRouters tests that only
|
||||
// ipv6.MaxDiscoveredDefaultRouters discovered routers are remembered.
|
||||
// ipv6.MaxDiscoveredOffLinkRoutes discovered routers are remembered.
|
||||
func TestRouterDiscoveryMaxRouters(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
@@ -1484,14 +1484,14 @@ func TestRouterDiscoveryMaxRouters(t *testing.T) {
|
||||
}
|
||||
|
||||
// Receive an RA from 2 more than the max number of discovered routers.
|
||||
for i := 1; i <= ipv6.MaxDiscoveredDefaultRouters+2; i++ {
|
||||
for i := 1; i <= ipv6.MaxDiscoveredOffLinkRoutes+2; i++ {
|
||||
linkAddr := []byte{2, 2, 3, 4, 5, 0}
|
||||
linkAddr[5] = byte(i)
|
||||
llAddr := header.LinkLocalAddr(tcpip.LinkAddress(linkAddr))
|
||||
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufSimple(llAddr, 5))
|
||||
|
||||
if i <= ipv6.MaxDiscoveredDefaultRouters {
|
||||
if i <= ipv6.MaxDiscoveredOffLinkRoutes {
|
||||
select {
|
||||
case e := <-ndpDisp.offLinkRouteC:
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, llAddr, header.MediumRoutePreference, true); diff != "" {
|
||||
|
||||
Reference in New Issue
Block a user