diff options
author | gVisor bot <gvisor-bot@google.com> | 2020-11-30 22:27:48 +0000 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-11-30 22:27:48 +0000 |
commit | e236d392b180e164b6631d18d64ff2f69a374446 (patch) | |
tree | 6cbb7f1e4727d4d552034960cb267c1429263902 | |
parent | 5b624f21ee562ccc0b9fe64bb8a0243b0daffc40 (diff) | |
parent | e813008664ffb361211936dda8631754411cca4f (diff) |
Merge release-20201117.0-78-ge81300866 (automated)
-rw-r--r-- | pkg/tcpip/network/ipv4/ipv4.go | 34 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv6/ipv6.go | 34 | ||||
-rw-r--r-- | pkg/tcpip/stack/addressable_endpoint_state.go | 11 |
3 files changed, 67 insertions, 12 deletions
diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go index be9c8e2f9..ce2087002 100644 --- a/pkg/tcpip/network/ipv4/ipv4.go +++ b/pkg/tcpip/network/ipv4/ipv4.go @@ -123,6 +123,15 @@ func (e *endpoint) Enable() *tcpip.Error { // We have no need for the address endpoint. ep.DecRef() + // Groups may have been joined while the endpoint was disabled, or the + // endpoint may have left groups from the perspective of IGMP when the + // endpoint was disabled. Either way, we need to let routers know to + // send us multicast traffic. + joinedGroups := e.mu.addressableEndpointState.JoinedGroups() + for _, group := range joinedGroups { + e.igmp.joinGroup(group) + } + // As per RFC 1122 section 3.3.7, all hosts should join the all-hosts // multicast group. Note, the IANA calls the all-hosts multicast group the // all-systems multicast group. @@ -168,6 +177,13 @@ func (e *endpoint) disableLocked() { panic(fmt.Sprintf("unexpected error when leaving group = %s: %s", header.IPv4AllSystems, err)) } + // Leave groups from the perspective of IGMP so that routers know that + // we are no longer interested in the group. + joinedGroups := e.mu.addressableEndpointState.JoinedGroups() + for _, group := range joinedGroups { + e.igmp.leaveGroup(group) + } + // The address may have already been removed. if err := e.mu.addressableEndpointState.RemovePermanentAddress(ipv4BroadcastAddr.Address); err != nil && err != tcpip.ErrBadLocalAddress { panic(fmt.Sprintf("unexpected error when removing address = %s: %s", ipv4BroadcastAddr.Address, err)) @@ -853,6 +869,15 @@ func (e *endpoint) joinGroupLocked(addr tcpip.Address) (bool, *tcpip.Error) { return joined, err } + // Only join the group from the perspective of IGMP when the endpoint is + // enabled. + // + // If we are not enabled right now, we will join the group from the + // perspective of IGMP when the endpoint is enabled. + if !e.Enabled() { + return true, nil + } + // joinGroup only returns an error if we try to join a group twice, but we // checked above to make sure that the group was newly joined. if err := e.igmp.joinGroup(addr); err != nil { @@ -874,15 +899,12 @@ func (e *endpoint) LeaveGroup(addr tcpip.Address) (bool, *tcpip.Error) { // Precondition: e.mu must be locked. func (e *endpoint) leaveGroupLocked(addr tcpip.Address) (bool, *tcpip.Error) { left, err := e.mu.addressableEndpointState.LeaveGroup(addr) - if err != nil { + if err != nil || !left { return left, err } - if left { - e.igmp.leaveGroup(addr) - } - - return left, nil + e.igmp.leaveGroup(addr) + return true, nil } // IsInGroup implements stack.GroupAddressableEndpoint. diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index ac67d4ac5..4d49afcbb 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -228,6 +228,15 @@ func (e *endpoint) Enable() *tcpip.Error { return nil } + // Groups may have been joined when the endpoint was disabled, or the + // endpoint may have left groups from the perspective of MLD when the + // endpoint was disabled. Either way, we need to let routers know to + // send us multicast traffic. + joinedGroups := e.mu.addressableEndpointState.JoinedGroups() + for _, group := range joinedGroups { + e.mld.joinGroup(group) + } + // Join the IPv6 All-Nodes Multicast group if the stack is configured to // use IPv6. This is required to ensure that this node properly receives // and responds to the various NDP messages that are destined to the @@ -338,6 +347,13 @@ func (e *endpoint) disableLocked() { if _, err := e.leaveGroupLocked(header.IPv6AllNodesMulticastAddress); err != nil && err != tcpip.ErrBadLocalAddress { panic(fmt.Sprintf("unexpected error when leaving group = %s: %s", header.IPv6AllNodesMulticastAddress, err)) } + + // Leave groups from the perspective of MLD so that routers know that + // we are no longer interested in the group. + joinedGroups := e.mu.addressableEndpointState.JoinedGroups() + for _, group := range joinedGroups { + e.mld.leaveGroup(group) + } } // stopDADForPermanentAddressesLocked stops DAD for all permaneent addresses. @@ -1409,6 +1425,15 @@ func (e *endpoint) joinGroupLocked(addr tcpip.Address) (bool, *tcpip.Error) { return joined, err } + // Only join the group from the perspective of IGMP when the endpoint is + // enabled. + // + // If we are not enabled right now, we will join the group from the + // perspective of MLD when the endpoint is enabled. + if !e.Enabled() { + return true, nil + } + // joinGroup only returns an error if we try to join a group twice, but we // checked above to make sure that the group was newly joined. if err := e.mld.joinGroup(addr); err != nil { @@ -1430,15 +1455,12 @@ func (e *endpoint) LeaveGroup(addr tcpip.Address) (bool, *tcpip.Error) { // Precondition: e.mu must be locked. func (e *endpoint) leaveGroupLocked(addr tcpip.Address) (bool, *tcpip.Error) { left, err := e.mu.addressableEndpointState.LeaveGroup(addr) - if err != nil { + if err != nil || !left { return left, err } - if left { - e.mld.leaveGroup(addr) - } - - return left, nil + e.mld.leaveGroup(addr) + return true, nil } // IsInGroup implements stack.GroupAddressableEndpoint. diff --git a/pkg/tcpip/stack/addressable_endpoint_state.go b/pkg/tcpip/stack/addressable_endpoint_state.go index adeebfe37..6e855d815 100644 --- a/pkg/tcpip/stack/addressable_endpoint_state.go +++ b/pkg/tcpip/stack/addressable_endpoint_state.go @@ -625,6 +625,17 @@ func (a *AddressableEndpointState) IsInGroup(group tcpip.Address) bool { return ok } +// JoinedGroups returns a list of groups the endpoint is a member of. +func (a *AddressableEndpointState) JoinedGroups() []tcpip.Address { + a.mu.RLock() + defer a.mu.RUnlock() + groups := make([]tcpip.Address, 0, len(a.mu.groups)) + for g := range a.mu.groups { + groups = append(groups, g) + } + return groups +} + // Cleanup forcefully leaves all groups and removes all permanent addresses. func (a *AddressableEndpointState) Cleanup() { a.mu.Lock() |