sentry: Add simple SIOCGIFFLAGS support (IFF_RUNNING and IFF_PROMIS).

Establishes a way of communicating interface flags between netstack and
epsocket. More flags can be added over time.

PiperOrigin-RevId: 197616669
Change-Id: I230448c5fb5b7d2e8d69b41a451eb4e1096a0e30
This commit is contained in:
Kevin Krakauer 2018-05-22 13:46:37 -07:00 committed by Shentubot
parent 3a6070dc98
commit 705605f901
11 changed files with 138 additions and 6 deletions

View File

@ -48,12 +48,15 @@ import (
"gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
nstack "gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/unix"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
const sizeOfInt32 int = 4
var errStackType = syserr.New("expected but did not receive an epsocket.Stack", linux.EINVAL)
// ntohs converts a 16-bit number from network byte order to host byte order. It
// assumes that the host is little endian.
func ntohs(v uint16) uint16 {
@ -1177,9 +1180,11 @@ func interfaceIoctl(ctx context.Context, io usermem.IO, arg int, ifr *linux.IFRe
usermem.ByteOrder.PutUint16(ifr.Data[:2], uint16(n))
case syscall.SIOCGIFFLAGS:
// TODO: Implement. For now, return only that the
// device is up so that ifconfig prints it.
usermem.ByteOrder.PutUint16(ifr.Data[:2], linux.IFF_UP)
f, err := interfaceStatusFlags(stack, iface.Name)
if err != nil {
return err
}
usermem.ByteOrder.PutUint16(ifr.Data[:2], f)
case syscall.SIOCGIFADDR:
// Copy the IPv4 address out.
@ -1288,3 +1293,49 @@ func ifconfIoctl(ctx context.Context, io usermem.IO, ifc *linux.IFConf) error {
}
return nil
}
// interfaceStatusFlags returns status flags for an interface in the stack.
// Flag values and meanings are described in greater detail in netdevice(7) in
// the SIOCGIFFLAGS section.
func interfaceStatusFlags(stack inet.Stack, name string) (uint16, *syserr.Error) {
// epsocket should only ever be passed an epsocket.Stack.
epstack, ok := stack.(*Stack)
if !ok {
return 0, errStackType
}
// Find the NIC corresponding to this interface.
var (
nicid tcpip.NICID
info nstack.NICInfo
found bool
)
ns := epstack.Stack
for nicid, info = range ns.NICInfo() {
if info.Name == name {
found = true
break
}
}
if !found {
return 0, syserr.ErrNoDevice
}
// Set flags based on NIC state.
nicFlags, err := ns.NICFlags(nicid)
if err != nil {
return 0, syserr.TranslateNetstackError(err)
}
var retFlags uint16
if nicFlags.Up {
retFlags |= linux.IFF_UP
}
if nicFlags.Running {
retFlags |= linux.IFF_RUNNING
}
if nicFlags.Promiscuous {
retFlags |= linux.IFF_PROMISC
}
return retFlags, nil
}

View File

@ -67,6 +67,11 @@ func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.dispatcher = dispatcher
}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (e *Endpoint) IsAttached() bool {
return e.dispatcher != nil
}
// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized
// during construction.
func (e *Endpoint) MTU() uint32 {

View File

@ -45,9 +45,10 @@ type endpoint struct {
// its end of the communication pipe.
closed func(*tcpip.Error)
vv *buffer.VectorisedView
iovecs []syscall.Iovec
views []buffer.View
vv *buffer.VectorisedView
iovecs []syscall.Iovec
views []buffer.View
attached bool
}
// Options specify the details about the fd-based endpoint to be created.
@ -96,9 +97,15 @@ func New(opts *Options) tcpip.LinkEndpointID {
// Attach launches the goroutine that reads packets from the file descriptor and
// dispatches them via the provided dispatcher.
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.attached = true
go e.dispatchLoop(dispatcher) // S/R-FIXME
}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (e *endpoint) IsAttached() bool {
return e.attached
}
// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized
// during construction.
func (e *endpoint) MTU() uint32 {

View File

@ -32,6 +32,11 @@ func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.dispatcher = dispatcher
}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (e *endpoint) IsAttached() bool {
return e.dispatcher != nil
}
// MTU implements stack.LinkEndpoint.MTU. It returns a constant that matches the
// linux loopback interface.
func (*endpoint) MTU() uint32 {

View File

@ -137,6 +137,13 @@ func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.mu.Unlock()
}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (e *endpoint) IsAttached() bool {
e.mu.Lock()
defer e.mu.Unlock()
return e.workerStarted
}
// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized
// during construction.
func (e *endpoint) MTU() uint32 {

View File

@ -143,6 +143,11 @@ func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.lower.Attach(e)
}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (e *endpoint) IsAttached() bool {
return e.dispatcher != nil
}
// MTU implements stack.LinkEndpoint.MTU. It just forwards the request to the
// lower endpoint.
func (e *endpoint) MTU() uint32 {

View File

@ -58,6 +58,11 @@ func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.lower.Attach(e)
}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (e *Endpoint) IsAttached() bool {
return e.dispatcher != nil
}
// MTU implements stack.LinkEndpoint.MTU. It just forwards the request to the
// lower endpoint.
func (e *Endpoint) MTU() uint32 {

View File

@ -34,6 +34,11 @@ func (e *countedEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.dispatcher = dispatcher
}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (e *countedEndpoint) IsAttached() bool {
return e.dispatcher != nil
}
func (e *countedEndpoint) MTU() uint32 {
return e.mtu
}

View File

@ -90,6 +90,11 @@ func (t *testObject) DeliverTransportControlPacket(local, remote tcpip.Address,
// Attach is only implemented to satisfy the LinkEndpoint interface.
func (*testObject) Attach(stack.NetworkDispatcher) {}
// IsAttached implements stack.LinkEndpoint.IsAttached.
func (*testObject) IsAttached() bool {
return true
}
// MTU implements stack.LinkEndpoint.MTU. It just returns a constant that
// matches the linux loopback MTU.
func (*testObject) MTU() uint32 {

View File

@ -224,6 +224,10 @@ type LinkEndpoint interface {
// Attach attaches the data link layer endpoint to the network-layer
// dispatcher of the stack.
Attach(dispatcher NetworkDispatcher)
// IsAttached returns whether a NetworkDispatcher is attached to the
// endpoint.
IsAttached() bool
}
// A LinkAddressResolver is an extension to a NetworkProtocol that

View File

@ -541,6 +541,39 @@ func (s *Stack) NICInfo() map[tcpip.NICID]NICInfo {
return nics
}
// NICStateFlags holds information about the state of an NIC.
type NICStateFlags struct {
// Up indicates whether the interface is running.
Up bool
// Running indicates whether resources are allocated.
Running bool
// Promiscuous indicates whether the interface is in promiscuous mode.
Promiscuous bool
}
// NICFlags returns flags about the state of the NIC. It returns an error if
// the NIC corresponding to id cannot be found.
func (s *Stack) NICFlags(id tcpip.NICID) (NICStateFlags, *tcpip.Error) {
s.mu.RLock()
defer s.mu.RUnlock()
nic := s.nics[id]
if nic == nil {
return NICStateFlags{}, tcpip.ErrUnknownNICID
}
ret := NICStateFlags{
// Netstack interfaces are always up.
Up: true,
Running: nic.linkEP.IsAttached(),
Promiscuous: nic.promiscuous,
}
return ret, nil
}
// AddAddress adds a new network-layer address to the specified NIC.
func (s *Stack) AddAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error {
s.mu.RLock()