Allow clients to store an opaque NICContext with NICs

...retrievable later via stack.NICInfo().

Clients of this library can use it to add metadata that should be tracked
alongside a NIC, to avoid having to keep a map[tcpip.NICID]metadata mirroring
stack.Stack's nic map.

PiperOrigin-RevId: 288924900
This commit is contained in:
Bert Muthalaly
2020-01-09 10:46:01 -08:00
committed by gVisor bot
parent 290908fa8a
commit e752ddbb72
3 changed files with 62 additions and 6 deletions
+7 -5
View File
@@ -27,10 +27,11 @@ import (
// NIC represents a "network interface card" to which the networking stack is
// attached.
type NIC struct {
stack *Stack
id tcpip.NICID
name string
linkEP LinkEndpoint
stack *Stack
id tcpip.NICID
name string
linkEP LinkEndpoint
context NICContext
mu sync.RWMutex
spoofing bool
@@ -84,7 +85,7 @@ const (
)
// newNIC returns a new NIC using the default NDP configurations from stack.
func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint) *NIC {
func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICContext) *NIC {
// TODO(b/141011931): Validate a LinkEndpoint (ep) is valid. For
// example, make sure that the link address it provides is a valid
// unicast ethernet address.
@@ -98,6 +99,7 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint) *NIC {
id: id,
name: name,
linkEP: ep,
context: ctx,
primary: make(map[tcpip.NetworkProtocolNumber][]*referencedNetworkEndpoint),
endpoints: make(map[NetworkEndpointID]*referencedNetworkEndpoint),
mcastJoins: make(map[NetworkEndpointID]int32),
+15 -1
View File
@@ -796,6 +796,9 @@ func (s *Stack) NewPacketEndpoint(cooked bool, netProto tcpip.NetworkProtocolNum
return s.rawFactory.NewPacketEndpoint(s, cooked, netProto, waiterQueue)
}
// NICContext is an opaque pointer used to store client-supplied NIC metadata.
type NICContext interface{}
// NICOptions specifies the configuration of a NIC as it is being created.
// The zero value creates an enabled, unnamed NIC.
type NICOptions struct {
@@ -805,6 +808,12 @@ type NICOptions struct {
// Disabled specifies whether to avoid calling Attach on the passed
// LinkEndpoint.
Disabled bool
// Context specifies user-defined data that will be returned in stack.NICInfo
// for the NIC. Clients of this library can use it to add metadata that
// should be tracked alongside a NIC, to avoid having to keep a
// map[tcpip.NICID]metadata mirroring stack.Stack's nic map.
Context NICContext
}
// CreateNICWithOptions creates a NIC with the provided id, LinkEndpoint, and
@@ -819,7 +828,7 @@ func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOp
return tcpip.ErrDuplicateNICID
}
n := newNIC(s, id, opts.Name, ep)
n := newNIC(s, id, opts.Name, ep, opts.Context)
s.nics[id] = n
if !opts.Disabled {
@@ -886,6 +895,10 @@ type NICInfo struct {
MTU uint32
Stats NICStats
// Context is user-supplied data optionally supplied in CreateNICWithOptions.
// See type NICOptions for more details.
Context NICContext
}
// NICInfo returns a map of NICIDs to their associated information.
@@ -908,6 +921,7 @@ func (s *Stack) NICInfo() map[tcpip.NICID]NICInfo {
Flags: flags,
MTU: nic.linkEP.MTU(),
Stats: nic.stats,
Context: nic.context,
}
}
return nics
+40
View File
@@ -2001,6 +2001,46 @@ func TestNICAutoGenAddr(t *testing.T) {
}
}
// TestNICContextPreservation tests that you can read out via stack.NICInfo the
// Context data you pass via NICContext.Context in stack.CreateNICWithOptions.
func TestNICContextPreservation(t *testing.T) {
var ctx *int
tests := []struct {
name string
opts stack.NICOptions
want stack.NICContext
}{
{
"context_set",
stack.NICOptions{Context: ctx},
ctx,
},
{
"context_not_set",
stack.NICOptions{},
nil,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
s := stack.New(stack.Options{})
id := tcpip.NICID(1)
ep := channel.New(0, 0, tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00"))
if err := s.CreateNICWithOptions(id, ep, test.opts); err != nil {
t.Fatalf("got stack.CreateNICWithOptions(%d, %+v, %+v) = %s, want nil", id, ep, test.opts, err)
}
nicinfos := s.NICInfo()
nicinfo, ok := nicinfos[id]
if !ok {
t.Fatalf("got nicinfos[%d] = _, %t, want _, true; nicinfos = %+v", id, ok, nicinfos)
}
if got, want := nicinfo.Context == test.want, true; got != want {
t.Fatal("got nicinfo.Context == ctx = %t, want %t; nicinfo.Context = %p, ctx = %p", got, want, nicinfo.Context, test.want)
}
})
}
}
// TestNICAutoGenAddrWithOpaque tests the auto-generation of IPv6 link-local
// addresses with opaque interface identifiers. Link Local addresses should
// always be generated with opaque IIDs if configured to use them, even if the