summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/tcpip/network/ipv6/ipv6.go43
-rw-r--r--pkg/tcpip/network/ipv6/ndp.go62
2 files changed, 63 insertions, 42 deletions
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go
index c7a92be6c..659057fa7 100644
--- a/pkg/tcpip/network/ipv6/ipv6.go
+++ b/pkg/tcpip/network/ipv6/ipv6.go
@@ -420,8 +420,6 @@ func (e *endpoint) transitionForwarding(forwarding bool) {
defer e.mu.Unlock()
if forwarding {
- e.mu.ndp.stopSolicitingRouters()
-
// As per RFC 4291 section 2.8:
//
// A router is required to recognize all addresses that a host is
@@ -445,28 +443,19 @@ func (e *endpoint) transitionForwarding(forwarding bool) {
panic(fmt.Sprintf("e.joinGroupLocked(%s): %s", g, err))
}
}
-
- return
- }
-
- for _, g := range allRoutersGroups {
- switch err := e.leaveGroupLocked(g).(type) {
- case nil:
- case *tcpip.ErrBadLocalAddress:
- // The endpoint may have already left the multicast group.
- default:
- panic(fmt.Sprintf("e.leaveGroupLocked(%s): %s", g, err))
+ } else {
+ for _, g := range allRoutersGroups {
+ switch err := e.leaveGroupLocked(g).(type) {
+ case nil:
+ case *tcpip.ErrBadLocalAddress:
+ // The endpoint may have already left the multicast group.
+ default:
+ panic(fmt.Sprintf("e.leaveGroupLocked(%s): %s", g, err))
+ }
}
}
- // When transitioning into an IPv6 host, NDP router solicitations are
- // started if the endpoint is enabled.
- //
- // If the endpoint is not currently enabled, routers will be solicited when
- // the endpoint becomes enabled (if it is still a host).
- if e.Enabled() {
- e.mu.ndp.startSolicitingRouters()
- }
+ e.mu.ndp.forwardingChanged(forwarding)
}
// Enable implements stack.NetworkEndpoint.
@@ -548,17 +537,7 @@ func (e *endpoint) Enable() tcpip.Error {
e.mu.ndp.doSLAAC(header.IPv6LinkLocalPrefix.Subnet(), header.NDPInfiniteLifetime, header.NDPInfiniteLifetime)
}
- // If we are operating as a router, then do not solicit routers since we
- // won't process the RAs anyway.
- //
- // Routers do not process Router Advertisements (RA) the same way a host
- // does. That is, routers do not learn from RAs (e.g. on-link prefixes
- // and default routers). Therefore, soliciting RAs from other routers on
- // a link is unnecessary for routers.
- if !e.protocol.Forwarding() {
- e.mu.ndp.startSolicitingRouters()
- }
-
+ e.mu.ndp.startSolicitingRouters()
return nil
}
diff --git a/pkg/tcpip/network/ipv6/ndp.go b/pkg/tcpip/network/ipv6/ndp.go
index be6a2e161..b29fed347 100644
--- a/pkg/tcpip/network/ipv6/ndp.go
+++ b/pkg/tcpip/network/ipv6/ndp.go
@@ -334,10 +334,27 @@ func (c HandleRAsConfiguration) String() string {
}
}
+// enabled returns true iff Router Advertisements may be handled given the
+// specified forwarding status.
+func (c HandleRAsConfiguration) enabled(forwarding bool) bool {
+ switch c {
+ case HandlingRAsDisabled:
+ return false
+ case HandlingRAsEnabledWhenForwardingDisabled:
+ return !forwarding
+ case HandlingRAsAlwaysEnabled:
+ return true
+ default:
+ panic(fmt.Sprintf("unhandled HandleRAsConfiguration = %d", c))
+ }
+}
+
// NDPConfigurations is the NDP configurations for the netstack.
type NDPConfigurations struct {
// The number of Router Solicitation messages to send when the IPv6 endpoint
// becomes enabled.
+ //
+ // Ignored unless configured to handle Router Advertisements.
MaxRtrSolicitations uint8
// The amount of time between transmitting Router Solicitation messages.
@@ -688,18 +705,9 @@ func (ndp *ndpState) handleRA(ip tcpip.Address, ra header.NDPRouterAdvert) {
// per-interface basis; it is a protocol-wide configuration, so we check the
// protocol's forwarding flag to determine if the IPv6 endpoint is forwarding
// packets.
- switch ndp.configs.HandleRAs {
- case HandlingRAsDisabled:
+ if !ndp.configs.HandleRAs.enabled(ndp.ep.protocol.Forwarding()) {
ndp.ep.stats.localStats.UnhandledRouterAdvertisements.Increment()
return
- case HandlingRAsEnabledWhenForwardingDisabled:
- if ndp.ep.protocol.Forwarding() {
- ndp.ep.stats.localStats.UnhandledRouterAdvertisements.Increment()
- return
- }
- case HandlingRAsAlwaysEnabled:
- default:
- panic(fmt.Sprintf("unhandled HandleRAs configuration = %d", ndp.configs.HandleRAs))
}
// Only worry about the DHCPv6 configuration if we have an NDPDispatcher as we
@@ -1686,6 +1694,10 @@ func (ndp *ndpState) cleanupState() {
// startSolicitingRouters starts soliciting routers, as per RFC 4861 section
// 6.3.7. If routers are already being solicited, this function does nothing.
//
+// If ndp is not configured to handle Router Advertisements, routers will not
+// be solicited as there is no point soliciting routers if we don't handle their
+// advertisements.
+//
// The IPv6 endpoint that ndp belongs to MUST be locked.
func (ndp *ndpState) startSolicitingRouters() {
if ndp.rtrSolicitTimer.timer != nil {
@@ -1698,6 +1710,10 @@ func (ndp *ndpState) startSolicitingRouters() {
return
}
+ if !ndp.configs.HandleRAs.enabled(ndp.ep.protocol.Forwarding()) {
+ return
+ }
+
// Calculate the random delay before sending our first RS, as per RFC
// 4861 section 6.3.7.
var delay time.Duration
@@ -1790,6 +1806,32 @@ func (ndp *ndpState) startSolicitingRouters() {
}
}
+// forwardingChanged handles a change in forwarding configuration.
+//
+// If transitioning to a host, router solicitation will be started. Otherwise,
+// router solicitation will be stopped if NDP is not configured to handle RAs
+// as a router.
+//
+// Precondition: ndp.ep.mu must be locked.
+func (ndp *ndpState) forwardingChanged(forwarding bool) {
+ if forwarding {
+ if ndp.configs.HandleRAs.enabled(forwarding) {
+ return
+ }
+
+ ndp.stopSolicitingRouters()
+ return
+ }
+
+ // Solicit routers when transitioning to a host.
+ //
+ // If the endpoint is not currently enabled, routers will be solicited when
+ // the endpoint becomes enabled (if it is still a host).
+ if ndp.ep.Enabled() {
+ ndp.startSolicitingRouters()
+ }
+}
+
// stopSolicitingRouters stops soliciting routers. If routers are not currently
// being solicited, this function does nothing.
//