net/packet: remove {get,put}{16,32} indirection to encoding/binary.

name              old time/op    new time/op    delta
Decode/tcp4-8       28.8ns ± 2%    13.1ns ± 4%  -54.44%  (p=0.008 n=5+5)
Decode/tcp6-8       20.6ns ± 1%    12.6ns ± 2%  -38.72%  (p=0.008 n=5+5)
Decode/udp4-8       28.2ns ± 1%    12.1ns ± 4%  -57.01%  (p=0.008 n=5+5)
Decode/udp6-8       20.0ns ± 6%    12.1ns ± 2%  -39.38%  (p=0.008 n=5+5)
Decode/icmp4-8      21.7ns ± 2%    11.5ns ± 1%  -47.01%  (p=0.008 n=5+5)
Decode/icmp6-8      14.1ns ± 2%    11.8ns ± 4%  -16.60%  (p=0.008 n=5+5)
Decode/unknown-8    9.43ns ± 2%    9.30ns ± 3%     ~     (p=0.222 n=5+5)

Signed-off-by: David Anderson <danderson@tailscale.com>
pull/914/head
David Anderson 4 years ago committed by Dave Anderson
parent 55b1221db2
commit 22bf48f37c

@ -4,6 +4,8 @@
package packet package packet
import "encoding/binary"
type ICMP4Type uint8 type ICMP4Type uint8
const ( const (
@ -66,7 +68,7 @@ func (h ICMP4Header) Marshal(buf []byte) error {
h.IP4Header.Marshal(buf) h.IP4Header.Marshal(buf)
put16(buf[22:24], ipChecksum(buf)) binary.BigEndian.PutUint16(buf[22:24], ipChecksum(buf))
return nil return nil
} }

@ -5,6 +5,7 @@
package packet package packet
import ( import (
"encoding/binary"
"fmt" "fmt"
"net" "net"
@ -21,13 +22,13 @@ func NewIP4(b net.IP) IP4 {
if b4 == nil { if b4 == nil {
panic(fmt.Sprintf("To4(%v) failed", b)) panic(fmt.Sprintf("To4(%v) failed", b))
} }
return IP4(get32(b4)) return IP4(binary.BigEndian.Uint32(b4))
} }
// IPFromNetaddr converts a netaddr.IP to an IP. // IPFromNetaddr converts a netaddr.IP to an IP.
func IP4FromNetaddr(ip netaddr.IP) IP4 { func IP4FromNetaddr(ip netaddr.IP) IP4 {
ipbytes := ip.As4() ipbytes := ip.As4()
return IP4(get32(ipbytes[:])) return IP4(binary.BigEndian.Uint32(ipbytes[:]))
} }
// Netaddr converts an IP to a netaddr.IP. // Netaddr converts an IP to a netaddr.IP.
@ -71,16 +72,16 @@ func (h IP4Header) Marshal(buf []byte) error {
buf[0] = 0x40 | (ip4HeaderLength >> 2) // IPv4 buf[0] = 0x40 | (ip4HeaderLength >> 2) // IPv4
buf[1] = 0x00 // DHCP, ECN buf[1] = 0x00 // DHCP, ECN
put16(buf[2:4], uint16(len(buf))) binary.BigEndian.PutUint16(buf[2:4], uint16(len(buf)))
put16(buf[4:6], h.IPID) binary.BigEndian.PutUint16(buf[4:6], h.IPID)
put16(buf[6:8], 0) // flags, offset binary.BigEndian.PutUint16(buf[6:8], 0) // flags, offset
buf[8] = 64 // TTL buf[8] = 64 // TTL
buf[9] = uint8(h.IPProto) buf[9] = uint8(h.IPProto)
put16(buf[10:12], 0) // blank IP header checksum binary.BigEndian.PutUint16(buf[10:12], 0) // blank IP header checksum
put32(buf[12:16], uint32(h.SrcIP)) binary.BigEndian.PutUint32(buf[12:16], uint32(h.SrcIP))
put32(buf[16:20], uint32(h.DstIP)) binary.BigEndian.PutUint32(buf[16:20], uint32(h.DstIP))
put16(buf[10:12], ipChecksum(buf[0:20])) binary.BigEndian.PutUint16(buf[10:12], ipChecksum(buf[0:20]))
return nil return nil
} }
@ -97,11 +98,11 @@ func (h IP4Header) MarshalPseudo(buf []byte) error {
} }
length := len(buf) - ip4HeaderLength length := len(buf) - ip4HeaderLength
put32(buf[8:12], uint32(h.SrcIP)) binary.BigEndian.PutUint32(buf[8:12], uint32(h.SrcIP))
put32(buf[12:16], uint32(h.DstIP)) binary.BigEndian.PutUint32(buf[12:16], uint32(h.DstIP))
buf[16] = 0x0 buf[16] = 0x0
buf[17] = uint8(h.IPProto) buf[17] = uint8(h.IPProto)
put16(buf[18:20], uint16(length)) binary.BigEndian.PutUint16(buf[18:20], uint16(length))
return nil return nil
} }

@ -21,14 +21,6 @@ const (
TCPSynAck = TCPSyn | TCPAck TCPSynAck = TCPSyn | TCPAck
) )
var (
get16 = binary.BigEndian.Uint16
get32 = binary.BigEndian.Uint32
put16 = binary.BigEndian.PutUint16
put32 = binary.BigEndian.PutUint32
)
// Parsed is a minimal decoding of a packet suitable for use in filters. // Parsed is a minimal decoding of a packet suitable for use in filters.
// //
// In general, it only supports IPv4. The IPv6 parsing is very minimal. // In general, it only supports IPv4. The IPv6 parsing is very minimal.
@ -114,7 +106,7 @@ func ipChecksum(b []byte) uint16 {
i := 0 i := 0
n := len(b) n := len(b)
for n >= 2 { for n >= 2 {
ac += uint32(get16(b[i : i+2])) ac += uint32(binary.BigEndian.Uint16(b[i : i+2]))
n -= 2 n -= 2
i += 2 i += 2
} }
@ -161,7 +153,7 @@ func (q *Parsed) decode4(b []byte) {
// Check that it's IPv4. // Check that it's IPv4.
q.IPProto = IPProto(b[9]) q.IPProto = IPProto(b[9])
q.length = int(get16(b[2:4])) q.length = int(binary.BigEndian.Uint16(b[2:4]))
if len(b) < q.length { if len(b) < q.length {
// Packet was cut off before full IPv4 length. // Packet was cut off before full IPv4 length.
q.IPProto = Unknown q.IPProto = Unknown
@ -169,8 +161,8 @@ func (q *Parsed) decode4(b []byte) {
} }
// If it's valid IPv4, then the IP addresses are valid // If it's valid IPv4, then the IP addresses are valid
q.SrcIP4 = IP4(get32(b[12:16])) q.SrcIP4 = IP4(binary.BigEndian.Uint32(b[12:16]))
q.DstIP4 = IP4(get32(b[16:20])) q.DstIP4 = IP4(binary.BigEndian.Uint32(b[16:20]))
q.subofs = int((b[0] & 0x0F) << 2) q.subofs = int((b[0] & 0x0F) << 2)
sub := b[q.subofs:] sub := b[q.subofs:]
@ -187,7 +179,7 @@ func (q *Parsed) decode4(b []byte) {
// zero reason to send such a short first fragment, so we can treat // zero reason to send such a short first fragment, so we can treat
// it as Unknown. We can also treat any subsequent fragment that starts // it as Unknown. We can also treat any subsequent fragment that starts
// at such a low offset as Unknown. // at such a low offset as Unknown.
fragFlags := get16(b[6:8]) fragFlags := binary.BigEndian.Uint16(b[6:8])
moreFrags := (fragFlags & 0x20) != 0 moreFrags := (fragFlags & 0x20) != 0
fragOfs := fragFlags & 0x1FFF fragOfs := fragFlags & 0x1FFF
if fragOfs == 0 { if fragOfs == 0 {
@ -215,8 +207,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = Unknown q.IPProto = Unknown
return return
} }
q.SrcPort = get16(sub[0:2]) q.SrcPort = binary.BigEndian.Uint16(sub[0:2])
q.DstPort = get16(sub[2:4]) q.DstPort = binary.BigEndian.Uint16(sub[2:4])
q.TCPFlags = sub[13] & 0x3F q.TCPFlags = sub[13] & 0x3F
headerLength := (sub[12] & 0xF0) >> 2 headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength) q.dataofs = q.subofs + int(headerLength)
@ -226,8 +218,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = Unknown q.IPProto = Unknown
return return
} }
q.SrcPort = get16(sub[0:2]) q.SrcPort = binary.BigEndian.Uint16(sub[0:2])
q.DstPort = get16(sub[2:4]) q.DstPort = binary.BigEndian.Uint16(sub[2:4])
q.dataofs = q.subofs + udpHeaderLength q.dataofs = q.subofs + udpHeaderLength
return return
default: default:
@ -261,7 +253,7 @@ func (q *Parsed) decode6(b []byte) {
} }
q.IPProto = IPProto(b[6]) q.IPProto = IPProto(b[6])
q.length = int(get16(b[4:6])) + ip6HeaderLength q.length = int(binary.BigEndian.Uint16(b[4:6])) + ip6HeaderLength
if len(b) < q.length { if len(b) < q.length {
// Packet was cut off before the full IPv6 length. // Packet was cut off before the full IPv6 length.
q.IPProto = Unknown q.IPProto = Unknown
@ -300,8 +292,8 @@ func (q *Parsed) decode6(b []byte) {
q.IPProto = Unknown q.IPProto = Unknown
return return
} }
q.SrcPort = get16(sub[0:2]) q.SrcPort = binary.BigEndian.Uint16(sub[0:2])
q.DstPort = get16(sub[2:4]) q.DstPort = binary.BigEndian.Uint16(sub[2:4])
q.TCPFlags = sub[13] & 0x3F q.TCPFlags = sub[13] & 0x3F
headerLength := (sub[12] & 0xF0) >> 2 headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength) q.dataofs = q.subofs + int(headerLength)
@ -311,8 +303,8 @@ func (q *Parsed) decode6(b []byte) {
q.IPProto = Unknown q.IPProto = Unknown
return return
} }
q.SrcPort = get16(sub[0:2]) q.SrcPort = binary.BigEndian.Uint16(sub[0:2])
q.DstPort = get16(sub[2:4]) q.DstPort = binary.BigEndian.Uint16(sub[2:4])
q.dataofs = q.subofs + udpHeaderLength q.dataofs = q.subofs + udpHeaderLength
default: default:
q.IPProto = Unknown q.IPProto = Unknown
@ -324,7 +316,7 @@ func (q *Parsed) IP4Header() IP4Header {
if q.IPVersion != 4 { if q.IPVersion != 4 {
panic("IP4Header called on non-IPv4 Parsed") panic("IP4Header called on non-IPv4 Parsed")
} }
ipid := get16(q.b[4:6]) ipid := binary.BigEndian.Uint16(q.b[4:6])
return IP4Header{ return IP4Header{
IPID: ipid, IPID: ipid,
IPProto: q.IPProto, IPProto: q.IPProto,

@ -4,6 +4,8 @@
package packet package packet
import "encoding/binary"
// UDPHeader represents an UDP packet header. // UDPHeader represents an UDP packet header.
type UDP4Header struct { type UDP4Header struct {
IP4Header IP4Header
@ -32,15 +34,15 @@ func (h UDP4Header) Marshal(buf []byte) error {
h.IPProto = UDP h.IPProto = UDP
length := len(buf) - h.IP4Header.Len() length := len(buf) - h.IP4Header.Len()
put16(buf[20:22], h.SrcPort) binary.BigEndian.PutUint16(buf[20:22], h.SrcPort)
put16(buf[22:24], h.DstPort) binary.BigEndian.PutUint16(buf[22:24], h.DstPort)
put16(buf[24:26], uint16(length)) binary.BigEndian.PutUint16(buf[24:26], uint16(length))
put16(buf[26:28], 0) // blank checksum binary.BigEndian.PutUint16(buf[26:28], 0) // blank checksum
h.IP4Header.MarshalPseudo(buf) h.IP4Header.MarshalPseudo(buf)
// UDP checksum with IP pseudo header. // UDP checksum with IP pseudo header.
put16(buf[26:28], ipChecksum(buf[8:])) binary.BigEndian.PutUint16(buf[26:28], ipChecksum(buf[8:]))
h.IP4Header.Marshal(buf) h.IP4Header.Marshal(buf)

Loading…
Cancel
Save