mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add various statistics
PiperOrigin-RevId: 210442599 Change-Id: I9498351f461dc69c77b7f815d526c5693bec8e4a
This commit is contained in:
committed by
Shentubot
parent
0b3bfe2ea3
commit
0923bcf06b
@@ -118,7 +118,7 @@ func NewWithFile(lower tcpip.LinkEndpointID, file *os.File, snapLen uint32) (tcp
|
||||
// logs the packet before forwarding to the actual dispatcher.
|
||||
func (e *endpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
|
||||
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
|
||||
LogPacket("recv", protocol, vv.First(), nil)
|
||||
logPacket("recv", protocol, vv.First(), nil)
|
||||
}
|
||||
if e.file != nil && atomic.LoadUint32(&LogPacketsToFile) == 1 {
|
||||
vs := vv.Views()
|
||||
@@ -190,7 +190,7 @@ func (e *endpoint) LinkAddress() tcpip.LinkAddress {
|
||||
// the request to the lower endpoint.
|
||||
func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.View, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
|
||||
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
|
||||
LogPacket("send", protocol, hdr.UsedBytes(), payload)
|
||||
logPacket("send", protocol, hdr.UsedBytes(), payload)
|
||||
}
|
||||
if e.file != nil && atomic.LoadUint32(&LogPacketsToFile) == 1 {
|
||||
hdrBuf := hdr.UsedBytes()
|
||||
@@ -226,8 +226,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
|
||||
return e.lower.WritePacket(r, hdr, payload, protocol)
|
||||
}
|
||||
|
||||
// LogPacket logs the given packet.
|
||||
func LogPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b, plb []byte) {
|
||||
func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b, plb []byte) {
|
||||
// Figure out the network layer info.
|
||||
var transProto uint8
|
||||
src := tcpip.Address("unknown")
|
||||
@@ -316,9 +315,19 @@ func LogPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b, plb []byt
|
||||
case header.TCPProtocolNumber:
|
||||
transName = "tcp"
|
||||
tcp := header.TCP(b)
|
||||
offset := int(tcp.DataOffset())
|
||||
if offset < header.TCPMinimumSize {
|
||||
details += fmt.Sprintf("invalid packet: tcp data offset too small %d", offset)
|
||||
break
|
||||
}
|
||||
if offset > len(tcp) {
|
||||
details += fmt.Sprintf("invalid packet: tcp data offset %d larger than packet buffer length %d", offset, len(tcp))
|
||||
break
|
||||
}
|
||||
|
||||
srcPort = tcp.SourcePort()
|
||||
dstPort = tcp.DestinationPort()
|
||||
size -= uint16(tcp.DataOffset())
|
||||
size -= uint16(offset)
|
||||
|
||||
// Initialize the TCP flags.
|
||||
flags := tcp.Flags()
|
||||
@@ -334,6 +343,7 @@ func LogPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b, plb []byt
|
||||
} else {
|
||||
details += fmt.Sprintf(" options: %+v", tcp.ParsedOptions())
|
||||
}
|
||||
|
||||
default:
|
||||
log.Infof("%s %v -> %v unknown transport protocol: %d", prefix, src, dst, transProto)
|
||||
return
|
||||
|
||||
@@ -12,8 +12,11 @@ go_test(
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/buffer",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/link/loopback",
|
||||
"//pkg/tcpip/network/ipv4",
|
||||
"//pkg/tcpip/network/ipv6",
|
||||
"//pkg/tcpip/stack",
|
||||
"//pkg/tcpip/transport/tcp",
|
||||
"//pkg/tcpip/transport/udp",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -20,9 +20,25 @@ import (
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/link/loopback"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv6"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/tcp"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/udp"
|
||||
)
|
||||
|
||||
const (
|
||||
localIpv4Addr = "\x0a\x00\x00\x01"
|
||||
remoteIpv4Addr = "\x0a\x00\x00\x02"
|
||||
ipv4SubnetAddr = "\x0a\x00\x00\x00"
|
||||
ipv4SubnetMask = "\xff\xff\xff\x00"
|
||||
ipv4Gateway = "\x0a\x00\x00\x03"
|
||||
localIpv6Addr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
|
||||
remoteIpv6Addr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
|
||||
ipv6SubnetAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
ipv6SubnetMask = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00"
|
||||
ipv6Gateway = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"
|
||||
)
|
||||
|
||||
// testObject implements two interfaces: LinkEndpoint and TransportDispatcher.
|
||||
@@ -152,10 +168,38 @@ func (t *testObject) WritePacket(_ *stack.Route, hdr *buffer.Prependable, payloa
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildIPv4Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) {
|
||||
s := stack.New([]string{ipv4.ProtocolName}, []string{udp.ProtocolName, tcp.ProtocolName}, stack.Options{})
|
||||
s.CreateNIC(1, loopback.New())
|
||||
s.AddAddress(1, ipv4.ProtocolNumber, local)
|
||||
s.SetRouteTable([]tcpip.Route{{
|
||||
Destination: ipv4SubnetAddr,
|
||||
Mask: ipv4SubnetMask,
|
||||
Gateway: ipv4Gateway,
|
||||
NIC: 1,
|
||||
}})
|
||||
|
||||
return s.FindRoute(1, local, remote, ipv4.ProtocolNumber)
|
||||
}
|
||||
|
||||
func buildIPv6Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) {
|
||||
s := stack.New([]string{ipv6.ProtocolName}, []string{udp.ProtocolName, tcp.ProtocolName}, stack.Options{})
|
||||
s.CreateNIC(1, loopback.New())
|
||||
s.AddAddress(1, ipv6.ProtocolNumber, local)
|
||||
s.SetRouteTable([]tcpip.Route{{
|
||||
Destination: ipv6SubnetAddr,
|
||||
Mask: ipv6SubnetMask,
|
||||
Gateway: ipv6Gateway,
|
||||
NIC: 1,
|
||||
}})
|
||||
|
||||
return s.FindRoute(1, local, remote, ipv6.ProtocolNumber)
|
||||
}
|
||||
|
||||
func TestIPv4Send(t *testing.T) {
|
||||
o := testObject{t: t, v4: true}
|
||||
proto := ipv4.NewProtocol()
|
||||
ep, err := proto.NewEndpoint(1, "\x0a\x00\x00\x01", nil, nil, &o)
|
||||
ep, err := proto.NewEndpoint(1, localIpv4Addr, nil, nil, &o)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
@@ -171,13 +215,13 @@ func TestIPv4Send(t *testing.T) {
|
||||
|
||||
// Issue the write.
|
||||
o.protocol = 123
|
||||
o.srcAddr = "\x0a\x00\x00\x01"
|
||||
o.dstAddr = "\x0a\x00\x00\x02"
|
||||
o.srcAddr = localIpv4Addr
|
||||
o.dstAddr = remoteIpv4Addr
|
||||
o.contents = payload
|
||||
|
||||
r := stack.Route{
|
||||
RemoteAddress: o.dstAddr,
|
||||
LocalAddress: o.srcAddr,
|
||||
r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr)
|
||||
if err != nil {
|
||||
t.Fatalf("could not find route: %v", err)
|
||||
}
|
||||
if err := ep.WritePacket(&r, &hdr, payload, 123); err != nil {
|
||||
t.Fatalf("WritePacket failed: %v", err)
|
||||
@@ -187,7 +231,7 @@ func TestIPv4Send(t *testing.T) {
|
||||
func TestIPv4Receive(t *testing.T) {
|
||||
o := testObject{t: t, v4: true}
|
||||
proto := ipv4.NewProtocol()
|
||||
ep, err := proto.NewEndpoint(1, "\x0a\x00\x00\x01", nil, &o, nil)
|
||||
ep, err := proto.NewEndpoint(1, localIpv4Addr, nil, &o, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
@@ -200,8 +244,8 @@ func TestIPv4Receive(t *testing.T) {
|
||||
TotalLength: uint16(totalLen),
|
||||
TTL: 20,
|
||||
Protocol: 10,
|
||||
SrcAddr: "\x0a\x00\x00\x02",
|
||||
DstAddr: "\x0a\x00\x00\x01",
|
||||
SrcAddr: remoteIpv4Addr,
|
||||
DstAddr: localIpv4Addr,
|
||||
})
|
||||
|
||||
// Make payload be non-zero.
|
||||
@@ -211,13 +255,13 @@ func TestIPv4Receive(t *testing.T) {
|
||||
|
||||
// Give packet to ipv4 endpoint, dispatcher will validate that it's ok.
|
||||
o.protocol = 10
|
||||
o.srcAddr = "\x0a\x00\x00\x02"
|
||||
o.dstAddr = "\x0a\x00\x00\x01"
|
||||
o.srcAddr = remoteIpv4Addr
|
||||
o.dstAddr = localIpv4Addr
|
||||
o.contents = view[header.IPv4MinimumSize:totalLen]
|
||||
|
||||
r := stack.Route{
|
||||
LocalAddress: o.dstAddr,
|
||||
RemoteAddress: o.srcAddr,
|
||||
r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr)
|
||||
if err != nil {
|
||||
t.Fatalf("could not find route: %v", err)
|
||||
}
|
||||
var views [1]buffer.View
|
||||
vv := view.ToVectorisedView(views)
|
||||
@@ -248,7 +292,7 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
{"Zero-length packet", 0, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv4MinimumSize + header.ICMPv4DstUnreachableMinimumSize + 8},
|
||||
}
|
||||
r := stack.Route{
|
||||
LocalAddress: "\x0a\x00\x00\x01",
|
||||
LocalAddress: localIpv4Addr,
|
||||
RemoteAddress: "\x0a\x00\x00\xbb",
|
||||
}
|
||||
for _, c := range cases {
|
||||
@@ -256,7 +300,7 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
var views [1]buffer.View
|
||||
o := testObject{t: t}
|
||||
proto := ipv4.NewProtocol()
|
||||
ep, err := proto.NewEndpoint(1, "\x0a\x00\x00\x01", nil, &o, nil)
|
||||
ep, err := proto.NewEndpoint(1, localIpv4Addr, nil, &o, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
@@ -273,7 +317,7 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
TTL: 20,
|
||||
Protocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
SrcAddr: "\x0a\x00\x00\xbb",
|
||||
DstAddr: "\x0a\x00\x00\x01",
|
||||
DstAddr: localIpv4Addr,
|
||||
})
|
||||
|
||||
// Create the ICMP header.
|
||||
@@ -290,8 +334,8 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
TTL: 20,
|
||||
Protocol: 10,
|
||||
FragmentOffset: c.fragmentOffset,
|
||||
SrcAddr: "\x0a\x00\x00\x01",
|
||||
DstAddr: "\x0a\x00\x00\x02",
|
||||
SrcAddr: localIpv4Addr,
|
||||
DstAddr: remoteIpv4Addr,
|
||||
})
|
||||
|
||||
// Make payload be non-zero.
|
||||
@@ -302,8 +346,8 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
// Give packet to IPv4 endpoint, dispatcher will validate that
|
||||
// it's ok.
|
||||
o.protocol = 10
|
||||
o.srcAddr = "\x0a\x00\x00\x02"
|
||||
o.dstAddr = "\x0a\x00\x00\x01"
|
||||
o.srcAddr = remoteIpv4Addr
|
||||
o.dstAddr = localIpv4Addr
|
||||
o.contents = view[dataOffset:]
|
||||
o.typ = c.expectedTyp
|
||||
o.extra = c.expectedExtra
|
||||
@@ -321,7 +365,7 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
o := testObject{t: t, v4: true}
|
||||
proto := ipv4.NewProtocol()
|
||||
ep, err := proto.NewEndpoint(1, "\x0a\x00\x00\x01", nil, &o, nil)
|
||||
ep, err := proto.NewEndpoint(1, localIpv4Addr, nil, &o, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
@@ -337,8 +381,8 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
Protocol: 10,
|
||||
FragmentOffset: 0,
|
||||
Flags: header.IPv4FlagMoreFragments,
|
||||
SrcAddr: "\x0a\x00\x00\x02",
|
||||
DstAddr: "\x0a\x00\x00\x01",
|
||||
SrcAddr: remoteIpv4Addr,
|
||||
DstAddr: localIpv4Addr,
|
||||
})
|
||||
// Make payload be non-zero.
|
||||
for i := header.IPv4MinimumSize; i < totalLen; i++ {
|
||||
@@ -353,8 +397,8 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
TTL: 20,
|
||||
Protocol: 10,
|
||||
FragmentOffset: 24,
|
||||
SrcAddr: "\x0a\x00\x00\x02",
|
||||
DstAddr: "\x0a\x00\x00\x01",
|
||||
SrcAddr: remoteIpv4Addr,
|
||||
DstAddr: localIpv4Addr,
|
||||
})
|
||||
// Make payload be non-zero.
|
||||
for i := header.IPv4MinimumSize; i < totalLen; i++ {
|
||||
@@ -363,13 +407,13 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
|
||||
// Give packet to ipv4 endpoint, dispatcher will validate that it's ok.
|
||||
o.protocol = 10
|
||||
o.srcAddr = "\x0a\x00\x00\x02"
|
||||
o.dstAddr = "\x0a\x00\x00\x01"
|
||||
o.srcAddr = remoteIpv4Addr
|
||||
o.dstAddr = localIpv4Addr
|
||||
o.contents = append(frag1[header.IPv4MinimumSize:totalLen], frag2[header.IPv4MinimumSize:totalLen]...)
|
||||
|
||||
r := stack.Route{
|
||||
LocalAddress: o.dstAddr,
|
||||
RemoteAddress: o.srcAddr,
|
||||
r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr)
|
||||
if err != nil {
|
||||
t.Fatalf("could not find route: %v", err)
|
||||
}
|
||||
|
||||
// Send first segment.
|
||||
@@ -393,7 +437,7 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
func TestIPv6Send(t *testing.T) {
|
||||
o := testObject{t: t}
|
||||
proto := ipv6.NewProtocol()
|
||||
ep, err := proto.NewEndpoint(1, "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", nil, nil, &o)
|
||||
ep, err := proto.NewEndpoint(1, localIpv6Addr, nil, nil, &o)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
@@ -409,13 +453,13 @@ func TestIPv6Send(t *testing.T) {
|
||||
|
||||
// Issue the write.
|
||||
o.protocol = 123
|
||||
o.srcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
|
||||
o.dstAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
|
||||
o.srcAddr = localIpv6Addr
|
||||
o.dstAddr = remoteIpv6Addr
|
||||
o.contents = payload
|
||||
|
||||
r := stack.Route{
|
||||
RemoteAddress: o.dstAddr,
|
||||
LocalAddress: o.srcAddr,
|
||||
r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr)
|
||||
if err != nil {
|
||||
t.Fatalf("could not find route: %v", err)
|
||||
}
|
||||
if err := ep.WritePacket(&r, &hdr, payload, 123); err != nil {
|
||||
t.Fatalf("WritePacket failed: %v", err)
|
||||
@@ -425,7 +469,7 @@ func TestIPv6Send(t *testing.T) {
|
||||
func TestIPv6Receive(t *testing.T) {
|
||||
o := testObject{t: t}
|
||||
proto := ipv6.NewProtocol()
|
||||
ep, err := proto.NewEndpoint(1, "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", nil, &o, nil)
|
||||
ep, err := proto.NewEndpoint(1, localIpv6Addr, nil, &o, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
@@ -437,8 +481,8 @@ func TestIPv6Receive(t *testing.T) {
|
||||
PayloadLength: uint16(totalLen - header.IPv6MinimumSize),
|
||||
NextHeader: 10,
|
||||
HopLimit: 20,
|
||||
SrcAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
|
||||
DstAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
|
||||
SrcAddr: remoteIpv6Addr,
|
||||
DstAddr: localIpv6Addr,
|
||||
})
|
||||
|
||||
// Make payload be non-zero.
|
||||
@@ -448,14 +492,15 @@ func TestIPv6Receive(t *testing.T) {
|
||||
|
||||
// Give packet to ipv6 endpoint, dispatcher will validate that it's ok.
|
||||
o.protocol = 10
|
||||
o.srcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
|
||||
o.dstAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
|
||||
o.srcAddr = remoteIpv6Addr
|
||||
o.dstAddr = localIpv6Addr
|
||||
o.contents = view[header.IPv6MinimumSize:totalLen]
|
||||
|
||||
r := stack.Route{
|
||||
LocalAddress: o.dstAddr,
|
||||
RemoteAddress: o.srcAddr,
|
||||
r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr)
|
||||
if err != nil {
|
||||
t.Fatalf("could not find route: %v", err)
|
||||
}
|
||||
|
||||
var views [1]buffer.View
|
||||
vv := view.ToVectorisedView(views)
|
||||
ep.HandlePacket(&r, &vv)
|
||||
@@ -491,7 +536,7 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
{"Zero-length packet", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv6MinimumSize + header.ICMPv6DstUnreachableMinimumSize + 8},
|
||||
}
|
||||
r := stack.Route{
|
||||
LocalAddress: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
|
||||
LocalAddress: localIpv6Addr,
|
||||
RemoteAddress: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa",
|
||||
}
|
||||
for _, c := range cases {
|
||||
@@ -499,7 +544,7 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
var views [1]buffer.View
|
||||
o := testObject{t: t}
|
||||
proto := ipv6.NewProtocol()
|
||||
ep, err := proto.NewEndpoint(1, "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", nil, &o, nil)
|
||||
ep, err := proto.NewEndpoint(1, localIpv6Addr, nil, &o, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
@@ -519,7 +564,7 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
NextHeader: uint8(header.ICMPv6ProtocolNumber),
|
||||
HopLimit: 20,
|
||||
SrcAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa",
|
||||
DstAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
|
||||
DstAddr: localIpv6Addr,
|
||||
})
|
||||
|
||||
// Create the ICMP header.
|
||||
@@ -534,8 +579,8 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
PayloadLength: 100,
|
||||
NextHeader: 10,
|
||||
HopLimit: 20,
|
||||
SrcAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
|
||||
DstAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
|
||||
SrcAddr: localIpv6Addr,
|
||||
DstAddr: remoteIpv6Addr,
|
||||
})
|
||||
|
||||
// Build the fragmentation header if needed.
|
||||
@@ -558,8 +603,8 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
// Give packet to IPv6 endpoint, dispatcher will validate that
|
||||
// it's ok.
|
||||
o.protocol = 10
|
||||
o.srcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
|
||||
o.dstAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
|
||||
o.srcAddr = remoteIpv6Addr
|
||||
o.dstAddr = localIpv6Addr
|
||||
o.contents = view[dataOffset:]
|
||||
o.typ = c.expectedTyp
|
||||
o.extra = c.expectedExtra
|
||||
|
||||
@@ -121,6 +121,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
|
||||
DstAddr: r.RemoteAddress,
|
||||
})
|
||||
ip.SetChecksum(^ip.CalculateChecksum())
|
||||
r.Stats().IP.PacketsSent.Increment()
|
||||
|
||||
return e.linkEP.WritePacket(r, hdr, payload, ProtocolNumber)
|
||||
}
|
||||
@@ -153,6 +154,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, vv *buffer.VectorisedView) {
|
||||
e.handleICMP(r, vv)
|
||||
return
|
||||
}
|
||||
r.Stats().IP.PacketsDelivered.Increment()
|
||||
e.dispatcher.DeliverTransportPacket(r, p, vv)
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
|
||||
SrcAddr: tcpip.Address(e.address[:]),
|
||||
DstAddr: r.RemoteAddress,
|
||||
})
|
||||
r.Stats().IP.PacketsSent.Increment()
|
||||
|
||||
return e.linkEP.WritePacket(r, hdr, payload, ProtocolNumber)
|
||||
}
|
||||
@@ -118,6 +119,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, vv *buffer.VectorisedView) {
|
||||
return
|
||||
}
|
||||
|
||||
r.Stats().IP.PacketsDelivered.Increment()
|
||||
e.dispatcher.DeliverTransportPacket(r, p, vv)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"gvisor.googlesource.com/gvisor/pkg/ilist"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
|
||||
)
|
||||
|
||||
// NIC represents a "network interface card" to which the networking stack is
|
||||
@@ -286,6 +287,10 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin
|
||||
return
|
||||
}
|
||||
|
||||
if netProto.Number() == header.IPv4ProtocolNumber || netProto.Number() == header.IPv6ProtocolNumber {
|
||||
n.stack.stats.IP.PacketsReceived.Increment()
|
||||
}
|
||||
|
||||
if len(vv.First()) < netProto.MinimumPacketSize() {
|
||||
n.stack.stats.MalformedRcvdPackets.Increment()
|
||||
return
|
||||
@@ -330,7 +335,7 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin
|
||||
}
|
||||
|
||||
if ref == nil {
|
||||
n.stack.stats.UnknownNetworkEndpointRcvdPackets.Increment()
|
||||
n.stack.stats.IP.InvalidAddressesReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,11 @@ func (r *Route) MaxHeaderLength() uint16 {
|
||||
return r.ref.ep.MaxHeaderLength()
|
||||
}
|
||||
|
||||
// Stats returns a mutable copy of current stats.
|
||||
func (r *Route) Stats() tcpip.Stats {
|
||||
return r.ref.nic.stack.Stats()
|
||||
}
|
||||
|
||||
// PseudoHeaderChecksum forwards the call to the network endpoint's
|
||||
// implementation.
|
||||
func (r *Route) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber) uint16 {
|
||||
@@ -125,7 +130,11 @@ func (r *Route) IsResolutionRequired() bool {
|
||||
|
||||
// WritePacket writes the packet through the given route.
|
||||
func (r *Route) WritePacket(hdr *buffer.Prependable, payload buffer.View, protocol tcpip.TransportProtocolNumber) *tcpip.Error {
|
||||
return r.ref.ep.WritePacket(r, hdr, payload, protocol)
|
||||
err := r.ref.ep.WritePacket(r, hdr, payload, protocol)
|
||||
if err == tcpip.ErrNoRoute {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MTU returns the MTU of the underlying network endpoint.
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
|
||||
)
|
||||
|
||||
type protocolIDs struct {
|
||||
@@ -111,6 +112,10 @@ func (d *transportDemuxer) deliverPacket(r *Route, protocol tcpip.TransportProto
|
||||
|
||||
// Fail if we didn't find one.
|
||||
if ep == nil {
|
||||
// UDP packet could not be delivered to an unknown destination port.
|
||||
if protocol == header.UDPProtocolNumber {
|
||||
r.Stats().UDP.UnknownPortErrors.Increment()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
+146
-52
@@ -31,6 +31,7 @@ package tcpip
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -47,48 +48,56 @@ import (
|
||||
// Note: to support save / restore, it is important that all tcpip errors have
|
||||
// distinct error messages.
|
||||
type Error struct {
|
||||
string
|
||||
msg string
|
||||
|
||||
ignoreStats bool
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.String.
|
||||
func (e *Error) String() string {
|
||||
return e.string
|
||||
return e.msg
|
||||
}
|
||||
|
||||
// IgnoreStats indicates whether this error type should be included in failure
|
||||
// counts in tcpip.Stats structs.
|
||||
func (e *Error) IgnoreStats() bool {
|
||||
return e.ignoreStats
|
||||
}
|
||||
|
||||
// Errors that can be returned by the network stack.
|
||||
var (
|
||||
ErrUnknownProtocol = &Error{"unknown protocol"}
|
||||
ErrUnknownNICID = &Error{"unknown nic id"}
|
||||
ErrUnknownProtocolOption = &Error{"unknown option for protocol"}
|
||||
ErrDuplicateNICID = &Error{"duplicate nic id"}
|
||||
ErrDuplicateAddress = &Error{"duplicate address"}
|
||||
ErrNoRoute = &Error{"no route"}
|
||||
ErrBadLinkEndpoint = &Error{"bad link layer endpoint"}
|
||||
ErrAlreadyBound = &Error{"endpoint already bound"}
|
||||
ErrInvalidEndpointState = &Error{"endpoint is in invalid state"}
|
||||
ErrAlreadyConnecting = &Error{"endpoint is already connecting"}
|
||||
ErrAlreadyConnected = &Error{"endpoint is already connected"}
|
||||
ErrNoPortAvailable = &Error{"no ports are available"}
|
||||
ErrPortInUse = &Error{"port is in use"}
|
||||
ErrBadLocalAddress = &Error{"bad local address"}
|
||||
ErrClosedForSend = &Error{"endpoint is closed for send"}
|
||||
ErrClosedForReceive = &Error{"endpoint is closed for receive"}
|
||||
ErrWouldBlock = &Error{"operation would block"}
|
||||
ErrConnectionRefused = &Error{"connection was refused"}
|
||||
ErrTimeout = &Error{"operation timed out"}
|
||||
ErrAborted = &Error{"operation aborted"}
|
||||
ErrConnectStarted = &Error{"connection attempt started"}
|
||||
ErrDestinationRequired = &Error{"destination address is required"}
|
||||
ErrNotSupported = &Error{"operation not supported"}
|
||||
ErrQueueSizeNotSupported = &Error{"queue size querying not supported"}
|
||||
ErrNotConnected = &Error{"endpoint not connected"}
|
||||
ErrConnectionReset = &Error{"connection reset by peer"}
|
||||
ErrConnectionAborted = &Error{"connection aborted"}
|
||||
ErrNoSuchFile = &Error{"no such file"}
|
||||
ErrInvalidOptionValue = &Error{"invalid option value specified"}
|
||||
ErrNoLinkAddress = &Error{"no remote link address"}
|
||||
ErrBadAddress = &Error{"bad address"}
|
||||
ErrNetworkUnreachable = &Error{"network is unreachable"}
|
||||
ErrUnknownProtocol = &Error{msg: "unknown protocol"}
|
||||
ErrUnknownNICID = &Error{msg: "unknown nic id"}
|
||||
ErrUnknownProtocolOption = &Error{msg: "unknown option for protocol"}
|
||||
ErrDuplicateNICID = &Error{msg: "duplicate nic id"}
|
||||
ErrDuplicateAddress = &Error{msg: "duplicate address"}
|
||||
ErrNoRoute = &Error{msg: "no route"}
|
||||
ErrBadLinkEndpoint = &Error{msg: "bad link layer endpoint"}
|
||||
ErrAlreadyBound = &Error{msg: "endpoint already bound", ignoreStats: true}
|
||||
ErrInvalidEndpointState = &Error{msg: "endpoint is in invalid state"}
|
||||
ErrAlreadyConnecting = &Error{msg: "endpoint is already connecting", ignoreStats: true}
|
||||
ErrAlreadyConnected = &Error{msg: "endpoint is already connected", ignoreStats: true}
|
||||
ErrNoPortAvailable = &Error{msg: "no ports are available"}
|
||||
ErrPortInUse = &Error{msg: "port is in use"}
|
||||
ErrBadLocalAddress = &Error{msg: "bad local address"}
|
||||
ErrClosedForSend = &Error{msg: "endpoint is closed for send"}
|
||||
ErrClosedForReceive = &Error{msg: "endpoint is closed for receive"}
|
||||
ErrWouldBlock = &Error{msg: "operation would block", ignoreStats: true}
|
||||
ErrConnectionRefused = &Error{msg: "connection was refused"}
|
||||
ErrTimeout = &Error{msg: "operation timed out"}
|
||||
ErrAborted = &Error{msg: "operation aborted"}
|
||||
ErrConnectStarted = &Error{msg: "connection attempt started", ignoreStats: true}
|
||||
ErrDestinationRequired = &Error{msg: "destination address is required"}
|
||||
ErrNotSupported = &Error{msg: "operation not supported"}
|
||||
ErrQueueSizeNotSupported = &Error{msg: "queue size querying not supported"}
|
||||
ErrNotConnected = &Error{msg: "endpoint not connected"}
|
||||
ErrConnectionReset = &Error{msg: "connection reset by peer"}
|
||||
ErrConnectionAborted = &Error{msg: "connection aborted"}
|
||||
ErrNoSuchFile = &Error{msg: "no such file"}
|
||||
ErrInvalidOptionValue = &Error{msg: "invalid option value specified"}
|
||||
ErrNoLinkAddress = &Error{msg: "no remote link address"}
|
||||
ErrBadAddress = &Error{msg: "bad address"}
|
||||
ErrNetworkUnreachable = &Error{msg: "network is unreachable"}
|
||||
)
|
||||
|
||||
// Errors related to Subnet
|
||||
@@ -473,7 +482,7 @@ type StatCounter struct {
|
||||
|
||||
// Increment adds one to the counter.
|
||||
func (s *StatCounter) Increment() {
|
||||
atomic.AddUint64(&s.count, 1)
|
||||
s.IncrementBy(1)
|
||||
}
|
||||
|
||||
// Value returns the current value of the counter.
|
||||
@@ -486,6 +495,82 @@ func (s *StatCounter) IncrementBy(v uint64) {
|
||||
atomic.AddUint64(&s.count, v)
|
||||
}
|
||||
|
||||
// IPStats collects IP-specific stats (both v4 and v6).
|
||||
type IPStats struct {
|
||||
// PacketsReceived is the total number of IP packets received from the link
|
||||
// layer in nic.DeliverNetworkPacket.
|
||||
PacketsReceived *StatCounter
|
||||
|
||||
// InvalidAddressesReceived is the total number of IP packets received
|
||||
// with an unknown or invalid destination address.
|
||||
InvalidAddressesReceived *StatCounter
|
||||
|
||||
// PacketsDelivered is the total number of incoming IP packets that
|
||||
// are successfully delivered to the transport layer via HandlePacket.
|
||||
PacketsDelivered *StatCounter
|
||||
|
||||
// PacketsSent is the total number of IP packets sent via WritePacket.
|
||||
PacketsSent *StatCounter
|
||||
|
||||
// OutgoingPacketErrors is the total number of IP packets which failed
|
||||
// to write to a link-layer endpoint.
|
||||
OutgoingPacketErrors *StatCounter
|
||||
}
|
||||
|
||||
// TCPStats collects TCP-specific stats.
|
||||
type TCPStats struct {
|
||||
// ActiveConnectionOpenings is the number of connections opened successfully
|
||||
// via Connect.
|
||||
ActiveConnectionOpenings *StatCounter
|
||||
|
||||
// PassiveConnectionOpenings is the number of connections opened
|
||||
// successfully via Listen.
|
||||
PassiveConnectionOpenings *StatCounter
|
||||
|
||||
// FailedConnectionAttempts is the number of calls to Connect or Listen
|
||||
// (active and passive openings, respectively) that end in an error.
|
||||
FailedConnectionAttempts *StatCounter
|
||||
|
||||
// ValidSegmentsReceived is the number of TCP segments received that the
|
||||
// transport layer successfully parsed.
|
||||
ValidSegmentsReceived *StatCounter
|
||||
|
||||
// InvalidSegmentsReceived is the number of TCP segments received that
|
||||
// the transport layer could not parse.
|
||||
InvalidSegmentsReceived *StatCounter
|
||||
|
||||
// SegmentsSent is the number of TCP segments sent.
|
||||
SegmentsSent *StatCounter
|
||||
|
||||
// ResetsSent is the number of TCP resets sent.
|
||||
ResetsSent *StatCounter
|
||||
|
||||
// ResetsReceived is the number of TCP resets received.
|
||||
ResetsReceived *StatCounter
|
||||
}
|
||||
|
||||
// UDPStats collects UDP-specific stats.
|
||||
type UDPStats struct {
|
||||
// PacketsReceived is the number of UDP datagrams received via
|
||||
// HandlePacket.
|
||||
PacketsReceived *StatCounter
|
||||
|
||||
// UnknownPortErrors is the number of incoming UDP datagrams dropped
|
||||
// because they did not have a known destination port.
|
||||
UnknownPortErrors *StatCounter
|
||||
|
||||
// ReceiveBufferErrors is the number of incoming UDP datagrams dropped
|
||||
// due to the receiving buffer being in an invalid state.
|
||||
ReceiveBufferErrors *StatCounter
|
||||
|
||||
// MalformedPacketsReceived is the number of incoming UDP datagrams
|
||||
// dropped due to the UDP header being in a malformed state.
|
||||
MalformedPacketsReceived *StatCounter
|
||||
|
||||
// PacketsSent is the number of UDP datagrams sent via sendUDP.
|
||||
PacketsSent *StatCounter
|
||||
}
|
||||
|
||||
// Stats holds statistics about the networking stack.
|
||||
//
|
||||
// All fields are optional.
|
||||
@@ -494,33 +579,42 @@ type Stats struct {
|
||||
// stack that were for an unknown or unsupported protocol.
|
||||
UnknownProtocolRcvdPackets *StatCounter
|
||||
|
||||
// UnknownNetworkEndpointRcvdPackets is the number of packets received
|
||||
// by the stack that were for a supported network protocol, but whose
|
||||
// destination address didn't having a matching endpoint.
|
||||
UnknownNetworkEndpointRcvdPackets *StatCounter
|
||||
|
||||
// MalformedRcvPackets is the number of packets received by the stack
|
||||
// that were deemed malformed.
|
||||
MalformedRcvdPackets *StatCounter
|
||||
|
||||
// DroppedPackets is the number of packets dropped due to full queues.
|
||||
DroppedPackets *StatCounter
|
||||
|
||||
// IP breaks out IP-specific stats (both v4 and v6).
|
||||
IP IPStats
|
||||
|
||||
// TCP breaks out TCP-specific stats.
|
||||
TCP TCPStats
|
||||
|
||||
// UDP breaks out UDP-specific stats.
|
||||
UDP UDPStats
|
||||
}
|
||||
|
||||
func fillIn(v reflect.Value) {
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
v := v.Field(i)
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
if s, ok := v.Addr().Interface().(**StatCounter); ok {
|
||||
if *s == nil {
|
||||
*s = &StatCounter{}
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
fillIn(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FillIn returns a copy of s with nil fields initialized to new StatCounters.
|
||||
func (s Stats) FillIn() Stats {
|
||||
if s.UnknownProtocolRcvdPackets == nil {
|
||||
s.UnknownProtocolRcvdPackets = &StatCounter{}
|
||||
}
|
||||
if s.UnknownNetworkEndpointRcvdPackets == nil {
|
||||
s.UnknownNetworkEndpointRcvdPackets = &StatCounter{}
|
||||
}
|
||||
if s.MalformedRcvdPackets == nil {
|
||||
s.MalformedRcvdPackets = &StatCounter{}
|
||||
}
|
||||
if s.DroppedPackets == nil {
|
||||
s.DroppedPackets = &StatCounter{}
|
||||
}
|
||||
fillIn(reflect.ValueOf(&s).Elem())
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
@@ -604,6 +604,11 @@ func sendTCPWithOptions(r *stack.Route, id stack.TransportEndpointID, data buffe
|
||||
tcp.SetChecksum(^tcp.CalculateChecksum(xsum, length))
|
||||
}
|
||||
|
||||
r.Stats().TCP.SegmentsSent.Increment()
|
||||
if (flags & flagRst) != 0 {
|
||||
r.Stats().TCP.ResetsSent.Increment()
|
||||
}
|
||||
|
||||
return r.WritePacket(&hdr, data, ProtocolNumber)
|
||||
}
|
||||
|
||||
@@ -641,6 +646,11 @@ func sendTCP(r *stack.Route, id stack.TransportEndpointID, data buffer.View, fla
|
||||
tcp.SetChecksum(^tcp.CalculateChecksum(xsum, length))
|
||||
}
|
||||
|
||||
r.Stats().TCP.SegmentsSent.Increment()
|
||||
if (flags & flagRst) != 0 {
|
||||
r.Stats().TCP.ResetsSent.Increment()
|
||||
}
|
||||
|
||||
return r.WritePacket(&hdr, data, ProtocolNumber)
|
||||
}
|
||||
|
||||
|
||||
@@ -829,9 +829,14 @@ func (e *endpoint) Connect(addr tcpip.FullAddress) *tcpip.Error {
|
||||
// created (so no new handshaking is done); for stack-accepted connections not
|
||||
// yet accepted by the app, they are restored without running the main goroutine
|
||||
// here.
|
||||
func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool, run bool) *tcpip.Error {
|
||||
func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool, run bool) (err *tcpip.Error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
defer func() {
|
||||
if err != nil && !err.IgnoreStats() {
|
||||
e.stack.Stats().TCP.FailedConnectionAttempts.Increment()
|
||||
}
|
||||
}()
|
||||
|
||||
connectingAddr := addr.Addr
|
||||
|
||||
@@ -960,6 +965,7 @@ func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool, run bool) *tc
|
||||
|
||||
if run {
|
||||
e.workerRunning = true
|
||||
e.stack.Stats().TCP.ActiveConnectionOpenings.Increment()
|
||||
go e.protocolMainLoop(handshake) // S/R-SAFE: will be drained before save.
|
||||
}
|
||||
|
||||
@@ -1032,9 +1038,14 @@ func (e *endpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error {
|
||||
|
||||
// Listen puts the endpoint in "listen" mode, which allows it to accept
|
||||
// new connections.
|
||||
func (e *endpoint) Listen(backlog int) *tcpip.Error {
|
||||
func (e *endpoint) Listen(backlog int) (err *tcpip.Error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
defer func() {
|
||||
if err != nil && !err.IgnoreStats() {
|
||||
e.stack.Stats().TCP.FailedConnectionAttempts.Increment()
|
||||
}
|
||||
}()
|
||||
|
||||
// Allow the backlog to be adjusted if the endpoint is not shutting down.
|
||||
// When the endpoint shuts down, it sets workerCleanup to true, and from
|
||||
@@ -1075,6 +1086,7 @@ func (e *endpoint) Listen(backlog int) *tcpip.Error {
|
||||
}
|
||||
e.workerRunning = true
|
||||
|
||||
e.stack.Stats().TCP.PassiveConnectionOpenings.Increment()
|
||||
go e.protocolListenLoop( // S/R-SAFE: drained on save.
|
||||
seqnum.Size(e.receiveBufferAvailable()))
|
||||
|
||||
@@ -1226,10 +1238,16 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv
|
||||
s := newSegment(r, id, vv)
|
||||
if !s.parse() {
|
||||
e.stack.Stats().MalformedRcvdPackets.Increment()
|
||||
e.stack.Stats().TCP.InvalidSegmentsReceived.Increment()
|
||||
s.decRef()
|
||||
return
|
||||
}
|
||||
|
||||
e.stack.Stats().TCP.ValidSegmentsReceived.Increment()
|
||||
if (s.flags & flagRst) != 0 {
|
||||
e.stack.Stats().TCP.ResetsReceived.Increment()
|
||||
}
|
||||
|
||||
// Send packet to worker goroutine.
|
||||
if e.segmentQueue.enqueue(s) {
|
||||
e.newSegmentWaker.Assert()
|
||||
|
||||
+322
-106
File diff suppressed because it is too large
Load Diff
@@ -267,8 +267,7 @@ func TestSegmentDropWhenTimestampMissing(t *testing.T) {
|
||||
c.WQ.EventRegister(&we, waiter.EventIn)
|
||||
defer c.WQ.EventUnregister(&we)
|
||||
|
||||
stk := c.Stack()
|
||||
droppedPacketsStat := stk.Stats().DroppedPackets
|
||||
droppedPacketsStat := c.Stack().Stats().DroppedPackets
|
||||
droppedPackets := droppedPacketsStat.Value()
|
||||
data := []byte{1, 2, 3}
|
||||
// Save the sequence number as we will reset it later down
|
||||
|
||||
@@ -295,9 +295,8 @@ func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code uint8, p1, p2 []byt
|
||||
c.linkEP.Inject(ipv4.ProtocolNumber, &vv)
|
||||
}
|
||||
|
||||
// SendPacket builds and sends a TCP segment(with the provided payload & TCP
|
||||
// headers) in an IPv4 packet via the link layer endpoint.
|
||||
func (c *Context) SendPacket(payload []byte, h *Headers) {
|
||||
// BuildSegment builds a TCP segment based on the given Headers and payload.
|
||||
func (c *Context) BuildSegment(payload []byte, h *Headers) buffer.VectorisedView {
|
||||
// Allocate a buffer for data and headers.
|
||||
buf := buffer.NewView(header.TCPMinimumSize + header.IPv4MinimumSize + len(h.TCPOpts) + len(payload))
|
||||
copy(buf[len(buf)-len(payload):], payload)
|
||||
@@ -340,6 +339,20 @@ func (c *Context) SendPacket(payload []byte, h *Headers) {
|
||||
// Inject packet.
|
||||
var views [1]buffer.View
|
||||
vv := buf.ToVectorisedView(views)
|
||||
|
||||
return vv
|
||||
}
|
||||
|
||||
// SendSegment sends a TCP segment that has already been built and written to a
|
||||
// buffer.VectorisedView.
|
||||
func (c *Context) SendSegment(s *buffer.VectorisedView) {
|
||||
c.linkEP.Inject(ipv4.ProtocolNumber, s)
|
||||
}
|
||||
|
||||
// SendPacket builds and sends a TCP segment(with the provided payload & TCP
|
||||
// headers) in an IPv4 packet via the link layer endpoint.
|
||||
func (c *Context) SendPacket(payload []byte, h *Headers) {
|
||||
vv := c.BuildSegment(payload, h)
|
||||
c.linkEP.Inject(ipv4.ProtocolNumber, &vv)
|
||||
}
|
||||
|
||||
|
||||
@@ -327,7 +327,10 @@ func (e *endpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions) (uintptr, *tc
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
sendUDP(route, v, e.id.LocalPort, dstPort)
|
||||
|
||||
if err := sendUDP(route, v, e.id.LocalPort, dstPort); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uintptr(len(v)), nil
|
||||
}
|
||||
|
||||
@@ -447,6 +450,9 @@ func sendUDP(r *stack.Route, data buffer.View, localPort, remotePort uint16) *tc
|
||||
udp.SetChecksum(^udp.CalculateChecksum(xsum, length))
|
||||
}
|
||||
|
||||
// Track count of packets sent.
|
||||
r.Stats().UDP.PacketsSent.Increment()
|
||||
|
||||
return r.WritePacket(&hdr, data, ProtocolNumber)
|
||||
}
|
||||
|
||||
@@ -758,15 +764,18 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv
|
||||
hdr := header.UDP(vv.First())
|
||||
if int(hdr.Length()) > vv.Size() {
|
||||
// Malformed packet.
|
||||
e.stack.Stats().UDP.MalformedPacketsReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
vv.TrimFront(header.UDPMinimumSize)
|
||||
|
||||
e.rcvMu.Lock()
|
||||
e.stack.Stats().UDP.PacketsReceived.Increment()
|
||||
|
||||
// Drop the packet if our buffer is currently full.
|
||||
if !e.rcvReady || e.rcvClosed || e.rcvBufSize >= e.rcvBufSizeMax {
|
||||
e.stack.Stats().UDP.ReceiveBufferErrors.Increment()
|
||||
e.rcvMu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -661,3 +661,41 @@ func TestV4WriteOnConnected(t *testing.T) {
|
||||
c.t.Fatalf("Bad payload: got %x, want %x", udp.Payload(), payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadIncrementsPacketsReceived(t *testing.T) {
|
||||
c := newDualTestContext(t, defaultMTU)
|
||||
defer c.cleanup()
|
||||
|
||||
// Create IPv4 UDP endpoint
|
||||
var err *tcpip.Error
|
||||
c.ep, err = c.s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &c.wq)
|
||||
if err != nil {
|
||||
c.t.Fatalf("NewEndpoint failed: %v", err)
|
||||
}
|
||||
|
||||
// Bind to wildcard.
|
||||
if err := c.ep.Bind(tcpip.FullAddress{Port: stackPort}, nil); err != nil {
|
||||
c.t.Fatalf("Bind failed: %v", err)
|
||||
}
|
||||
|
||||
testV4Read(c)
|
||||
|
||||
var want uint64 = 1
|
||||
if got := c.s.Stats().UDP.PacketsReceived.Value(); got != want {
|
||||
c.t.Fatalf("Read did not increment PacketsReceived: got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteIncrementsPacketsSent(t *testing.T) {
|
||||
c := newDualTestContext(t, defaultMTU)
|
||||
defer c.cleanup()
|
||||
|
||||
c.createV6Endpoint(false)
|
||||
|
||||
testDualWrite(c)
|
||||
|
||||
var want uint64 = 2
|
||||
if got := c.s.Stats().UDP.PacketsSent.Value(); got != want {
|
||||
c.t.Fatalf("Write did not increment PacketsSent: got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user