mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Pass NetworkInterface to LinkAddressRequest
Previously a link endpoint was passed to
stack.LinkAddressResolver.LinkAddressRequest. With this change,
implementations that want a route for the link address request may
find one through the stack. Other implementations that want to send
a packet without a route may continue to do so using the network
interface directly.
Test: - arp_test.TestLinkAddressRequest
- ipv6.TestLinkAddressRequest
PiperOrigin-RevId: 338577474
This commit is contained in:
committed by
gVisor bot
parent
c188daf889
commit
c1a6ba06ab
@@ -18,6 +18,7 @@
|
||||
package arp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
@@ -153,25 +154,33 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
e.nud.HandleProbe(remoteAddr, localAddr, ProtocolNumber, remoteLinkAddr, e.protocol)
|
||||
}
|
||||
|
||||
// As per RFC 826, under Packet Reception:
|
||||
// Swap hardware and protocol fields, putting the local hardware and
|
||||
// protocol addresses in the sender fields.
|
||||
//
|
||||
// Send the packet to the (new) target hardware address on the same
|
||||
// hardware on which the request was received.
|
||||
origSender := h.HardwareAddressSender()
|
||||
r.RemoteLinkAddress = tcpip.LinkAddress(origSender)
|
||||
respPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(e.nic.MaxHeaderLength()) + header.ARPSize,
|
||||
})
|
||||
packet := header.ARP(respPkt.NetworkHeader().Push(header.ARPSize))
|
||||
packet.SetIPv4OverEthernet()
|
||||
packet.SetOp(header.ARPReply)
|
||||
copy(packet.HardwareAddressSender(), r.LocalLinkAddress[:])
|
||||
copy(packet.ProtocolAddressSender(), h.ProtocolAddressTarget())
|
||||
copy(packet.HardwareAddressTarget(), origSender)
|
||||
copy(packet.ProtocolAddressTarget(), h.ProtocolAddressSender())
|
||||
_ = e.nic.WritePacket(r, nil /* gso */, ProtocolNumber, respPkt)
|
||||
// TODO(gvisor.dev/issue/4582): check copied length once TAP devices have a
|
||||
// link address.
|
||||
_ = copy(packet.HardwareAddressSender(), e.nic.LinkAddress())
|
||||
if n := copy(packet.ProtocolAddressSender(), h.ProtocolAddressTarget()); n != header.IPv4AddressSize {
|
||||
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
|
||||
}
|
||||
origSender := h.HardwareAddressSender()
|
||||
if n := copy(packet.HardwareAddressTarget(), origSender); n != header.EthernetAddressSize {
|
||||
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.EthernetAddressSize))
|
||||
}
|
||||
if n := copy(packet.ProtocolAddressTarget(), h.ProtocolAddressSender()); n != header.IPv4AddressSize {
|
||||
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
|
||||
}
|
||||
|
||||
// As per RFC 826, under Packet Reception:
|
||||
// Swap hardware and protocol fields, putting the local hardware and
|
||||
// protocol addresses in the sender fields.
|
||||
//
|
||||
// Send the packet to the (new) target hardware address on the same
|
||||
// hardware on which the request was received.
|
||||
_ = e.nic.WritePacketToRemote(tcpip.LinkAddress(origSender), nil /* gso */, ProtocolNumber, respPkt)
|
||||
|
||||
case header.ARPReply:
|
||||
addr := tcpip.Address(h.ProtocolAddressSender())
|
||||
@@ -227,26 +236,28 @@ func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
}
|
||||
|
||||
// LinkAddressRequest implements stack.LinkAddressResolver.LinkAddressRequest.
|
||||
func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP stack.LinkEndpoint) *tcpip.Error {
|
||||
r := &stack.Route{
|
||||
NetProto: ProtocolNumber,
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
}
|
||||
if len(r.RemoteLinkAddress) == 0 {
|
||||
r.RemoteLinkAddress = header.EthernetBroadcastAddress
|
||||
func (*protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, nic stack.NetworkInterface) *tcpip.Error {
|
||||
if len(remoteLinkAddr) == 0 {
|
||||
remoteLinkAddr = header.EthernetBroadcastAddress
|
||||
}
|
||||
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(linkEP.MaxHeaderLength()) + header.ARPSize,
|
||||
ReserveHeaderBytes: int(nic.MaxHeaderLength()) + header.ARPSize,
|
||||
})
|
||||
h := header.ARP(pkt.NetworkHeader().Push(header.ARPSize))
|
||||
pkt.NetworkProtocolNumber = ProtocolNumber
|
||||
h.SetIPv4OverEthernet()
|
||||
h.SetOp(header.ARPRequest)
|
||||
copy(h.HardwareAddressSender(), linkEP.LinkAddress())
|
||||
copy(h.ProtocolAddressSender(), localAddr)
|
||||
copy(h.ProtocolAddressTarget(), addr)
|
||||
|
||||
return linkEP.WritePacket(r, nil /* gso */, ProtocolNumber, pkt)
|
||||
// TODO(gvisor.dev/issue/4582): check copied length once TAP devices have a
|
||||
// link address.
|
||||
_ = copy(h.HardwareAddressSender(), nic.LinkAddress())
|
||||
if n := copy(h.ProtocolAddressSender(), localAddr); n != header.IPv4AddressSize {
|
||||
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
|
||||
}
|
||||
if n := copy(h.ProtocolAddressTarget(), targetAddr); n != header.IPv4AddressSize {
|
||||
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
|
||||
}
|
||||
return nic.WritePacketToRemote(remoteLinkAddr, nil /* gso */, ProtocolNumber, pkt)
|
||||
}
|
||||
|
||||
// ResolveStaticAddress implements stack.LinkAddressResolver.ResolveStaticAddress.
|
||||
|
||||
@@ -423,6 +423,36 @@ func TestDirectRequestWithNeighborCache(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var _ stack.NetworkInterface = (*testInterface)(nil)
|
||||
|
||||
type testInterface struct {
|
||||
stack.LinkEndpoint
|
||||
}
|
||||
|
||||
func (*testInterface) ID() tcpip.NICID {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (*testInterface) IsLoopback() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (*testInterface) Name() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (*testInterface) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (t *testInterface) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
r := stack.Route{
|
||||
NetProto: protocol,
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
}
|
||||
return t.LinkEndpoint.WritePacket(&r, gso, protocol, pkt)
|
||||
}
|
||||
|
||||
func TestLinkAddressRequest(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -449,7 +479,7 @@ func TestLinkAddressRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
linkEP := channel.New(defaultChannelSize, defaultMTU, stackLinkAddr)
|
||||
if err := linkRes.LinkAddressRequest(stackAddr, remoteAddr, test.remoteLinkAddr, linkEP); err != nil {
|
||||
if err := linkRes.LinkAddressRequest(stackAddr, remoteAddr, test.remoteLinkAddr, &testInterface{LinkEndpoint: linkEP}); err != nil {
|
||||
t.Errorf("got p.LinkAddressRequest(%s, %s, %s, _) = %s", stackAddr, remoteAddr, test.remoteLinkAddr, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -304,6 +304,10 @@ func (t *testInterface) setEnabled(v bool) {
|
||||
t.mu.disabled = !v
|
||||
}
|
||||
|
||||
func (*testInterface) WritePacketToRemote(tcpip.LinkAddress, *stack.GSO, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) *tcpip.Error {
|
||||
return tcpip.ErrNotSupported
|
||||
}
|
||||
|
||||
func TestSourceAddressValidation(t *testing.T) {
|
||||
rxIPv4ICMP := func(e *channel.Endpoint, src tcpip.Address) {
|
||||
totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize
|
||||
|
||||
@@ -651,52 +651,46 @@ func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
}
|
||||
|
||||
// LinkAddressRequest implements stack.LinkAddressResolver.
|
||||
func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP stack.LinkEndpoint) *tcpip.Error {
|
||||
// TODO(b/148672031): Use stack.FindRoute instead of manually creating the
|
||||
// route here. Note, we would need the nicID to do this properly so the right
|
||||
// NIC (associated to linkEP) is used to send the NDP NS message.
|
||||
r := stack.Route{
|
||||
LocalAddress: localAddr,
|
||||
RemoteAddress: addr,
|
||||
LocalLinkAddress: linkEP.LinkAddress(),
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
func (p *protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, nic stack.NetworkInterface) *tcpip.Error {
|
||||
remoteAddr := targetAddr
|
||||
if len(remoteLinkAddr) == 0 {
|
||||
remoteAddr = header.SolicitedNodeAddr(targetAddr)
|
||||
remoteLinkAddr = header.EthernetAddressFromMulticastIPv6Address(remoteAddr)
|
||||
}
|
||||
|
||||
// If a remote address is not already known, then send a multicast
|
||||
// solicitation since multicast addresses have a static mapping to link
|
||||
// addresses.
|
||||
if len(r.RemoteLinkAddress) == 0 {
|
||||
r.RemoteAddress = header.SolicitedNodeAddr(addr)
|
||||
r.RemoteLinkAddress = header.EthernetAddressFromMulticastIPv6Address(r.RemoteAddress)
|
||||
r, err := p.stack.FindRoute(nic.ID(), localAddr, remoteAddr, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Release()
|
||||
r.ResolveWith(remoteLinkAddr)
|
||||
|
||||
optsSerializer := header.NDPOptionsSerializer{
|
||||
header.NDPSourceLinkLayerAddressOption(linkEP.LinkAddress()),
|
||||
header.NDPSourceLinkLayerAddressOption(nic.LinkAddress()),
|
||||
}
|
||||
neighborSolicitSize := header.ICMPv6NeighborSolicitMinimumSize + optsSerializer.Length()
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(linkEP.MaxHeaderLength()) + header.IPv6MinimumSize + neighborSolicitSize,
|
||||
ReserveHeaderBytes: int(r.MaxHeaderLength()) + neighborSolicitSize,
|
||||
})
|
||||
pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
packet := header.ICMPv6(pkt.TransportHeader().Push(neighborSolicitSize))
|
||||
packet.SetType(header.ICMPv6NeighborSolicit)
|
||||
ns := header.NDPNeighborSolicit(packet.NDPPayload())
|
||||
ns.SetTargetAddress(addr)
|
||||
ns.SetTargetAddress(targetAddr)
|
||||
ns.Options().Serialize(optsSerializer)
|
||||
packet.SetChecksum(header.ICMPv6Checksum(packet, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
|
||||
|
||||
length := uint16(pkt.Size())
|
||||
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
PayloadLength: length,
|
||||
NextHeader: uint8(header.ICMPv6ProtocolNumber),
|
||||
HopLimit: header.NDPHopLimit,
|
||||
SrcAddr: r.LocalAddress,
|
||||
DstAddr: r.RemoteAddress,
|
||||
})
|
||||
stat := p.stack.Stats().ICMP.V6PacketsSent
|
||||
if err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv6ProtocolNumber,
|
||||
TTL: header.NDPHopLimit,
|
||||
}, pkt); err != nil {
|
||||
stat.Dropped.Increment()
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(stijlist): count this in ICMP stats.
|
||||
return linkEP.WritePacket(&r, nil /* gso */, ProtocolNumber, pkt)
|
||||
stat.NeighborSolicit.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolveStaticAddress implements stack.LinkAddressResolver.
|
||||
|
||||
@@ -122,17 +122,13 @@ func (*stubNUDHandler) HandleUpperLevelConfirmation(addr tcpip.Address) {
|
||||
var _ stack.NetworkInterface = (*testInterface)(nil)
|
||||
|
||||
type testInterface struct {
|
||||
stack.NetworkLinkEndpoint
|
||||
stack.LinkEndpoint
|
||||
|
||||
linkAddr tcpip.LinkAddress
|
||||
}
|
||||
|
||||
func (i *testInterface) LinkAddress() tcpip.LinkAddress {
|
||||
return i.linkAddr
|
||||
nicID tcpip.NICID
|
||||
}
|
||||
|
||||
func (*testInterface) ID() tcpip.NICID {
|
||||
return 0
|
||||
return nicID
|
||||
}
|
||||
|
||||
func (*testInterface) IsLoopback() bool {
|
||||
@@ -147,6 +143,14 @@ func (*testInterface) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (t *testInterface) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
r := stack.Route{
|
||||
NetProto: protocol,
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
}
|
||||
return t.LinkEndpoint.WritePacket(&r, gso, protocol, pkt)
|
||||
}
|
||||
|
||||
func TestICMPCounts(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1235,6 +1239,8 @@ func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLinkAddressRequest(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
snaddr := header.SolicitedNodeAddr(lladdr0)
|
||||
mcaddr := header.EthernetAddressFromMulticastIPv6Address(snaddr)
|
||||
|
||||
@@ -1269,7 +1275,18 @@ func TestLinkAddressRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
linkEP := channel.New(defaultChannelSize, defaultMTU, linkAddr0)
|
||||
if err := linkRes.LinkAddressRequest(lladdr0, lladdr1, test.remoteLinkAddr, linkEP); err != nil {
|
||||
if err := s.CreateNIC(nicID, linkEP); err != nil {
|
||||
t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
|
||||
}
|
||||
if err := s.AddAddress(nicID, ProtocolNumber, lladdr1); err != nil {
|
||||
t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, ProtocolNumber, lladdr1, err)
|
||||
}
|
||||
|
||||
// We pass a test network interface to LinkAddressRequest with the same NIC
|
||||
// ID and link endpoint used by the NIC we created earlier so that we can
|
||||
// mock a link address request and observe the packets sent to the link
|
||||
// endpoint even though the stack uses the real NIC.
|
||||
if err := linkRes.LinkAddressRequest(lladdr0, lladdr1, test.remoteLinkAddr, &testInterface{LinkEndpoint: linkEP, nicID: nicID}); err != nil {
|
||||
t.Errorf("got p.LinkAddressRequest(%s, %s, %s, _) = %s", lladdr0, lladdr1, test.remoteLinkAddr, err)
|
||||
}
|
||||
|
||||
@@ -1698,7 +1715,7 @@ func TestCallsToNeighborCache(t *testing.T) {
|
||||
t.Fatalf("cannot find protocol instance for network protocol %d", ProtocolNumber)
|
||||
}
|
||||
nudHandler := &stubNUDHandler{}
|
||||
ep := netProto.NewEndpoint(&testInterface{linkAddr: linkAddr0}, &stubLinkAddressCache{}, nudHandler, &stubDispatcher{})
|
||||
ep := netProto.NewEndpoint(&testInterface{LinkEndpoint: channel.New(0, header.IPv6MinimumMTU, linkAddr0)}, &stubLinkAddressCache{}, nudHandler, &stubDispatcher{})
|
||||
defer ep.Close()
|
||||
|
||||
if err := ep.Enable(); err != nil {
|
||||
|
||||
@@ -178,7 +178,7 @@ func (*fwdTestNetworkProtocol) Close() {}
|
||||
|
||||
func (*fwdTestNetworkProtocol) Wait() {}
|
||||
|
||||
func (f *fwdTestNetworkProtocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP LinkEndpoint) *tcpip.Error {
|
||||
func (f *fwdTestNetworkProtocol) LinkAddressRequest(addr, _ tcpip.Address, remoteLinkAddr tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
|
||||
if f.onLinkAddressResolved != nil {
|
||||
time.AfterFunc(f.addrResolveDelay, func() {
|
||||
f.onLinkAddressResolved(f.addrCache, f.neigh, addr, remoteLinkAddr)
|
||||
|
||||
@@ -180,7 +180,7 @@ func (c *linkAddrCache) getOrCreateEntryLocked(k tcpip.FullAddress) *linkAddrEnt
|
||||
}
|
||||
|
||||
// get reports any known link address for k.
|
||||
func (c *linkAddrCache) get(k tcpip.FullAddress, linkRes LinkAddressResolver, localAddr tcpip.Address, linkEP LinkEndpoint, waker *sleep.Waker) (tcpip.LinkAddress, <-chan struct{}, *tcpip.Error) {
|
||||
func (c *linkAddrCache) get(k tcpip.FullAddress, linkRes LinkAddressResolver, localAddr tcpip.Address, nic NetworkInterface, waker *sleep.Waker) (tcpip.LinkAddress, <-chan struct{}, *tcpip.Error) {
|
||||
if linkRes != nil {
|
||||
if addr, ok := linkRes.ResolveStaticAddress(k.Addr); ok {
|
||||
return addr, nil, nil
|
||||
@@ -221,7 +221,7 @@ func (c *linkAddrCache) get(k tcpip.FullAddress, linkRes LinkAddressResolver, lo
|
||||
}
|
||||
|
||||
entry.done = make(chan struct{})
|
||||
go c.startAddressResolution(k, linkRes, localAddr, linkEP, entry.done) // S/R-SAFE: link non-savable; wakers dropped synchronously.
|
||||
go c.startAddressResolution(k, linkRes, localAddr, nic, entry.done) // S/R-SAFE: link non-savable; wakers dropped synchronously.
|
||||
}
|
||||
|
||||
return entry.linkAddr, entry.done, tcpip.ErrWouldBlock
|
||||
@@ -240,11 +240,11 @@ func (c *linkAddrCache) removeWaker(k tcpip.FullAddress, waker *sleep.Waker) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *linkAddrCache) startAddressResolution(k tcpip.FullAddress, linkRes LinkAddressResolver, localAddr tcpip.Address, linkEP LinkEndpoint, done <-chan struct{}) {
|
||||
func (c *linkAddrCache) startAddressResolution(k tcpip.FullAddress, linkRes LinkAddressResolver, localAddr tcpip.Address, nic NetworkInterface, done <-chan struct{}) {
|
||||
for i := 0; ; i++ {
|
||||
// Send link request, then wait for the timeout limit and check
|
||||
// whether the request succeeded.
|
||||
linkRes.LinkAddressRequest(k.Addr, localAddr, "" /* linkAddr */, linkEP)
|
||||
linkRes.LinkAddressRequest(k.Addr, localAddr, "" /* linkAddr */, nic)
|
||||
|
||||
select {
|
||||
case now := <-time.After(c.resolutionTimeout):
|
||||
|
||||
@@ -49,8 +49,8 @@ type testLinkAddressResolver struct {
|
||||
onLinkAddressRequest func()
|
||||
}
|
||||
|
||||
func (r *testLinkAddressResolver) LinkAddressRequest(addr, _ tcpip.Address, _ tcpip.LinkAddress, _ LinkEndpoint) *tcpip.Error {
|
||||
time.AfterFunc(r.delay, func() { r.fakeRequest(addr) })
|
||||
func (r *testLinkAddressResolver) LinkAddressRequest(targetAddr, _ tcpip.Address, _ tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
|
||||
time.AfterFunc(r.delay, func() { r.fakeRequest(targetAddr) })
|
||||
if f := r.onLinkAddressRequest; f != nil {
|
||||
f()
|
||||
}
|
||||
|
||||
@@ -195,10 +195,10 @@ type testNeighborResolver struct {
|
||||
|
||||
var _ LinkAddressResolver = (*testNeighborResolver)(nil)
|
||||
|
||||
func (r *testNeighborResolver) LinkAddressRequest(addr, localAddr tcpip.Address, linkAddr tcpip.LinkAddress, linkEP LinkEndpoint) *tcpip.Error {
|
||||
func (r *testNeighborResolver) LinkAddressRequest(targetAddr, _ tcpip.Address, _ tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
|
||||
// Delay handling the request to emulate network latency.
|
||||
r.clock.AfterFunc(r.delay, func() {
|
||||
r.fakeRequest(addr)
|
||||
r.fakeRequest(targetAddr)
|
||||
})
|
||||
|
||||
// Execute post address resolution action, if available.
|
||||
|
||||
@@ -236,7 +236,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, e.neigh.LocalAddr, "", e.nic.LinkEndpoint); err != nil {
|
||||
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, e.neigh.LocalAddr, "", e.nic); err != nil {
|
||||
// There is no need to log the error here; the NUD implementation may
|
||||
// assume a working link. A valid link should be the responsibility of
|
||||
// the NIC/stack.LinkEndpoint.
|
||||
@@ -277,7 +277,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, e.neigh.LocalAddr, e.neigh.LinkAddr, e.nic.LinkEndpoint); err != nil {
|
||||
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, e.neigh.LocalAddr, e.neigh.LinkAddr, e.nic); err != nil {
|
||||
e.dispatchRemoveEventLocked()
|
||||
e.setStateLocked(Failed)
|
||||
return
|
||||
|
||||
@@ -202,9 +202,9 @@ func (p entryTestProbeInfo) String() string {
|
||||
|
||||
// LinkAddressRequest sends a request for the LinkAddress of addr. Broadcasts
|
||||
// to the local network if linkAddr is the zero value.
|
||||
func (r *entryTestLinkResolver) LinkAddressRequest(addr, localAddr tcpip.Address, linkAddr tcpip.LinkAddress, linkEP LinkEndpoint) *tcpip.Error {
|
||||
func (r *entryTestLinkResolver) LinkAddressRequest(targetAddr, localAddr tcpip.Address, linkAddr tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
|
||||
p := entryTestProbeInfo{
|
||||
RemoteAddress: addr,
|
||||
RemoteAddress: targetAddr,
|
||||
RemoteLinkAddress: linkAddr,
|
||||
LocalAddress: localAddr,
|
||||
}
|
||||
|
||||
@@ -273,6 +273,15 @@ func (n *NIC) WritePacket(r *Route, gso *GSO, protocol tcpip.NetworkProtocolNumb
|
||||
return n.writePacket(r, gso, protocol, pkt)
|
||||
}
|
||||
|
||||
// WritePacketToRemote implements NetworkInterface.
|
||||
func (n *NIC) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) *tcpip.Error {
|
||||
r := Route{
|
||||
NetProto: protocol,
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
}
|
||||
return n.writePacket(&r, gso, protocol, pkt)
|
||||
}
|
||||
|
||||
func (n *NIC) writePacket(r *Route, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) *tcpip.Error {
|
||||
// WritePacket takes ownership of pkt, calculate numBytes first.
|
||||
numBytes := pkt.Size()
|
||||
|
||||
@@ -169,7 +169,7 @@ func (*testIPv6Protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
}
|
||||
|
||||
// LinkAddressRequest implements LinkAddressResolver.
|
||||
func (*testIPv6Protocol) LinkAddressRequest(_, _ tcpip.Address, _ tcpip.LinkAddress, _ LinkEndpoint) *tcpip.Error {
|
||||
func (*testIPv6Protocol) LinkAddressRequest(_, _ tcpip.Address, _ tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -490,6 +490,9 @@ type NetworkInterface interface {
|
||||
|
||||
// Enabled returns true if the interface is enabled.
|
||||
Enabled() bool
|
||||
|
||||
// WritePacketToRemote writes the packet to the given remote link address.
|
||||
WritePacketToRemote(tcpip.LinkAddress, *GSO, tcpip.NetworkProtocolNumber, *PacketBuffer) *tcpip.Error
|
||||
}
|
||||
|
||||
// NetworkEndpoint is the interface that needs to be implemented by endpoints
|
||||
@@ -764,13 +767,13 @@ type InjectableLinkEndpoint interface {
|
||||
// A LinkAddressResolver is an extension to a NetworkProtocol that
|
||||
// can resolve link addresses.
|
||||
type LinkAddressResolver interface {
|
||||
// LinkAddressRequest sends a request for the LinkAddress of addr. Broadcasts
|
||||
// the request on the local network if remoteLinkAddr is the zero value. The
|
||||
// request is sent on linkEP with localAddr as the source.
|
||||
// LinkAddressRequest sends a request for the link address of the target
|
||||
// address. The request is broadcasted on the local network if a remote link
|
||||
// address is not provided.
|
||||
//
|
||||
// A valid response will cause the discovery protocol's network
|
||||
// endpoint to call AddLinkAddress.
|
||||
LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP LinkEndpoint) *tcpip.Error
|
||||
// The request is sent from the passed network interface. If the interface
|
||||
// local address is unspecified, any interface local address may be used.
|
||||
LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, nic NetworkInterface) *tcpip.Error
|
||||
|
||||
// ResolveStaticAddress attempts to resolve address without sending
|
||||
// requests. It either resolves the name immediately or returns the
|
||||
|
||||
@@ -1323,7 +1323,7 @@ func (s *Stack) GetLinkAddress(nicID tcpip.NICID, addr, localAddr tcpip.Address,
|
||||
|
||||
fullAddr := tcpip.FullAddress{NIC: nicID, Addr: addr}
|
||||
linkRes := s.linkAddrResolvers[protocol]
|
||||
return s.linkAddrCache.get(fullAddr, linkRes, localAddr, nic.LinkEndpoint, waker)
|
||||
return s.linkAddrCache.get(fullAddr, linkRes, localAddr, nic, waker)
|
||||
}
|
||||
|
||||
// Neighbors returns all IP to MAC address associations.
|
||||
|
||||
@@ -1452,6 +1452,10 @@ func (*testInterface) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (*testInterface) WritePacketToRemote(tcpip.LinkAddress, *stack.GSO, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) *tcpip.Error {
|
||||
return tcpip.ErrNotSupported
|
||||
}
|
||||
|
||||
func TestTTL(t *testing.T) {
|
||||
for _, flow := range []testFlow{unicastV4, unicastV4in6, unicastV6, unicastV6Only, multicastV4, multicastV4in6, multicastV6, broadcast, broadcastIn6} {
|
||||
t.Run(fmt.Sprintf("flow:%s", flow), func(t *testing.T) {
|
||||
|
||||
@@ -441,9 +441,20 @@ func (FilterOutputDestination) Name() string {
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (FilterOutputDestination) ContainerAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
rules := [][]string{
|
||||
{"-A", "OUTPUT", "-d", ip.String(), "-j", "ACCEPT"},
|
||||
{"-P", "OUTPUT", "DROP"},
|
||||
var rules [][]string
|
||||
if ipv6 {
|
||||
rules = [][]string{
|
||||
{"-A", "OUTPUT", "-d", ip.String(), "-j", "ACCEPT"},
|
||||
// Allow solicited node multicast addresses so we can send neighbor
|
||||
// solicitations.
|
||||
{"-A", "OUTPUT", "-d", "ff02::1:ff00:0/104", "-j", "ACCEPT"},
|
||||
{"-P", "OUTPUT", "DROP"},
|
||||
}
|
||||
} else {
|
||||
rules = [][]string{
|
||||
{"-A", "OUTPUT", "-d", ip.String(), "-j", "ACCEPT"},
|
||||
{"-P", "OUTPUT", "DROP"},
|
||||
}
|
||||
}
|
||||
if err := filterTableRules(ipv6, rules); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user