summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/network/internal
diff options
context:
space:
mode:
authorgVisor bot <gvisor-bot@google.com>2021-02-09 03:10:57 +0000
committergVisor bot <gvisor-bot@google.com>2021-02-09 03:10:57 +0000
commit5741b2ffd9a15af87775038d47667263bb871ca1 (patch)
tree1894624b3f564758077646888358d18c6e221db5 /pkg/tcpip/network/internal
parent619ca7375ad32627c6237433e4508e3c54f7450e (diff)
parent39251f31cb92d6c2b053416d04e195e290b106f2 (diff)
Merge release-20210201.0-58-g39251f31c (automated)
Diffstat (limited to 'pkg/tcpip/network/internal')
-rw-r--r--pkg/tcpip/network/internal/ip/duplicate_address_detection.go172
-rw-r--r--pkg/tcpip/network/internal/ip/ip_state_autogen.go3
2 files changed, 175 insertions, 0 deletions
diff --git a/pkg/tcpip/network/internal/ip/duplicate_address_detection.go b/pkg/tcpip/network/internal/ip/duplicate_address_detection.go
new file mode 100644
index 000000000..6f89a6a16
--- /dev/null
+++ b/pkg/tcpip/network/internal/ip/duplicate_address_detection.go
@@ -0,0 +1,172 @@
+// Copyright 2021 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package ip holds IPv4/IPv6 common utilities.
+package ip
+
+import (
+ "fmt"
+
+ "gvisor.dev/gvisor/pkg/sync"
+ "gvisor.dev/gvisor/pkg/tcpip"
+ "gvisor.dev/gvisor/pkg/tcpip/stack"
+)
+
+type dadState struct {
+ done *bool
+ timer tcpip.Timer
+
+ completionHandlers []stack.DADCompletionHandler
+}
+
+// DADProtocol is a protocol whose core state machine can be represented by DAD.
+type DADProtocol interface {
+ // SendDADMessage attempts to send a DAD probe message.
+ SendDADMessage(tcpip.Address) tcpip.Error
+}
+
+// DADOptions holds options for DAD.
+type DADOptions struct {
+ Clock tcpip.Clock
+ Protocol DADProtocol
+ NICID tcpip.NICID
+}
+
+// DAD performs duplicate address detection for addresses.
+type DAD struct {
+ opts DADOptions
+ configs stack.DADConfigurations
+
+ protocolMU sync.Locker
+ addresses map[tcpip.Address]dadState
+}
+
+// Init initializes the DAD state.
+//
+// Must only be called once for the lifetime of d; Init will panic if it is
+// called twice.
+//
+// The lock will only be taken when timers fire.
+func (d *DAD) Init(protocolMU sync.Locker, configs stack.DADConfigurations, opts DADOptions) {
+ if d.addresses != nil {
+ panic("attempted to initialize DAD state twice")
+ }
+
+ *d = DAD{
+ opts: opts,
+ configs: configs,
+ protocolMU: protocolMU,
+ addresses: make(map[tcpip.Address]dadState),
+ }
+}
+
+// CheckDuplicateAddressLocked performs DAD for an address, calling the
+// completion handler once DAD resolves.
+//
+// If DAD is already performing for the provided address, h will be called when
+// the currently running process completes.
+//
+// Precondition: d.protocolMU must be locked.
+func (d *DAD) CheckDuplicateAddressLocked(addr tcpip.Address, h stack.DADCompletionHandler) stack.DADCheckAddressDisposition {
+ if d.configs.DupAddrDetectTransmits == 0 {
+ return stack.DADDisabled
+ }
+
+ ret := stack.DADAlreadyRunning
+ s, ok := d.addresses[addr]
+ if !ok {
+ ret = stack.DADStarting
+
+ remaining := d.configs.DupAddrDetectTransmits
+
+ // Protected by d.protocolMU.
+ done := false
+
+ s = dadState{
+ done: &done,
+ timer: d.opts.Clock.AfterFunc(0, func() {
+ var err tcpip.Error
+ dadDone := remaining == 0
+ if !dadDone {
+ err = d.opts.Protocol.SendDADMessage(addr)
+ }
+
+ d.protocolMU.Lock()
+ defer d.protocolMU.Unlock()
+
+ if done {
+ return
+ }
+
+ s, ok := d.addresses[addr]
+ if !ok {
+ panic(fmt.Sprintf("dad: timer fired but missing state for %s on NIC(%d)", addr, d.opts.NICID))
+ }
+
+ if !dadDone && err == nil {
+ remaining--
+ s.timer.Reset(d.configs.RetransmitTimer)
+ return
+ }
+
+ // At this point we know that either DAD has resolved or we hit an error
+ // sending the last DAD message. Either way, clear the DAD state.
+ done = false
+ s.timer.Stop()
+ delete(d.addresses, addr)
+
+ r := stack.DADResult{Resolved: dadDone, Err: err}
+ for _, h := range s.completionHandlers {
+ h(r)
+ }
+ }),
+ }
+ }
+
+ s.completionHandlers = append(s.completionHandlers, h)
+ d.addresses[addr] = s
+ return ret
+}
+
+// StopLocked stops a currently running DAD process.
+//
+// Precondition: d.protocolMU must be locked.
+func (d *DAD) StopLocked(addr tcpip.Address, aborted bool) {
+ s, ok := d.addresses[addr]
+ if !ok {
+ return
+ }
+
+ *s.done = true
+ s.timer.Stop()
+ delete(d.addresses, addr)
+
+ var err tcpip.Error
+ if aborted {
+ err = &tcpip.ErrAborted{}
+ }
+
+ r := stack.DADResult{Resolved: false, Err: err}
+ for _, h := range s.completionHandlers {
+ h(r)
+ }
+}
+
+// SetConfigsLocked sets the DAD configurations.
+//
+// Precondition: d.protocolMU must be locked.
+func (d *DAD) SetConfigsLocked(c stack.DADConfigurations) {
+ c.Validate()
+ d.configs = c
+}
diff --git a/pkg/tcpip/network/internal/ip/ip_state_autogen.go b/pkg/tcpip/network/internal/ip/ip_state_autogen.go
new file mode 100644
index 000000000..aee77044e
--- /dev/null
+++ b/pkg/tcpip/network/internal/ip/ip_state_autogen.go
@@ -0,0 +1,3 @@
+// automatically generated by stateify.
+
+package ip