Add loopback interface as an ethernet-based device
...to match Linux behaviour.
We can see evidence of Linux representing loopback as an ethernet-based
device below:
```
# EUI-48 based MAC addresses.
$ ip link show lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# tcpdump showing ethernet frames when sniffing loopback and logging the
# link-type as EN10MB (Ethernet).
$ sudo tcpdump -i lo -e -c 2 -n
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
03:09:05.002034 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 66: 127.0.0.1.9557 > 127.0.0.1.36828: Flags [.], ack 3562800815, win 15342, options [nop,nop,TS val 843174495 ecr 843159493], length 0
03:09:05.002094 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 66: 127.0.0.1.36828 > 127.0.0.1.9557: Flags [.], ack 1, win 6160, options [nop,nop,TS val 843174496 ecr 843159493], length 0
2 packets captured
116 packets received by filter
0 packets dropped by kernel
```
Wireshark shows a similar result as the tcpdump example above.
Linux's loopback setup: 5bfc75d92e/drivers/net/loopback.c (L162)
PiperOrigin-RevId: 391836719
This commit is contained in:
parent
50ed6b2e09
commit
3b4bb94751
|
@ -49,9 +49,9 @@ const (
|
|||
// EthernetAddressSize is the size, in bytes, of an ethernet address.
|
||||
EthernetAddressSize = 6
|
||||
|
||||
// unspecifiedEthernetAddress is the unspecified ethernet address
|
||||
// UnspecifiedEthernetAddress is the unspecified ethernet address
|
||||
// (all bits set to 0).
|
||||
unspecifiedEthernetAddress = tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00")
|
||||
UnspecifiedEthernetAddress = tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00")
|
||||
|
||||
// EthernetBroadcastAddress is an ethernet address that addresses every node
|
||||
// on a local link.
|
||||
|
@ -134,7 +134,7 @@ func IsValidUnicastEthernetAddress(addr tcpip.LinkAddress) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if addr == unspecifiedEthernetAddress {
|
||||
if addr == UnspecifiedEthernetAddress {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ func TestIsValidUnicastEthernetAddress(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"Unspecified",
|
||||
unspecifiedEthernetAddress,
|
||||
UnspecifiedEthernetAddress,
|
||||
false,
|
||||
},
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ func TestIsMulticastEthernetAddress(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"Unspecified",
|
||||
unspecifiedEthernetAddress,
|
||||
UnspecifiedEthernetAddress,
|
||||
false,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -42,6 +42,14 @@ type Endpoint struct {
|
|||
nested.Endpoint
|
||||
}
|
||||
|
||||
// LinkAddress implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) LinkAddress() tcpip.LinkAddress {
|
||||
if l := e.Endpoint.LinkAddress(); len(l) != 0 {
|
||||
return l
|
||||
}
|
||||
return header.UnspecifiedEthernetAddress
|
||||
}
|
||||
|
||||
// DeliverNetworkPacket implements stack.NetworkDispatcher.
|
||||
func (e *Endpoint) DeliverNetworkPacket(_, _ tcpip.LinkAddress, _ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
|
||||
hdr, ok := pkt.LinkHeader().Consume(header.EthernetMinimumSize)
|
||||
|
@ -57,18 +65,22 @@ func (e *Endpoint) DeliverNetworkPacket(_, _ tcpip.LinkAddress, _ tcpip.NetworkP
|
|||
|
||||
// Capabilities implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityResolutionRequired | e.Endpoint.Capabilities()
|
||||
c := e.Endpoint.Capabilities()
|
||||
if c&stack.CapabilityLoopback == 0 {
|
||||
c |= stack.CapabilityResolutionRequired
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// WritePacket implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) WritePacket(r stack.RouteInfo, proto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
|
||||
e.AddHeader(e.Endpoint.LinkAddress(), r.RemoteLinkAddress, proto, pkt)
|
||||
e.AddHeader(e.LinkAddress(), r.RemoteLinkAddress, proto, pkt)
|
||||
return e.Endpoint.WritePacket(r, proto, pkt)
|
||||
}
|
||||
|
||||
// WritePackets implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) WritePackets(r stack.RouteInfo, pkts stack.PacketBufferList, proto tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
|
||||
linkAddr := e.Endpoint.LinkAddress()
|
||||
linkAddr := e.LinkAddress()
|
||||
|
||||
for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
|
||||
e.AddHeader(linkAddr, r.RemoteLinkAddress, proto, pkt)
|
||||
|
@ -83,7 +95,10 @@ func (e *Endpoint) MaxHeaderLength() uint16 {
|
|||
}
|
||||
|
||||
// ARPHardwareType implements stack.LinkEndpoint.
|
||||
func (*Endpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
func (e *Endpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
if a := e.Endpoint.ARPHardwareType(); a != header.ARPHardwareNone {
|
||||
return a
|
||||
}
|
||||
return header.ARPHardwareEther
|
||||
}
|
||||
|
||||
|
|
|
@ -321,28 +321,26 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp
|
|||
}
|
||||
defer route.Release()
|
||||
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(route.MaxHeaderLength()),
|
||||
Data: buffer.View(payloadBytes).ToVectorisedView(),
|
||||
})
|
||||
pkt.Owner = owner
|
||||
|
||||
if e.ops.GetHeaderIncluded() {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.View(payloadBytes).ToVectorisedView(),
|
||||
})
|
||||
if err := route.WriteHeaderIncludedPacket(pkt); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(route.MaxHeaderLength()),
|
||||
Data: buffer.View(payloadBytes).ToVectorisedView(),
|
||||
})
|
||||
pkt.Owner = owner
|
||||
if err := route.WritePacket(stack.NetworkHeaderParams{
|
||||
Protocol: e.TransProto,
|
||||
TTL: route.DefaultTTL(),
|
||||
TOS: stack.DefaultTOS,
|
||||
}, pkt); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int64(len(payloadBytes)), nil
|
||||
}
|
||||
|
||||
if err := route.WritePacket(stack.NetworkHeaderParams{
|
||||
Protocol: e.TransProto,
|
||||
TTL: route.DefaultTTL(),
|
||||
TOS: stack.DefaultTOS,
|
||||
}, pkt); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int64(len(payloadBytes)), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ go_library(
|
|||
"//pkg/sentry/watchdog",
|
||||
"//pkg/sync",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/link/ethernet",
|
||||
"//pkg/tcpip/link/fdbased",
|
||||
"//pkg/tcpip/link/loopback",
|
||||
"//pkg/tcpip/link/packetsocket",
|
||||
|
|
|
@ -58,6 +58,7 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/sentry/watchdog"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/ethernet"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/loopback"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/sniffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/arp"
|
||||
|
@ -1174,7 +1175,7 @@ func (f *sandboxNetstackCreator) CreateStack() (inet.Stack, error) {
|
|||
n := &Network{Stack: s.(*netstack.Stack).Stack}
|
||||
nicID := tcpip.NICID(f.uniqueID.UniqueID())
|
||||
link := DefaultLoopbackLink
|
||||
linkEP := loopback.New()
|
||||
linkEP := ethernet.New(loopback.New())
|
||||
if err := n.createNICWithAddrs(nicID, link.Name, linkEP, link.Addresses); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/ethernet"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/loopback"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/packetsocket"
|
||||
|
@ -169,7 +170,7 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
|
|||
nicID++
|
||||
nicids[link.Name] = nicID
|
||||
|
||||
linkEP := loopback.New()
|
||||
linkEP := ethernet.New(loopback.New())
|
||||
|
||||
log.Infof("Enabling loopback interface %q with id %d on addresses %+v", link.Name, nicID, link.Addresses)
|
||||
if err := n.createNICWithAddrs(nicID, link.Name, linkEP, link.Addresses); err != nil {
|
||||
|
|
Loading…
Reference in New Issue