summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/stack/nic.go
diff options
context:
space:
mode:
authorTamir Duberstein <tamird@google.com>2018-09-05 18:58:09 -0700
committerShentubot <shentubot@google.com>2018-09-05 18:59:16 -0700
commit156b49ca85be7602ec034167767f0d0bfedf2be5 (patch)
treee1ab6c9664461f0641ca2641f3549481a316b35f /pkg/tcpip/stack/nic.go
parent5f0002fc83a77a39d9a2ef1443bc6c18e22ea779 (diff)
Fix race condition introduced in 211135505
Now that it's possible to remove subnets, we must iterate over them with locks held. Also do the removal more efficiently while I'm here. PiperOrigin-RevId: 211737416 Change-Id: I29025ec8b0c3ad11f22d4447e8ad473f1c785463
Diffstat (limited to 'pkg/tcpip/stack/nic.go')
-rw-r--r--pkg/tcpip/stack/nic.go34
1 files changed, 19 insertions, 15 deletions
diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go
index 7aa960096..845b40f11 100644
--- a/pkg/tcpip/stack/nic.go
+++ b/pkg/tcpip/stack/nic.go
@@ -266,11 +266,14 @@ func (n *NIC) AddSubnet(protocol tcpip.NetworkProtocolNumber, subnet tcpip.Subne
func (n *NIC) RemoveSubnet(subnet tcpip.Subnet) {
n.mu.Lock()
- for i, sub := range n.subnets {
- if sub == subnet {
- n.subnets = append(n.subnets[:i], n.subnets[i+1:]...)
+ // Use the same underlying array.
+ tmp := n.subnets[:0]
+ for _, sub := range n.subnets {
+ if sub != subnet {
+ tmp = append(tmp, sub)
}
}
+ n.subnets = tmp
n.mu.Unlock()
}
@@ -369,33 +372,34 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin
id := NetworkEndpointID{dst}
n.mu.RLock()
- ref := n.endpoints[id]
- if ref != nil && !ref.tryIncRef() {
+ ref, ok := n.endpoints[id]
+ if ok && !ref.tryIncRef() {
ref = nil
}
- promiscuous := n.promiscuous
- subnets := n.subnets
- n.mu.RUnlock()
-
- if ref == nil {
+ if ref != nil {
+ n.mu.RUnlock()
+ } else {
+ promiscuous := n.promiscuous
// Check if the packet is for a subnet this NIC cares about.
if !promiscuous {
- for _, sn := range subnets {
+ for _, sn := range n.subnets {
if sn.Contains(dst) {
promiscuous = true
break
}
}
}
+ n.mu.RUnlock()
if promiscuous {
// Try again with the lock in exclusive mode. If we still can't
// get the endpoint, create a new "temporary" one. It will only
// exist while there's a route through it.
n.mu.Lock()
- ref = n.endpoints[id]
- if ref == nil || !ref.tryIncRef() {
- ref, _ = n.addAddressLocked(protocol, dst, true)
- if ref != nil {
+ ref, ok = n.endpoints[id]
+ if !ok || !ref.tryIncRef() {
+ var err *tcpip.Error
+ ref, err = n.addAddressLocked(protocol, dst, true)
+ if err == nil {
ref.holdsInsertRef = false
}
}