@@ -21,7 +21,6 @@ import (
2121 "net"
2222 "net/netip"
2323 "sync/atomic"
24- "unsafe"
2524
2625 "github.com/gopacket/gopacket"
2726 "github.com/gopacket/gopacket/layers"
@@ -54,6 +53,36 @@ type internalLink struct {
5453 is4 bool
5554}
5655
56+ // getRemote returns the ip address and port of the far end of the packet's trip.
57+ //
58+ // It is used as follows:
59+ // * We set it from src address when we ingest a packet: it will be used for any SCMP response.
60+ // * We set it when the main router code has us resolve the destination (for non-responses).
61+ // * We use it as destination when finally sending the packet.
62+ //
63+ // That address and port are stored at the beginning of the packet buffer so we do not need to
64+ // allocate. getRemoteAddr returns a slice pointing directly at that storage. It is meant to
65+ // copied into the outgoing packet header.
66+ func getRemoteAddr (p * router.Packet , is4 bool ) ([]byte , uint16 ) {
67+ if is4 {
68+ bh := p .BuffHead (6 )
69+ return bh [:4 ], binary .BigEndian .Uint16 (bh [4 :6 ])
70+ }
71+ bh := p .BuffHead (18 )
72+ return bh [:16 ], binary .BigEndian .Uint16 (bh [16 :18 ])
73+ }
74+
75+ // setRemote stores the ip address and port of the far end of the packet's trip.
76+ //
77+ // That address and port are stored at the beginning of the packet buffer.
78+ func setRemoteAddr (p * router.Packet , ip []byte , port uint16 ) {
79+ // FWIW: The storage format is identical to that produced by AddrPort.marshalBinary
80+ // as long as there's no zone. Just without all the hullabaloo because we never need a netip.
81+ bh := p .BuffHead (len (ip ) + 2 )
82+ copy (bh , ip )
83+ binary .BigEndian .PutUint16 (bh [len (ip ):], port )
84+ }
85+
5786// This is called during initialization only and does not need the neighbors cache. The header
5887// is incomplete and gets patched for each packet.
5988func (l * internalLink ) packHeader () {
@@ -119,9 +148,13 @@ func (l *internalLink) packHeader() {
119148// in the destination. If the destination is not resolved, this method returns false and the
120149// packet is left with an incorrect header. Note that an address resolution is triggered if the
121150// destination is not already resolved.
122- func (l * internalLink ) addHeader (p * router.Packet , dst * netip.AddrPort ) bool {
123- dstIP := dst .Addr ()
124-
151+ func (l * internalLink ) addHeader (p * router.Packet ) bool {
152+ dstIPBytes , dstPort := getRemoteAddr (p , l .is4 )
153+ dstIP , ok := netip .AddrFromSlice (dstIPBytes )
154+ if ! ok {
155+ // This is an internal error: these bytes were stored and validated by us.
156+ panic ("Broken remote address" )
157+ }
125158 // Resolve the destination MAC address if we can.
126159 l .neighbors .Lock ()
127160 dstMac , backlog := l .neighbors .get (dstIP ) // Send ARP/NDP req as needed.
@@ -145,19 +178,19 @@ func (l *internalLink) addHeader(p *router.Packet, dst *netip.AddrPort) bool {
145178 // Inject dest.
146179 copy (p .RawPacket , dstMac [:])
147180 if l .is4 {
148- copy (p .RawPacket [ipv4DstOffset :], dst . Addr (). AsSlice () ) // Can do cheaper?
149- binary .BigEndian .PutUint16 (p .RawPacket [udpv4DstPortOffset :], dst . Port () )
181+ copy (p .RawPacket [ipv4DstOffset :], dstIPBytes ) // Can do cheaper?
182+ binary .BigEndian .PutUint16 (p .RawPacket [udpv4DstPortOffset :], dstPort )
150183 } else {
151- copy (p .RawPacket [ipv6DstOffset :], dst . Addr (). AsSlice () ) // Can do cheaper?
152- binary .BigEndian .PutUint16 (p .RawPacket [udpv6DstPortOffset :], dst . Port () )
184+ copy (p .RawPacket [ipv6DstOffset :], dstIPBytes ) // Can do cheaper?
185+ binary .BigEndian .PutUint16 (p .RawPacket [udpv6DstPortOffset :], dstPort )
153186 }
154187 return true
155188}
156189
157190// TODO(jiceatscion): can do cleaner, more legible, faster?
158- func (l * internalLink ) finishPacket (p * router.Packet , dst * netip. AddrPort ) bool {
191+ func (l * internalLink ) finishPacket (p * router.Packet ) bool {
159192 payloadLen := len (p .RawPacket )
160- if ! l .addHeader (p , dst ) {
193+ if ! l .addHeader (p ) {
161194 return false
162195 }
163196 if l .is4 {
@@ -304,12 +337,7 @@ func (l *internalLink) Resolve(p *router.Packet, dst addr.Host, port uint16) err
304337 port = l .dispatchRedirect
305338 }
306339
307- // Packets that get here must have come from an external or a sibling link; neither of which
308- // attach a RemoteAddr to the packet (besides; it could be a different type). So, RemoteAddr is
309- // not generally usable. We must allocate a new object. The precautions needed to pool them cost
310- // more than the pool saves (verified experimentally).
311- addrPort := netip .AddrPortFrom (dstAddr , port )
312- p .RemoteAddr = unsafe .Pointer (& addrPort )
340+ setRemoteAddr (p , dstAddr .AsSlice (), port )
313341 return nil
314342}
315343
@@ -332,8 +360,7 @@ func (l *internalLink) sendBacklog(dstAddr netip.Addr) {
332360 continue
333361 }
334362 // The neighbor cache doesn't know the dest port, but the full address is in the packet.
335- dst := (* netip .AddrPort )(p .RemoteAddr )
336- if ! l .finishPacket (p , dst ) {
363+ if ! l .finishPacket (p ) {
337364 // Note that this packet goes back onto the backlog so we will drop it at the end of
338365 // the loop. TODO(jiceatscion): need new drop reason.
339366 givenup = true
@@ -360,8 +387,7 @@ func (l *internalLink) Send(p *router.Packet) {
360387 // instead of just storing the destination in the packet structure. That would save us the
361388 // allocation of address but requires some more changes to the dataplane code structure.
362389
363- dst := (* netip .AddrPort )(p .RemoteAddr )
364- if ! l .finishPacket (p , dst ) {
390+ if ! l .finishPacket (p ) {
365391 // The packet got put on the backlog (or discarded if the backlog is full).
366392 return
367393 }
@@ -377,8 +403,7 @@ func (l *internalLink) Send(p *router.Packet) {
377403// Only tests actually use this method, but since we have to have it, we might as well implement it
378404// ~correctly. Doesn't hurt. TODO(jiceatscion): deal with backlog (or not).
379405func (l * internalLink ) SendBlocking (p * router.Packet ) {
380- // Likewise: p.remoteAddress -> header.
381- if l .finishPacket (p , (* netip .AddrPort )(p .RemoteAddr )) {
406+ if l .finishPacket (p ) {
382407 l .egressQ <- p
383408 }
384409 // else, backlog'd or discarded => non-blocking after all. Sorry.
@@ -388,7 +413,7 @@ func (l *internalLink) SendBlocking(p *router.Packet) {
388413// Because this link is not associated with a specific remote address, the src
389414// address of the packet is recorded in the packet structure. This may be used
390415// as the destination if SCMP responds.
391- func (l * internalLink ) receive (srcAddr * netip. AddrPort , p * router.Packet ) {
416+ func (l * internalLink ) receive (p * router.Packet ) {
392417 metrics := l .metrics
393418 sc := router .ClassOfSize (len (p .RawPacket ))
394419 metrics [sc ].InputPacketsTotal .Inc ()
@@ -403,10 +428,6 @@ func (l *internalLink) receive(srcAddr *netip.AddrPort, p *router.Packet) {
403428
404429 p .Link = l
405430
406- // This is an unconnected link. We must record the src address in case the packet is turned
407- // around by SCMP.
408- p .RemoteAddr = unsafe .Pointer (srcAddr )
409-
410431 select {
411432 case l .procQs [procID ] <- p :
412433 default :
0 commit comments