From 792ebbff8e828248ef3b547f529f077447d46396 Mon Sep 17 00:00:00 2001 From: Kevin Krakauer Date: Tue, 16 May 2023 11:32:52 -0700 Subject: [PATCH] netstack: make tcpip.Address hold a []byte tcp_benchmark throughput increase 2-3%, but allocations go down (25% in the download benchmark, only 2% in the upload path). PiperOrigin-RevId: 532523146 --- pkg/sentry/socket/netstack/stack.go | 6 +- pkg/tcpip/header/checksum.go | 21 +----- pkg/tcpip/header/ipv6.go | 3 +- pkg/tcpip/header/ipv6_test.go | 3 +- pkg/tcpip/network/ipv6/ipv6.go | 7 +- pkg/tcpip/network/ipv6/ndp.go | 3 +- pkg/tcpip/network/multicast_group_test.go | 3 +- pkg/tcpip/stack/forwarding_test.go | 6 +- pkg/tcpip/stack/gro.go | 6 +- pkg/tcpip/stack/ndp_test.go | 21 ++++-- pkg/tcpip/stack/stack.go | 4 +- pkg/tcpip/stack/stack_test.go | 8 ++- pkg/tcpip/tcpip.go | 75 ++++++++++++-------- pkg/tcpip/tests/integration/loopback_test.go | 15 ++-- runsc/boot/network.go | 3 +- 15 files changed, 104 insertions(+), 80 deletions(-) diff --git a/pkg/sentry/socket/netstack/stack.go b/pkg/sentry/socket/netstack/stack.go index 170a893ca..25f25eacd 100644 --- a/pkg/sentry/socket/netstack/stack.go +++ b/pkg/sentry/socket/netstack/stack.go @@ -117,10 +117,11 @@ func (s *Stack) InterfaceAddrs() map[int32][]inet.InterfaceAddr { continue } + addrCopy := a.AddressWithPrefix.Address addrs = append(addrs, inet.InterfaceAddr{ Family: family, PrefixLen: uint8(a.AddressWithPrefix.PrefixLen), - Addr: a.AddressWithPrefix.Address.AsSlice(), + Addr: addrCopy.AsSlice(), // TODO(b/68878065): Other fields. }) } @@ -440,6 +441,7 @@ func (s *Stack) RouteTable() []inet.Route { continue } + dstAddr := rt.Destination.ID() routeTable = append(routeTable, inet.Route{ Family: family, DstLen: uint8(rt.Destination.Prefix()), // The CIDR prefix for the destination. @@ -453,7 +455,7 @@ func (s *Stack) RouteTable() []inet.Route { Scope: linux.RT_SCOPE_LINK, Type: linux.RTN_UNICAST, - DstAddr: rt.Destination.ID().AsSlice(), + DstAddr: dstAddr.AsSlice(), OutputInterface: int32(rt.NIC), GatewayAddr: rt.Gateway.AsSlice(), }) diff --git a/pkg/tcpip/header/checksum.go b/pkg/tcpip/header/checksum.go index 7c4f94913..cde74e730 100644 --- a/pkg/tcpip/header/checksum.go +++ b/pkg/tcpip/header/checksum.go @@ -76,25 +76,8 @@ func checksumUpdate2ByteAlignedAddress(xsum uint16, old, new tcpip.Address) uint panic(fmt.Sprintf("buffer has an odd number of bytes; got = %d", oldBytes)) } - // Try to avoid allocating. - var oldAddr []byte - var newAddr []byte - switch old.BitLen() { - case 32: - var oldAddr4 [4]byte - var newAddr4 [4]byte - oldAddr4 = old.As4() - newAddr4 = new.As4() - oldAddr = oldAddr4[:] - newAddr = newAddr4[:] - case 128: - var oldAddr16 [16]byte - var newAddr16 [16]byte - oldAddr16 = old.As16() - newAddr16 = new.As16() - oldAddr = oldAddr16[:] - newAddr = newAddr16[:] - } + oldAddr := old.AsSlice() + newAddr := new.AsSlice() // As per RFC 1071 page 4, // (4) Incremental Update diff --git a/pkg/tcpip/header/ipv6.go b/pkg/tcpip/header/ipv6.go index d908897c3..ed30f77b3 100644 --- a/pkg/tcpip/header/ipv6.go +++ b/pkg/tcpip/header/ipv6.go @@ -437,7 +437,8 @@ func AppendOpaqueInterfaceIdentifier(buf []byte, prefix tcpip.Subnet, nicName st // Note, we omit the optional Network_ID field. h := sha256.New() // h.Write never returns an error. - h.Write([]byte(prefix.ID().AsSlice()[:IIDOffsetInIPv6Address])) + prefixID := prefix.ID() + h.Write([]byte(prefixID.AsSlice()[:IIDOffsetInIPv6Address])) h.Write([]byte(nicName)) h.Write([]byte{dadCounter}) h.Write(secretKey) diff --git a/pkg/tcpip/header/ipv6_test.go b/pkg/tcpip/header/ipv6_test.go index a1c8a954f..e9d97208c 100644 --- a/pkg/tcpip/header/ipv6_test.go +++ b/pkg/tcpip/header/ipv6_test.go @@ -123,7 +123,8 @@ func TestAppendOpaqueInterfaceIdentifier(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { h := sha256.New() - h.Write(test.prefix.ID().AsSlice()[:header.IIDOffsetInIPv6Address]) + prefixID := test.prefix.ID() + h.Write(prefixID.AsSlice()[:header.IIDOffsetInIPv6Address]) h.Write([]byte(test.nicName)) h.Write([]byte{test.dadCounter}) if k := test.secretKey; k != nil { diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index 648ce5ec8..3573e7ccc 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -2806,11 +2806,12 @@ func hashRoute(r *stack.Route, hashIV uint32) uint32 { // The FNV-1a was chosen because it is a fast hashing algorithm, and // cryptographic properties are not needed here. h := fnv.New32a() - if _, err := h.Write(r.LocalAddress().AsSlice()); err != nil { + localAddr := r.LocalAddress() + if _, err := h.Write(localAddr.AsSlice()); err != nil { panic(fmt.Sprintf("Hash.Write: %s, but Hash' implementation of Write is not expected to ever return an error", err)) } - - if _, err := h.Write(r.RemoteAddress().AsSlice()); err != nil { + remoteAddr := r.RemoteAddress() + if _, err := h.Write(remoteAddr.AsSlice()); err != nil { panic(fmt.Sprintf("Hash.Write: %s, but Hash' implementation of Write is not expected to ever return an error", err)) } diff --git a/pkg/tcpip/network/ipv6/ndp.go b/pkg/tcpip/network/ipv6/ndp.go index 2d1b2079b..b78482019 100644 --- a/pkg/tcpip/network/ipv6/ndp.go +++ b/pkg/tcpip/network/ipv6/ndp.go @@ -1182,7 +1182,8 @@ func (ndp *ndpState) generateSLAACAddr(prefix tcpip.Subnet, state *slaacPrefixSt } var generatedAddr tcpip.AddressWithPrefix - addrBytes := []byte(prefix.ID().AsSlice()) + prefixID := prefix.ID() + addrBytes := prefixID.AsSlice() for i := 0; ; i++ { // If we were unable to generate an address after the maximum SLAAC address diff --git a/pkg/tcpip/network/multicast_group_test.go b/pkg/tcpip/network/multicast_group_test.go index 28686b68b..d91ab16a9 100644 --- a/pkg/tcpip/network/multicast_group_test.go +++ b/pkg/tcpip/network/multicast_group_test.go @@ -969,7 +969,8 @@ func TestMGPQueryMessages(t *testing.T) { { name: "Specified other address", multicastAddr: func() tcpip.Address { - addrBytes := test.multicastAddr.AsSlice() + addrCopy := test.multicastAddr + addrBytes := addrCopy.AsSlice() addrBytes[len(addrBytes)-1]++ return tcpip.AddrFromSlice(addrBytes) }(), diff --git a/pkg/tcpip/stack/forwarding_test.go b/pkg/tcpip/stack/forwarding_test.go index 41415c254..5df69a8ff 100644 --- a/pkg/tcpip/stack/forwarding_test.go +++ b/pkg/tcpip/stack/forwarding_test.go @@ -122,8 +122,10 @@ func (f *fwdTestNetworkEndpoint) WritePacket(r *Route, params NetworkHeaderParam // Add the protocol's header to the packet and send it to the link // endpoint. b := pkt.NetworkHeader().Push(fwdTestNetHeaderLen) - copy(b[dstAddrOffset:], r.RemoteAddress().AsSlice()) - copy(b[srcAddrOffset:], r.LocalAddress().AsSlice()) + remote := r.RemoteAddress() + local := r.LocalAddress() + copy(b[dstAddrOffset:], remote.AsSlice()) + copy(b[srcAddrOffset:], local.AsSlice()) b[protocolNumberOffset] = byte(params.Protocol) pkt.NetworkProtocolNumber = fwdTestNetNumber diff --git a/pkg/tcpip/stack/gro.go b/pkg/tcpip/stack/gro.go index 0be504af2..1167c3680 100644 --- a/pkg/tcpip/stack/gro.go +++ b/pkg/tcpip/stack/gro.go @@ -607,10 +607,12 @@ func (gd *groDispatcher) bucketForPacket(ipHdr header.Network, tcpHdr header.TCP // TODO(b/256037250): Use jenkins or checksum. Write a test to print // distribution. var sum int - for _, val := range ipHdr.SourceAddress().AsSlice() { + srcAddr := ipHdr.SourceAddress() + for _, val := range srcAddr.AsSlice() { sum += int(val) } - for _, val := range ipHdr.DestinationAddress().AsSlice() { + dstAddr := ipHdr.DestinationAddress() + for _, val := range dstAddr.AsSlice() { sum += int(val) } sum += int(tcpHdr.SourcePort()) diff --git a/pkg/tcpip/stack/ndp_test.go b/pkg/tcpip/stack/ndp_test.go index 2a40ac987..4b346189b 100644 --- a/pkg/tcpip/stack/ndp_test.go +++ b/pkg/tcpip/stack/ndp_test.go @@ -73,7 +73,8 @@ func addrForSubnet(subnet tcpip.Subnet, linkAddr tcpip.LinkAddress) tcpip.Addres return tcpip.AddressWithPrefix{} } - addrBytes := subnet.ID().AsSlice() + subnetID := subnet.ID() + addrBytes := subnetID.AsSlice() header.EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, addrBytes[header.IIDOffsetInIPv6Address:]) return tcpip.AddressWithPrefix{ Address: tcpip.AddrFromSlice(addrBytes), @@ -3214,7 +3215,8 @@ func TestMixedSLAACAddrConflictRegen(t *testing.T) { var stableAddrsWithOpaqueIID [maxAddrs]tcpip.AddressWithPrefix var tempAddrsWithOpaqueIID [maxAddrs]tcpip.AddressWithPrefix var tempAddrsWithModifiedEUI64 [maxAddrs]tcpip.AddressWithPrefix - addrBytes := subnet.ID().AsSlice() + subnetID := subnet.ID() + addrBytes := subnetID.AsSlice() for i := 0; i < maxAddrs; i++ { stableAddrsWithOpaqueIID[i] = tcpip.AddressWithPrefix{ Address: tcpip.AddrFromSlice(header.AppendOpaqueInterfaceIdentifier(addrBytes[:header.IIDOffsetInIPv6Address], subnet, nicName, uint8(i), nil)), @@ -4302,12 +4304,14 @@ func TestAutoGenAddrWithOpaqueIID(t *testing.T) { // addr1 and addr2 are the addresses that are expected to be generated when // stack.Stack is configured to generate opaque interface identifiers as // defined by RFC 7217. - addrBytes := subnet1.ID().AsSlice() + subnetID := subnet1.ID() + addrBytes := subnetID.AsSlice() addr1 := tcpip.AddressWithPrefix{ Address: tcpip.AddrFromSlice(header.AppendOpaqueInterfaceIdentifier(addrBytes[:header.IIDOffsetInIPv6Address], subnet1, nicName, 0, secretKey)), PrefixLen: 64, } - addrBytes = subnet2.ID().AsSlice() + subnetID = subnet2.ID() + addrBytes = subnetID.AsSlice() addr2 := tcpip.AddressWithPrefix{ Address: tcpip.AddrFromSlice(header.AppendOpaqueInterfaceIdentifier(addrBytes[:header.IIDOffsetInIPv6Address], subnet2, nicName, 0, secretKey)), PrefixLen: 64, @@ -4394,7 +4398,8 @@ func TestAutoGenAddrInResponseToDADConflicts(t *testing.T) { prefix, subnet, _ := prefixSubnetAddr(0, linkAddr1) addrForSubnet := func(subnet tcpip.Subnet, dadCounter uint8) tcpip.AddressWithPrefix { - addrBytes := subnet.ID().AsSlice() + subnetID := subnet.ID() + addrBytes := subnetID.AsSlice() return tcpip.AddressWithPrefix{ Address: tcpip.AddrFromSlice(header.AppendOpaqueInterfaceIdentifier(addrBytes[:header.IIDOffsetInIPv6Address], subnet, nicName, dadCounter, secretKey)), PrefixLen: 64, @@ -4676,7 +4681,8 @@ func TestAutoGenAddrWithEUI64IIDNoDADRetries(t *testing.T) { addrType.triggerSLAACFn(e) - addrBytes := addrType.subnet.ID().AsSlice() + subnetID := addrType.subnet.ID() + addrBytes := subnetID.AsSlice() header.EthernetAdddressToModifiedEUI64IntoBuf(linkAddr1, addrBytes[header.IIDOffsetInIPv6Address:]) addr := tcpip.AddressWithPrefix{ Address: tcpip.AddrFromSlice(addrBytes), @@ -4762,7 +4768,8 @@ func TestAutoGenAddrContinuesLifetimesAfterRetry(t *testing.T) { received := clock.NowMonotonic() e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, true, lifetimeSeconds, lifetimeSeconds)) - addrBytes := subnet.ID().AsSlice() + subnetID := subnet.ID() + addrBytes := subnetID.AsSlice() addr := tcpip.AddressWithPrefix{ Address: tcpip.AddrFromSlice(header.AppendOpaqueInterfaceIdentifier(addrBytes[:header.IIDOffsetInIPv6Address], subnet, nicName, 0, secretKey)), PrefixLen: 64, diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 23e53fb4d..f569a948f 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -1381,7 +1381,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n // requirement to do this from any RFC but simply a choice made to better // follow a strong host model which the netstack follows at the time of // writing. - if onlyGlobalAddresses && chosenRoute == (tcpip.Route{}) && isNICForwarding(nic, netProto) { + if onlyGlobalAddresses && chosenRoute.Equal(tcpip.Route{}) && isNICForwarding(nic, netProto) { chosenRoute = route } } @@ -1391,7 +1391,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n return r, nil } - if chosenRoute != (tcpip.Route{}) { + if !chosenRoute.Equal(tcpip.Route{}) { // At this point we know the stack has forwarding enabled since chosenRoute is // only set when forwarding is enabled. nic, ok := s.nics[chosenRoute.NIC] diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go index d14052e7b..9b8a71d67 100644 --- a/pkg/tcpip/stack/stack_test.go +++ b/pkg/tcpip/stack/stack_test.go @@ -180,14 +180,16 @@ func (f *fakeNetworkEndpoint) NetworkProtocolNumber() tcpip.NetworkProtocolNumbe func (f *fakeNetworkEndpoint) WritePacket(r *stack.Route, params stack.NetworkHeaderParams, pkt stack.PacketBufferPtr) tcpip.Error { // Increment the sent packet count in the protocol descriptor. - f.proto.sendPacketCount[int(r.RemoteAddress().AsSlice()[0])%len(f.proto.sendPacketCount)]++ + remote := r.RemoteAddress() + f.proto.sendPacketCount[int(remote.AsSlice()[0])%len(f.proto.sendPacketCount)]++ // Add the protocol's header to the packet and send it to the link // endpoint. hdr := pkt.NetworkHeader().Push(fakeNetHeaderLen) pkt.NetworkProtocolNumber = fakeNetNumber - copy(hdr[dstAddrOffset:], r.RemoteAddress().AsSlice()) - copy(hdr[srcAddrOffset:], r.LocalAddress().AsSlice()) + copy(hdr[dstAddrOffset:], remote.AsSlice()) + local := r.LocalAddress() + copy(hdr[srcAddrOffset:], local.AsSlice()) hdr[protocolNumberOffset] = byte(params.Protocol) if r.Loop()&stack.PacketLoop != 0 { diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go index 2932ab43e..09be47c0e 100644 --- a/pkg/tcpip/tcpip.go +++ b/pkg/tcpip/tcpip.go @@ -154,12 +154,18 @@ type Timer interface { // // +stateify savable type Address struct { - addr string + addr [16]byte + length int } // AddrFrom4 converts addr to an Address. func AddrFrom4(addr [4]byte) Address { - return Address{addr: string(addr[:])} + ret := Address{ + length: 4, + } + // It's guaranteed that copy will return 4. + copy(ret.addr[:4], addr[:]) + return ret } // AddrFrom4Slice converts addr to an Address. It panics if len(addr) != 4. @@ -167,12 +173,18 @@ func AddrFrom4Slice(addr []byte) Address { if len(addr) != 4 { panic(fmt.Sprintf("bad address length for address %v", addr)) } + // TODO(281863522): This is probalby an extra copy, just do the init here. return AddrFrom4([4]byte(addr)) } // AddrFrom16 converts addr to an Address. func AddrFrom16(addr [16]byte) Address { - return Address{addr: string(addr[:])} + ret := Address{ + length: 16, + } + // It's guaranteed that copy will return 16. + copy(ret.addr[:16], addr[:]) + return ret } // AddrFrom16Slice converts addr to an Address. It panics if len(addr) != 16. @@ -180,6 +192,7 @@ func AddrFrom16Slice(addr []byte) Address { if len(addr) != 16 { panic(fmt.Sprintf("bad address length for address %v", addr)) } + // TODO(281863522): This is probalby an extra copy, just do the init here. return AddrFrom16([16]byte(addr)) } @@ -200,7 +213,7 @@ func (a Address) As4() [4]byte { if a.Len() != 4 { panic(fmt.Sprintf("bad address length for address %v", a.addr)) } - return ([4]byte)([]byte(a.addr)) + return [4]byte(a.addr[:4]) } // As16 returns a as a 16 byte array. It panics if the address length is not 16. @@ -208,13 +221,15 @@ func (a Address) As16() [16]byte { if a.Len() != 16 { panic(fmt.Sprintf("bad address length for address %v", a.addr)) } - return ([16]byte)([]byte(a.addr)) + return [16]byte(a.addr[:16]) } -// AsSlice returns a as a byte slice. It may return a new slice or a window -// into existing memory. -func (a Address) AsSlice() []byte { - return []byte(a.addr) +// AsSlice returns a as a byte slice. Callers should be careful as it can +// return a window into existing memory. +// +// +checkescape +func (a *Address) AsSlice() []byte { + return a.addr[:a.length] } // BitLen returns the length in bits of a. @@ -224,7 +239,7 @@ func (a Address) BitLen() int { // Len returns the length in bytes of a. func (a Address) Len() int { - return len(a.addr) + return a.length } // WithPrefix returns the address with a prefix that represents a point subnet. @@ -262,7 +277,7 @@ func (a Address) MatchingPrefix(b Address) uint8 { } var prefix uint8 - for i := range a.addr { + for i := 0; i < a.length; i++ { aByte := a.addr[i] bByte := b.addr[i] @@ -308,7 +323,7 @@ func MaskFromBytes(bs []byte) AddressMask { // String implements Stringer. func (m AddressMask) String() string { - return fmt.Sprintf("%x", []byte(m.mask)) + return fmt.Sprintf("%x", m.mask) } // BitLen returns the length of the mask in bits. @@ -392,11 +407,11 @@ func (s *Subnet) Mask() AddressMask { // Broadcast returns the subnet's broadcast address. func (s *Subnet) Broadcast() Address { - addr := []byte(s.address.addr) - for i := range addr { - addr[i] |= ^s.mask.mask[i] + addrCopy := s.address + for i := 0; i < addrCopy.Len(); i++ { + addrCopy.addr[i] |= ^s.mask.mask[i] } - return Address{addr: string(addr)} + return addrCopy } // IsBroadcast returns true if the address is considered a broadcast address. @@ -1462,7 +1477,7 @@ type Route struct { func (r Route) String() string { var out strings.Builder _, _ = fmt.Fprintf(&out, "%s", r.Destination) - if len(r.Gateway.addr) > 0 { + if r.Gateway.length > 0 { _, _ = fmt.Fprintf(&out, " via %s", r.Gateway) } _, _ = fmt.Fprintf(&out, " nic %d", r.NIC) @@ -1472,7 +1487,7 @@ func (r Route) String() string { // Equal returns true if the given Route is equal to this Route. func (r Route) Equal(to Route) bool { // NOTE: This relies on the fact that r.Destination == to.Destination - return r == to + return r.Destination.Equal(to.Destination) && r.Gateway == to.Gateway && r.NIC == to.NIC } // TransportProtocolNumber is the number of a transport protocol. @@ -2520,7 +2535,7 @@ func (a Address) String() string { } return b.String() default: - return fmt.Sprintf("%x", []byte(a.addr)) + return fmt.Sprintf("%x", a.addr[:]) } } @@ -2535,18 +2550,18 @@ func (a Address) To4() Address { return a } if a.Len() == ipv6len && - isZeros(Address{addr: a.addr[0:10]}) && + isZeros(a.addr[:10]) && a.addr[10] == 0xff && a.addr[11] == 0xff { - return Address{addr: a.addr[12:16]} + return AddrFrom4Slice(a.addr[12:16]) } return Address{} } -// isZeros reports whether a is all zeros. -func isZeros(a Address) bool { - for i := 0; i < a.Len(); i++ { - if a.addr[i] != 0 { +// isZeros reports whether addr is all zeros. +func isZeros(addr []byte) bool { + for _, b := range addr { + if b != 0 { return false } } @@ -2606,17 +2621,17 @@ func (a AddressWithPrefix) String() string { // Subnet converts the address and prefix into a Subnet value and returns it. func (a AddressWithPrefix) Subnet() Subnet { - addrLen := len(a.Address.addr) + addrLen := a.Address.length if a.PrefixLen <= 0 { return Subnet{ - address: Address{addr: strings.Repeat("\x00", addrLen)}, - mask: AddressMask{mask: strings.Repeat("\x00", addrLen)}, + address: AddrFromSlice(bytes.Repeat([]byte{0}, addrLen)), + mask: MaskFromBytes(bytes.Repeat([]byte{0}, addrLen)), } } if a.PrefixLen >= addrLen*8 { return Subnet{ address: a.Address, - mask: AddressMask{mask: strings.Repeat("\xff", addrLen)}, + mask: MaskFromBytes(bytes.Repeat([]byte{0xff}, addrLen)), } } @@ -2638,7 +2653,7 @@ func (a AddressWithPrefix) Subnet() Subnet { // For extra caution, call NewSubnet rather than directly creating the Subnet // value. If that fails it indicates a serious bug in this code, so panic is // in order. - s, err := NewSubnet(Address{addr: string(sa)}, AddressMask{mask: string(sm)}) + s, err := NewSubnet(AddrFromSlice(sa), MaskFromBytes(sm)) if err != nil { panic("invalid subnet: " + err.Error()) } diff --git a/pkg/tcpip/tests/integration/loopback_test.go b/pkg/tcpip/tests/integration/loopback_test.go index df0e16e24..2f600b815 100644 --- a/pkg/tcpip/tests/integration/loopback_test.go +++ b/pkg/tcpip/tests/integration/loopback_test.go @@ -114,7 +114,8 @@ func TestLoopbackAcceptAllInSubnetUDP(t *testing.T) { Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: utils.Ipv4Addr, } - ipv4Bytes := ipv4ProtocolAddress.AddressWithPrefix.Address.AsSlice() + addrCopy := ipv4ProtocolAddress.AddressWithPrefix.Address + ipv4Bytes := addrCopy.AsSlice() ipv4Bytes[len(ipv4Bytes)-1]++ otherIPv4Address := tcpip.AddrFromSlice(ipv4Bytes) @@ -122,7 +123,8 @@ func TestLoopbackAcceptAllInSubnetUDP(t *testing.T) { Protocol: header.IPv6ProtocolNumber, AddressWithPrefix: utils.Ipv6Addr, } - ipv6Bytes := utils.Ipv6Addr.Address.AsSlice() + addrCopy = utils.Ipv6Addr.Address + ipv6Bytes := addrCopy.AsSlice() ipv6Bytes[len(ipv6Bytes)-1]++ otherIPv6Address := tcpip.AddrFromSlice(ipv6Bytes) @@ -283,7 +285,8 @@ func TestLoopbackSubnetLifetimeBoundToAddr(t *testing.T) { Protocol: ipv4.ProtocolNumber, AddressWithPrefix: utils.Ipv4Addr, } - addrBytes := utils.Ipv4Addr.Address.AsSlice() + addrCopy := utils.Ipv4Addr.Address + addrBytes := addrCopy.AsSlice() addrBytes[len(addrBytes)-1]++ otherAddr := tcpip.AddrFromSlice(addrBytes) @@ -352,7 +355,8 @@ func TestLoopbackAcceptAllInSubnetTCP(t *testing.T) { AddressWithPrefix: utils.Ipv4Addr, } ipv4ProtocolAddress.AddressWithPrefix.PrefixLen = 8 - ipv4Bytes := ipv4ProtocolAddress.AddressWithPrefix.Address.AsSlice() + addrCopy := ipv4ProtocolAddress.AddressWithPrefix.Address + ipv4Bytes := addrCopy.AsSlice() ipv4Bytes[len(ipv4Bytes)-1]++ otherIPv4Address := tcpip.AddrFromSlice(ipv4Bytes) @@ -360,7 +364,8 @@ func TestLoopbackAcceptAllInSubnetTCP(t *testing.T) { Protocol: header.IPv6ProtocolNumber, AddressWithPrefix: utils.Ipv6Addr, } - ipv6Bytes := utils.Ipv6Addr.Address.AsSlice() + addrCopy = utils.Ipv6Addr.Address + ipv6Bytes := addrCopy.AsSlice() ipv6Bytes[len(ipv6Bytes)-1]++ otherIPv6Address := tcpip.AddrFromSlice(ipv6Bytes) diff --git a/runsc/boot/network.go b/runsc/boot/network.go index 8844686ff..74c83f8f2 100644 --- a/runsc/boot/network.go +++ b/runsc/boot/network.go @@ -482,5 +482,6 @@ func ipToAddress(ip net.IP) tcpip.Address { // ipMaskToAddressMask converts IPMask to tcpip.AddressMask, ignoring the // protocol. func ipMaskToAddressMask(ipMask net.IPMask) tcpip.AddressMask { - return tcpip.MaskFromBytes(ipToAddress(net.IP(ipMask)).AsSlice()) + addr := ipToAddress(net.IP(ipMask)) + return tcpip.MaskFromBytes(addr.AsSlice()) }