summaryrefslogtreecommitdiffhomepage
path: root/test/packetimpact/testbench
diff options
context:
space:
mode:
authorgVisor bot <gvisor-bot@google.com>2020-04-28 18:49:19 -0700
committergVisor bot <gvisor-bot@google.com>2020-04-28 18:50:44 -0700
commit24abccbc1c3b7b0dd06b6da97e5b4c90c8c13907 (patch)
tree95911e3341b7296f7d80f5c0ee82e466e88184e2 /test/packetimpact/testbench
parentf93f2fda74f31246e8866783f6c4be2318bdedd6 (diff)
Internal change.
PiperOrigin-RevId: 308940886
Diffstat (limited to 'test/packetimpact/testbench')
-rw-r--r--test/packetimpact/testbench/connections.go120
-rw-r--r--test/packetimpact/testbench/dut.go153
-rw-r--r--test/packetimpact/testbench/layers.go104
3 files changed, 325 insertions, 52 deletions
diff --git a/test/packetimpact/testbench/connections.go b/test/packetimpact/testbench/connections.go
index 2280bd4ee..56ac3fa54 100644
--- a/test/packetimpact/testbench/connections.go
+++ b/test/packetimpact/testbench/connections.go
@@ -39,20 +39,28 @@ var remoteIPv6 = flag.String("remote_ipv6", "", "remote IPv6 address for test pa
var localMAC = flag.String("local_mac", "", "local mac address for test packets")
var remoteMAC = flag.String("remote_mac", "", "remote mac address for test packets")
-// pickPort makes a new socket and returns the socket FD and port. The domain
-// should be AF_INET or AF_INET6. The caller must close the FD when done with
+func portFromSockaddr(sa unix.Sockaddr) (uint16, error) {
+ switch sa := sa.(type) {
+ case *unix.SockaddrInet4:
+ return uint16(sa.Port), nil
+ case *unix.SockaddrInet6:
+ return uint16(sa.Port), nil
+ }
+ return 0, fmt.Errorf("sockaddr type %T does not contain port", sa)
+}
+
+// pickPort makes a new socket and returns the socket FD and port. The domain should be AF_INET or AF_INET6. The caller must close the FD when done with
// the port if there is no error.
-func pickPort(domain, typ int) (fd int, port uint16, err error) {
+func pickPort(domain, typ int) (fd int, sa unix.Sockaddr, err error) {
fd, err = unix.Socket(domain, typ, 0)
if err != nil {
- return -1, 0, err
+ return -1, nil, err
}
defer func() {
if err != nil {
err = multierr.Append(err, unix.Close(fd))
}
}()
- var sa unix.Sockaddr
switch domain {
case unix.AF_INET:
var sa4 unix.SockaddrInet4
@@ -63,31 +71,16 @@ func pickPort(domain, typ int) (fd int, port uint16, err error) {
copy(sa6.Addr[:], net.ParseIP(*localIPv6).To16())
sa = &sa6
default:
- return -1, 0, fmt.Errorf("invalid domain %d, it should be one of unix.AF_INET or unix.AF_INET6", domain)
+ return -1, nil, fmt.Errorf("invalid domain %d, it should be one of unix.AF_INET or unix.AF_INET6", domain)
}
if err = unix.Bind(fd, sa); err != nil {
- return -1, 0, err
+ return -1, nil, err
}
- newSockAddr, err := unix.Getsockname(fd)
+ sa, err = unix.Getsockname(fd)
if err != nil {
- return -1, 0, err
- }
- switch domain {
- case unix.AF_INET:
- newSockAddrInet4, ok := newSockAddr.(*unix.SockaddrInet4)
- if !ok {
- return -1, 0, fmt.Errorf("can't cast Getsockname result %T to SockaddrInet4", newSockAddr)
- }
- return fd, uint16(newSockAddrInet4.Port), nil
- case unix.AF_INET6:
- newSockAddrInet6, ok := newSockAddr.(*unix.SockaddrInet6)
- if !ok {
- return -1, 0, fmt.Errorf("can't cast Getsockname result %T to SockaddrInet6", newSockAddr)
- }
- return fd, uint16(newSockAddrInet6.Port), nil
- default:
- return -1, 0, fmt.Errorf("invalid domain %d, it should be one of unix.AF_INET or unix.AF_INET6", domain)
+ return -1, nil, err
}
+ return fd, sa, nil
}
// layerState stores the state of a layer of a connection.
@@ -282,7 +275,11 @@ func SeqNumValue(v seqnum.Value) *seqnum.Value {
// newTCPState creates a new TCPState.
func newTCPState(domain int, out, in TCP) (*tcpState, error) {
- portPickerFD, localPort, err := pickPort(domain, unix.SOCK_STREAM)
+ portPickerFD, localAddr, err := pickPort(domain, unix.SOCK_STREAM)
+ if err != nil {
+ return nil, err
+ }
+ localPort, err := portFromSockaddr(localAddr)
if err != nil {
return nil, err
}
@@ -385,10 +382,14 @@ type udpState struct {
var _ layerState = (*udpState)(nil)
// newUDPState creates a new udpState.
-func newUDPState(domain int, out, in UDP) (*udpState, error) {
- portPickerFD, localPort, err := pickPort(domain, unix.SOCK_DGRAM)
+func newUDPState(domain int, out, in UDP) (*udpState, unix.Sockaddr, error) {
+ portPickerFD, localAddr, err := pickPort(domain, unix.SOCK_DGRAM)
if err != nil {
- return nil, err
+ return nil, nil, err
+ }
+ localPort, err := portFromSockaddr(localAddr)
+ if err != nil {
+ return nil, nil, err
}
s := udpState{
out: UDP{SrcPort: &localPort},
@@ -396,12 +397,12 @@ func newUDPState(domain int, out, in UDP) (*udpState, error) {
portPickerFD: portPickerFD,
}
if err := s.out.merge(&out); err != nil {
- return nil, err
+ return nil, nil, err
}
if err := s.in.merge(&in); err != nil {
- return nil, err
+ return nil, nil, err
}
- return &s, nil
+ return &s, localAddr, nil
}
func (s *udpState) outgoing() Layer {
@@ -436,6 +437,7 @@ type Connection struct {
layerStates []layerState
injector Injector
sniffer Sniffer
+ localAddr unix.Sockaddr
t *testing.T
}
@@ -499,7 +501,7 @@ func (conn *Connection) CreateFrame(layer Layer, additionalLayers ...Layer) Laye
func (conn *Connection) SendFrame(frame Layers) {
outBytes, err := frame.ToBytes()
if err != nil {
- conn.t.Fatalf("can't build outgoing TCP packet: %s", err)
+ conn.t.Fatalf("can't build outgoing packet: %s", err)
}
conn.injector.Send(outBytes)
@@ -545,8 +547,9 @@ func (e *layersError) Error() string {
return e.got.diff(e.want)
}
-// Expect a frame with the final layerStates layer matching the provided Layer
-// within the timeout specified. If it doesn't arrive in time, it returns nil.
+// Expect expects a frame with the final layerStates layer matching the
+// provided Layer within the timeout specified. If it doesn't arrive in time,
+// an error is returned.
func (conn *Connection) Expect(layer Layer, timeout time.Duration) (Layer, error) {
// Make a frame that will ignore all but the final layer.
layers := make([]Layer, len(conn.layerStates))
@@ -671,8 +674,8 @@ func (conn *TCPIPv4) Close() {
(*Connection)(conn).Close()
}
-// Expect a frame with the TCP layer matching the provided TCP within the
-// timeout specified. If it doesn't arrive in time, it returns nil.
+// Expect expects a frame with the TCP layer matching the provided TCP within
+// the timeout specified. If it doesn't arrive in time, an error is returned.
func (conn *TCPIPv4) Expect(tcp TCP, timeout time.Duration) (*TCP, error) {
layer, err := (*Connection)(conn).Expect(&tcp, timeout)
if layer == nil {
@@ -756,7 +759,7 @@ func (conn *IPv6Conn) Close() {
}
// ExpectFrame expects a frame that matches the provided Layers within the
-// timeout specified. If it doesn't arrive in time, it returns nil.
+// timeout specified. If it doesn't arrive in time, an error is returned.
func (conn *IPv6Conn) ExpectFrame(frame Layers, timeout time.Duration) (Layers, error) {
return (*Connection)(conn).ExpectFrame(frame, timeout)
}
@@ -780,7 +783,7 @@ func NewUDPIPv4(t *testing.T, outgoingUDP, incomingUDP UDP) UDPIPv4 {
if err != nil {
t.Fatalf("can't make ipv4State: %s", err)
}
- tcpState, err := newUDPState(unix.AF_INET, outgoingUDP, incomingUDP)
+ udpState, localAddr, err := newUDPState(unix.AF_INET, outgoingUDP, incomingUDP)
if err != nil {
t.Fatalf("can't make udpState: %s", err)
}
@@ -794,24 +797,61 @@ func NewUDPIPv4(t *testing.T, outgoingUDP, incomingUDP UDP) UDPIPv4 {
}
return UDPIPv4{
- layerStates: []layerState{etherState, ipv4State, tcpState},
+ layerStates: []layerState{etherState, ipv4State, udpState},
injector: injector,
sniffer: sniffer,
+ localAddr: localAddr,
t: t,
}
}
+// LocalAddr gets the local socket address of this connection.
+func (conn *UDPIPv4) LocalAddr() unix.Sockaddr {
+ return conn.localAddr
+}
+
// CreateFrame builds a frame for the connection with layer overriding defaults
// of the innermost layer and additionalLayers added after it.
func (conn *UDPIPv4) CreateFrame(layer Layer, additionalLayers ...Layer) Layers {
return (*Connection)(conn).CreateFrame(layer, additionalLayers...)
}
+// Send a packet with reasonable defaults. Potentially override the UDP layer in
+// the connection with the provided layer and add additionLayers.
+func (conn *UDPIPv4) Send(udp UDP, additionalLayers ...Layer) {
+ (*Connection)(conn).Send(&udp, additionalLayers...)
+}
+
// SendFrame sends a frame on the wire and updates the state of all layers.
func (conn *UDPIPv4) SendFrame(frame Layers) {
(*Connection)(conn).SendFrame(frame)
}
+// SendIP sends a packet with additionalLayers following the IP layer in the
+// connection.
+func (conn *UDPIPv4) SendIP(additionalLayers ...Layer) {
+ var layersToSend Layers
+ for _, s := range conn.layerStates[:len(conn.layerStates)-1] {
+ layersToSend = append(layersToSend, s.outgoing())
+ }
+ layersToSend = append(layersToSend, additionalLayers...)
+ conn.SendFrame(layersToSend)
+}
+
+// Expect expects a frame with the UDP layer matching the provided UDP within
+// the timeout specified. If it doesn't arrive in time, an error is returned.
+func (conn *UDPIPv4) Expect(udp UDP, timeout time.Duration) (*UDP, error) {
+ layer, err := (*Connection)(conn).Expect(&udp, timeout)
+ if layer == nil {
+ return nil, err
+ }
+ gotUDP, ok := layer.(*UDP)
+ if !ok {
+ conn.t.Fatalf("expected %s to be UDP", layer)
+ }
+ return gotUDP, err
+}
+
// Close frees associated resources held by the UDPIPv4 connection.
func (conn *UDPIPv4) Close() {
(*Connection)(conn).Close()
diff --git a/test/packetimpact/testbench/dut.go b/test/packetimpact/testbench/dut.go
index 3f340c6bc..87eeeeb88 100644
--- a/test/packetimpact/testbench/dut.go
+++ b/test/packetimpact/testbench/dut.go
@@ -237,6 +237,33 @@ func (dut *DUT) CloseWithErrno(ctx context.Context, fd int32) (int32, error) {
return resp.GetRet(), syscall.Errno(resp.GetErrno_())
}
+// Connect calls connect on the DUT and causes a fatal test failure if it
+// doesn't succeed. If more control over the timeout or error handling is
+// needed, use ConnectWithErrno.
+func (dut *DUT) Connect(fd int32, sa unix.Sockaddr) {
+ dut.t.Helper()
+ ctx, cancel := context.WithTimeout(context.Background(), *rpcTimeout)
+ defer cancel()
+ ret, err := dut.ConnectWithErrno(ctx, fd, sa)
+ if ret != 0 {
+ dut.t.Fatalf("failed to connect socket: %s", err)
+ }
+}
+
+// ConnectWithErrno calls bind on the DUT.
+func (dut *DUT) ConnectWithErrno(ctx context.Context, fd int32, sa unix.Sockaddr) (int32, error) {
+ dut.t.Helper()
+ req := pb.ConnectRequest{
+ Sockfd: fd,
+ Addr: dut.sockaddrToProto(sa),
+ }
+ resp, err := dut.posixServer.Connect(ctx, &req)
+ if err != nil {
+ dut.t.Fatalf("failed to call Connect: %s", err)
+ }
+ return resp.GetRet(), syscall.Errno(resp.GetErrno_())
+}
+
// GetSockName calls getsockname on the DUT and causes a fatal test failure if
// it doesn't succeed. If more control over the timeout or error handling is
// needed, use GetSockNameWithErrno.
@@ -264,6 +291,102 @@ func (dut *DUT) GetSockNameWithErrno(ctx context.Context, sockfd int32) (int32,
return resp.GetRet(), dut.protoToSockaddr(resp.GetAddr()), syscall.Errno(resp.GetErrno_())
}
+// GetSockOpt calls getsockopt on the DUT and causes a fatal test failure if it
+// doesn't succeed. If more control over the timeout or error handling is
+// needed, use GetSockOptWithErrno. Because endianess and the width of values
+// might differ between the testbench and DUT architectures, prefer to use a
+// more specific GetSockOptXxx function.
+func (dut *DUT) GetSockOpt(sockfd, level, optname, optlen int32) []byte {
+ dut.t.Helper()
+ ctx, cancel := context.WithTimeout(context.Background(), *rpcTimeout)
+ defer cancel()
+ ret, optval, err := dut.GetSockOptWithErrno(ctx, sockfd, level, optname, optlen)
+ if ret != 0 {
+ dut.t.Fatalf("failed to GetSockOpt: %s", err)
+ }
+ return optval
+}
+
+// GetSockOptWithErrno calls getsockopt on the DUT. Because endianess and the
+// width of values might differ between the testbench and DUT architectures,
+// prefer to use a more specific GetSockOptXxxWithErrno function.
+func (dut *DUT) GetSockOptWithErrno(ctx context.Context, sockfd, level, optname, optlen int32) (int32, []byte, error) {
+ dut.t.Helper()
+ req := pb.GetSockOptRequest{
+ Sockfd: sockfd,
+ Level: level,
+ Optname: optname,
+ Optlen: optlen,
+ }
+ resp, err := dut.posixServer.GetSockOpt(ctx, &req)
+ if err != nil {
+ dut.t.Fatalf("failed to call GetSockOpt: %s", err)
+ }
+ return resp.GetRet(), resp.GetOptval(), syscall.Errno(resp.GetErrno_())
+}
+
+// GetSockOptInt calls getsockopt on the DUT and causes a fatal test failure
+// if it doesn't succeed. If more control over the int optval or error handling
+// is needed, use GetSockOptIntWithErrno.
+func (dut *DUT) GetSockOptInt(sockfd, level, optname int32) int32 {
+ dut.t.Helper()
+ ctx, cancel := context.WithTimeout(context.Background(), *rpcTimeout)
+ defer cancel()
+ ret, intval, err := dut.GetSockOptIntWithErrno(ctx, sockfd, level, optname)
+ if ret != 0 {
+ dut.t.Fatalf("failed to GetSockOptInt: %s", err)
+ }
+ return intval
+}
+
+// GetSockOptIntWithErrno calls getsockopt with an integer optval.
+func (dut *DUT) GetSockOptIntWithErrno(ctx context.Context, sockfd, level, optname int32) (int32, int32, error) {
+ dut.t.Helper()
+ req := pb.GetSockOptIntRequest{
+ Sockfd: sockfd,
+ Level: level,
+ Optname: optname,
+ }
+ resp, err := dut.posixServer.GetSockOptInt(ctx, &req)
+ if err != nil {
+ dut.t.Fatalf("failed to call GetSockOptInt: %s", err)
+ }
+ return resp.GetRet(), resp.GetIntval(), syscall.Errno(resp.GetErrno_())
+}
+
+// GetSockOptTimeval calls getsockopt on the DUT and causes a fatal test failure
+// if it doesn't succeed. If more control over the timeout or error handling is
+// needed, use GetSockOptTimevalWithErrno.
+func (dut *DUT) GetSockOptTimeval(sockfd, level, optname int32) unix.Timeval {
+ dut.t.Helper()
+ ctx, cancel := context.WithTimeout(context.Background(), *rpcTimeout)
+ defer cancel()
+ ret, timeval, err := dut.GetSockOptTimevalWithErrno(ctx, sockfd, level, optname)
+ if ret != 0 {
+ dut.t.Fatalf("failed to GetSockOptTimeval: %s", err)
+ }
+ return timeval
+}
+
+// GetSockOptTimevalWithErrno calls getsockopt and returns a timeval.
+func (dut *DUT) GetSockOptTimevalWithErrno(ctx context.Context, sockfd, level, optname int32) (int32, unix.Timeval, error) {
+ dut.t.Helper()
+ req := pb.GetSockOptTimevalRequest{
+ Sockfd: sockfd,
+ Level: level,
+ Optname: optname,
+ }
+ resp, err := dut.posixServer.GetSockOptTimeval(ctx, &req)
+ if err != nil {
+ dut.t.Fatalf("failed to call GetSockOptTimeval: %s", err)
+ }
+ timeval := unix.Timeval{
+ Sec: resp.GetTimeval().Seconds,
+ Usec: resp.GetTimeval().Microseconds,
+ }
+ return resp.GetRet(), timeval, syscall.Errno(resp.GetErrno_())
+}
+
// Listen calls listen on the DUT and causes a fatal test failure if it doesn't
// succeed. If more control over the timeout or error handling is needed, use
// ListenWithErrno.
@@ -320,6 +443,36 @@ func (dut *DUT) SendWithErrno(ctx context.Context, sockfd int32, buf []byte, fla
return resp.GetRet(), syscall.Errno(resp.GetErrno_())
}
+// SendTo calls sendto on the DUT and causes a fatal test failure if it doesn't
+// succeed. If more control over the timeout or error handling is needed, use
+// SendToWithErrno.
+func (dut *DUT) SendTo(sockfd int32, buf []byte, flags int32, destAddr unix.Sockaddr) int32 {
+ dut.t.Helper()
+ ctx, cancel := context.WithTimeout(context.Background(), *rpcTimeout)
+ defer cancel()
+ ret, err := dut.SendToWithErrno(ctx, sockfd, buf, flags, destAddr)
+ if ret == -1 {
+ dut.t.Fatalf("failed to sendto: %s", err)
+ }
+ return ret
+}
+
+// SendToWithErrno calls sendto on the DUT.
+func (dut *DUT) SendToWithErrno(ctx context.Context, sockfd int32, buf []byte, flags int32, destAddr unix.Sockaddr) (int32, error) {
+ dut.t.Helper()
+ req := pb.SendToRequest{
+ Sockfd: sockfd,
+ Buf: buf,
+ Flags: flags,
+ DestAddr: dut.sockaddrToProto(destAddr),
+ }
+ resp, err := dut.posixServer.SendTo(ctx, &req)
+ if err != nil {
+ dut.t.Fatalf("faled to call SendTo: %s", err)
+ }
+ return resp.GetRet(), syscall.Errno(resp.GetErrno_())
+}
+
// SetSockOpt calls setsockopt on the DUT and causes a fatal test failure if it
// doesn't succeed. If more control over the timeout or error handling is
// needed, use SetSockOptWithErrno. Because endianess and the width of values
diff --git a/test/packetimpact/testbench/layers.go b/test/packetimpact/testbench/layers.go
index 817f5c261..165f62d3b 100644
--- a/test/packetimpact/testbench/layers.go
+++ b/test/packetimpact/testbench/layers.go
@@ -58,7 +58,7 @@ type Layer interface {
next() Layer
// prev gets a pointer to the Layer encapsulating this one.
- prev() Layer
+ Prev() Layer
// setNext sets the pointer to the encapsulated Layer.
setNext(Layer)
@@ -80,7 +80,8 @@ func (lb *LayerBase) next() Layer {
return lb.nextLayer
}
-func (lb *LayerBase) prev() Layer {
+// Prev returns the previous layer.
+func (lb *LayerBase) Prev() Layer {
return lb.prevLayer
}
@@ -340,6 +341,8 @@ func (l *IPv4) ToBytes() ([]byte, error) {
fields.Protocol = uint8(header.TCPProtocolNumber)
case *UDP:
fields.Protocol = uint8(header.UDPProtocolNumber)
+ case *ICMPv4:
+ fields.Protocol = uint8(header.ICMPv4ProtocolNumber)
default:
// TODO(b/150301488): Support more protocols as needed.
return nil, fmt.Errorf("ipv4 header's next layer is unrecognized: %#v", n)
@@ -403,6 +406,8 @@ func parseIPv4(b []byte) (Layer, layerParser) {
nextParser = parseTCP
case header.UDPProtocolNumber:
nextParser = parseUDP
+ case header.ICMPv4ProtocolNumber:
+ nextParser = parseICMPv4
default:
// Assume that the rest is a payload.
nextParser = parsePayload
@@ -562,7 +567,7 @@ func (l *ICMPv6) ToBytes() ([]byte, error) {
if l.Checksum != nil {
h.SetChecksum(*l.Checksum)
} else {
- ipv6 := l.prev().(*IPv6)
+ ipv6 := l.Prev().(*IPv6)
h.SetChecksum(header.ICMPv6Checksum(h, *ipv6.SrcAddr, *ipv6.DstAddr, buffer.VectorisedView{}))
}
return h, nil
@@ -606,6 +611,72 @@ func (l *ICMPv6) merge(other Layer) error {
return mergeLayer(l, other)
}
+// ICMPv4Type is a helper routine that allocates a new header.ICMPv4Type value
+// to store t and returns a pointer to it.
+func ICMPv4Type(t header.ICMPv4Type) *header.ICMPv4Type {
+ return &t
+}
+
+// ICMPv4 can construct and match an ICMPv4 encapsulation.
+type ICMPv4 struct {
+ LayerBase
+ Type *header.ICMPv4Type
+ Code *uint8
+ Checksum *uint16
+}
+
+func (l *ICMPv4) String() string {
+ return stringLayer(l)
+}
+
+// ToBytes implements Layer.ToBytes.
+func (l *ICMPv4) ToBytes() ([]byte, error) {
+ b := make([]byte, header.ICMPv4MinimumSize)
+ h := header.ICMPv4(b)
+ if l.Type != nil {
+ h.SetType(*l.Type)
+ }
+ if l.Code != nil {
+ h.SetCode(byte(*l.Code))
+ }
+ if l.Checksum != nil {
+ h.SetChecksum(*l.Checksum)
+ return h, nil
+ }
+ payload, err := payload(l)
+ if err != nil {
+ return nil, err
+ }
+ h.SetChecksum(header.ICMPv4Checksum(h, payload))
+ return h, nil
+}
+
+// parseICMPv4 parses the bytes as an ICMPv4 header, returning a Layer and a
+// parser for the encapsulated payload.
+func parseICMPv4(b []byte) (Layer, layerParser) {
+ h := header.ICMPv4(b)
+ icmpv4 := ICMPv4{
+ Type: ICMPv4Type(h.Type()),
+ Code: Uint8(h.Code()),
+ Checksum: Uint16(h.Checksum()),
+ }
+ return &icmpv4, parsePayload
+}
+
+func (l *ICMPv4) match(other Layer) bool {
+ return equalLayer(l, other)
+}
+
+func (l *ICMPv4) length() int {
+ return header.ICMPv4MinimumSize
+}
+
+// merge overrides the values in l with the values from other but only in fields
+// where the value is not nil.
+func (l *ICMPv4) merge(other Layer) error {
+ return mergeLayer(l, other)
+}
+
// TCP can construct and match a TCP encapsulation.
type TCP struct {
LayerBase
@@ -676,25 +747,34 @@ func totalLength(l Layer) int {
return totalLength
}
+// payload returns a buffer.VectorisedView of l's payload.
+func payload(l Layer) (buffer.VectorisedView, error) {
+ var payloadBytes buffer.VectorisedView
+ for current := l.next(); current != nil; current = current.next() {
+ payload, err := current.ToBytes()
+ if err != nil {
+ return buffer.VectorisedView{}, fmt.Errorf("can't get bytes for next header: %s", payload)
+ }
+ payloadBytes.AppendView(payload)
+ }
+ return payloadBytes, nil
+}
+
// layerChecksum calculates the checksum of the Layer header, including the
-// peusdeochecksum of the layer before it and all the bytes after it..
+// peusdeochecksum of the layer before it and all the bytes after it.
func layerChecksum(l Layer, protoNumber tcpip.TransportProtocolNumber) (uint16, error) {
totalLength := uint16(totalLength(l))
var xsum uint16
- switch s := l.prev().(type) {
+ switch s := l.Prev().(type) {
case *IPv4:
xsum = header.PseudoHeaderChecksum(protoNumber, *s.SrcAddr, *s.DstAddr, totalLength)
default:
// TODO(b/150301488): Support more protocols, like IPv6.
return 0, fmt.Errorf("can't get src and dst addr from previous layer: %#v", s)
}
- var payloadBytes buffer.VectorisedView
- for current := l.next(); current != nil; current = current.next() {
- payload, err := current.ToBytes()
- if err != nil {
- return 0, fmt.Errorf("can't get bytes for next header: %s", payload)
- }
- payloadBytes.AppendView(payload)
+ payloadBytes, err := payload(l)
+ if err != nil {
+ return 0, err
}
xsum = header.ChecksumVV(payloadBytes, xsum)
return xsum, nil