Attach LinkEndpoint to NetworkDispatcher immediately

Tests: stack_test.TestAttachToLinkEndpointImmediately
PiperOrigin-RevId: 296474068
This commit is contained in:
Ghanan Gowripalan 2020-02-21 11:20:15 -08:00 committed by Copybara-Service
parent d8e60e7867
commit a155a23480
3 changed files with 68 additions and 18 deletions

View File

@ -45,7 +45,6 @@ type NIC struct {
context NICContext
stats NICStats
attach sync.Once
mu struct {
sync.RWMutex
@ -141,6 +140,8 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
nic.mu.packetEPs[netProto.Number()] = []PacketEndpoint{}
}
nic.linkEP.Attach(nic)
return nic
}
@ -200,14 +201,16 @@ func (n *NIC) disable() *tcpip.Error {
}
}
// TODO(b/147015577): Should n detach from its LinkEndpoint?
n.mu.enabled = false
return nil
}
// enable enables n. enable will attach the nic to its LinkEndpoint and
// join the IPv6 All-Nodes Multicast address (ff02::1).
// enable enables n.
//
// If the stack has IPv6 enabled, enable will join the IPv6 All-Nodes Multicast
// address (ff02::1), start DAD for permanent addresses, and start soliciting
// routers if the stack is not operating as a router. If the stack is also
// configured to auto-generate a link-local address, one will be generated.
func (n *NIC) enable() *tcpip.Error {
n.mu.RLock()
enabled := n.mu.enabled
@ -225,8 +228,6 @@ func (n *NIC) enable() *tcpip.Error {
n.mu.enabled = true
n.attachLinkEndpoint()
// Create an endpoint to receive broadcast packets on this interface.
if _, ok := n.stack.networkProtocols[header.IPv4ProtocolNumber]; ok {
if _, err := n.addAddressLocked(ipv4BroadcastAddr, NeverPrimaryEndpoint, permanent, static, false /* deprecated */); err != nil {
@ -321,14 +322,6 @@ func (n *NIC) becomeIPv6Host() {
n.mu.ndp.startSolicitingRouters()
}
// attachLinkEndpoint attaches the NIC to the endpoint, which will enable it
// to start delivering packets.
func (n *NIC) attachLinkEndpoint() {
n.attach.Do(func() {
n.linkEP.Attach(n)
})
}
// setPromiscuousMode enables or disables promiscuous mode.
func (n *NIC) setPromiscuousMode(enable bool) {
n.mu.Lock()

View File

@ -881,6 +881,8 @@ type NICOptions struct {
// CreateNICWithOptions creates a NIC with the provided id, LinkEndpoint, and
// NICOptions. See the documentation on type NICOptions for details on how
// NICs can be configured.
//
// LinkEndpoint.Attach will be called to bind ep with a NetworkDispatcher.
func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOptions) *tcpip.Error {
s.mu.Lock()
defer s.mu.Unlock()
@ -900,7 +902,6 @@ func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOp
}
n := newNIC(s, id, opts.Name, ep, opts.Context)
s.nics[id] = n
if !opts.Disabled {
return n.enable()
@ -910,7 +911,7 @@ func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOp
}
// CreateNIC creates a NIC with the provided id and LinkEndpoint and calls
// `LinkEndpoint.Attach` to start delivering packets to it.
// LinkEndpoint.Attach to bind ep with a NetworkDispatcher.
func (s *Stack) CreateNIC(id tcpip.NICID, ep LinkEndpoint) *tcpip.Error {
return s.CreateNICWithOptions(id, ep, NICOptions{})
}

View File

@ -239,6 +239,23 @@ func fakeNetFactory() stack.NetworkProtocol {
return &fakeNetworkProtocol{}
}
// linkEPWithMockedAttach is a stack.LinkEndpoint that tests can use to verify
// that LinkEndpoint.Attach was called.
type linkEPWithMockedAttach struct {
stack.LinkEndpoint
attached bool
}
// Attach implements stack.LinkEndpoint.Attach.
func (l *linkEPWithMockedAttach) Attach(d stack.NetworkDispatcher) {
l.LinkEndpoint.Attach(d)
l.attached = true
}
func (l *linkEPWithMockedAttach) isAttached() bool {
return l.attached
}
func TestNetworkReceive(t *testing.T) {
// Create a stack with the fake network protocol, one nic, and two
// addresses attached to it: 1 & 2.
@ -510,6 +527,45 @@ func testNoRoute(t *testing.T, s *stack.Stack, nic tcpip.NICID, srcAddr, dstAddr
}
}
// TestAttachToLinkEndpointImmediately tests that a LinkEndpoint is attached to
// a NetworkDispatcher when the NIC is created.
func TestAttachToLinkEndpointImmediately(t *testing.T) {
const nicID = 1
tests := []struct {
name string
nicOpts stack.NICOptions
}{
{
name: "Create enabled NIC",
nicOpts: stack.NICOptions{Disabled: false},
},
{
name: "Create disabled NIC",
nicOpts: stack.NICOptions{Disabled: true},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocol{fakeNetFactory()},
})
e := linkEPWithMockedAttach{
LinkEndpoint: loopback.New(),
}
if err := s.CreateNICWithOptions(nicID, &e, test.nicOpts); err != nil {
t.Fatalf("CreateNICWithOptions(%d, _, %+v) = %s", nicID, test.nicOpts, err)
}
if !e.isAttached() {
t.Fatalf("link endpoint not attached to a network disatcher")
}
})
}
}
func TestDisableUnknownNIC(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocol{fakeNetFactory()},