mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
epsocket: support /proc/net/snmp
Netstack has its own stats, we use this to fill /proc/net/snmp. Note that some metrics are not recorded in Netstack, which will be shown as 0 in the proc file. Signed-off-by: Jianfeng Tan <henry.tjf@antfin.com> Change-Id: Ie0089184507d16f49bc0057b4b0482094417ebe1
This commit is contained in:
@@ -144,7 +144,98 @@ func (s *Stack) SetTCPSACKEnabled(enabled bool) error {
|
||||
|
||||
// Statistics implements inet.Stack.Statistics.
|
||||
func (s *Stack) Statistics(stat interface{}, arg string) error {
|
||||
return syserr.ErrEndpointOperation.ToError()
|
||||
switch stats := stat.(type) {
|
||||
case *inet.StatSNMPIP:
|
||||
ip := Metrics.IP
|
||||
*stats = inet.StatSNMPIP{
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/Forwarding.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/DefaultTTL.
|
||||
ip.PacketsReceived.Value(), // InReceives.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/InHdrErrors.
|
||||
ip.InvalidAddressesReceived.Value(), // InAddrErrors.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/ForwDatagrams.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/InUnknownProtos.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/InDiscards.
|
||||
ip.PacketsDelivered.Value(), // InDelivers.
|
||||
ip.PacketsSent.Value(), // OutRequests.
|
||||
ip.OutgoingPacketErrors.Value(), // OutDiscards.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/OutNoRoutes.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/ReasmTimeout.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/ReasmReqds.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/ReasmOKs.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/ReasmFails.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/FragOKs.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/FragFails.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Ip/FragCreates.
|
||||
}
|
||||
case *inet.StatSNMPICMP:
|
||||
in := Metrics.ICMP.V4PacketsReceived.ICMPv4PacketStats
|
||||
out := Metrics.ICMP.V4PacketsSent.ICMPv4PacketStats
|
||||
*stats = inet.StatSNMPICMP{
|
||||
0, // TODO(gvisor.dev/issue/969): Support Icmp/InMsgs.
|
||||
Metrics.ICMP.V4PacketsSent.Dropped.Value(), // InErrors.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Icmp/InCsumErrors.
|
||||
in.DstUnreachable.Value(), // InDestUnreachs.
|
||||
in.TimeExceeded.Value(), // InTimeExcds.
|
||||
in.ParamProblem.Value(), // InParmProbs.
|
||||
in.SrcQuench.Value(), // InSrcQuenchs.
|
||||
in.Redirect.Value(), // InRedirects.
|
||||
in.Echo.Value(), // InEchos.
|
||||
in.EchoReply.Value(), // InEchoReps.
|
||||
in.Timestamp.Value(), // InTimestamps.
|
||||
in.TimestampReply.Value(), // InTimestampReps.
|
||||
in.InfoRequest.Value(), // InAddrMasks.
|
||||
in.InfoReply.Value(), // InAddrMaskReps.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Icmp/OutMsgs.
|
||||
Metrics.ICMP.V4PacketsReceived.Invalid.Value(), // OutErrors.
|
||||
out.DstUnreachable.Value(), // OutDestUnreachs.
|
||||
out.TimeExceeded.Value(), // OutTimeExcds.
|
||||
out.ParamProblem.Value(), // OutParmProbs.
|
||||
out.SrcQuench.Value(), // OutSrcQuenchs.
|
||||
out.Redirect.Value(), // OutRedirects.
|
||||
out.Echo.Value(), // OutEchos.
|
||||
out.EchoReply.Value(), // OutEchoReps.
|
||||
out.Timestamp.Value(), // OutTimestamps.
|
||||
out.TimestampReply.Value(), // OutTimestampReps.
|
||||
out.InfoRequest.Value(), // OutAddrMasks.
|
||||
out.InfoReply.Value(), // OutAddrMaskReps.
|
||||
}
|
||||
case *inet.StatSNMPTCP:
|
||||
tcp := Metrics.TCP
|
||||
// RFC 2012 (updates 1213): SNMPv2-MIB-TCP.
|
||||
*stats = inet.StatSNMPTCP{
|
||||
1, // RtoAlgorithm.
|
||||
200, // RtoMin.
|
||||
120000, // RtoMax.
|
||||
(1<<64 - 1), // MaxConn.
|
||||
tcp.ActiveConnectionOpenings.Value(), // ActiveOpens.
|
||||
tcp.PassiveConnectionOpenings.Value(), // PassiveOpens.
|
||||
tcp.FailedConnectionAttempts.Value(), // AttemptFails.
|
||||
tcp.EstablishedResets.Value(), // EstabResets.
|
||||
tcp.CurrentEstablished.Value(), // CurrEstab.
|
||||
tcp.ValidSegmentsReceived.Value(), // InSegs.
|
||||
tcp.SegmentsSent.Value(), // OutSegs.
|
||||
tcp.Retransmits.Value(), // RetransSegs.
|
||||
tcp.InvalidSegmentsReceived.Value(), // InErrs.
|
||||
tcp.ResetsSent.Value(), // OutRsts.
|
||||
tcp.ChecksumErrors.Value(), // InCsumErrors.
|
||||
}
|
||||
case *inet.StatSNMPUDP:
|
||||
udp := Metrics.UDP
|
||||
*stats = inet.StatSNMPUDP{
|
||||
udp.PacketsReceived.Value(), // InDatagrams.
|
||||
udp.UnknownPortErrors.Value(), // NoPorts.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Udp/InErrors.
|
||||
udp.PacketsSent.Value(), // OutDatagrams.
|
||||
udp.ReceiveBufferErrors.Value(), // RcvbufErrors.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Udp/SndbufErrors.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Udp/InCsumErrors.
|
||||
0, // TODO(gvisor.dev/issue/969): Support Udp/IgnoredMulti.
|
||||
}
|
||||
default:
|
||||
return syserr.ErrEndpointOperation.ToError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RouteTable implements inet.Stack.RouteTable.
|
||||
|
||||
@@ -297,10 +297,8 @@ func (l *listenContext) createEndpointAndPerformHandshake(s *segment, opts *head
|
||||
return nil, err
|
||||
}
|
||||
ep.mu.Lock()
|
||||
if ep.state != StateEstablished {
|
||||
ep.stack.Stats().TCP.CurrentEstablished.Increment()
|
||||
ep.state = StateEstablished
|
||||
}
|
||||
ep.stack.Stats().TCP.CurrentEstablished.Increment()
|
||||
ep.state = StateEstablished
|
||||
ep.mu.Unlock()
|
||||
|
||||
// Update the receive window scaling. We can't do it before the
|
||||
|
||||
@@ -928,10 +928,8 @@ func (e *endpoint) protocolMainLoop(handshake bool) *tcpip.Error {
|
||||
e.lastErrorMu.Unlock()
|
||||
|
||||
e.mu.Lock()
|
||||
if e.state == StateEstablished || e.state == StateCloseWait {
|
||||
e.stack.Stats().TCP.EstablishedResets.Increment()
|
||||
e.stack.Stats().TCP.CurrentEstablished.Decrement()
|
||||
}
|
||||
e.stack.Stats().TCP.EstablishedResets.Increment()
|
||||
e.stack.Stats().TCP.CurrentEstablished.Decrement()
|
||||
e.state = StateError
|
||||
e.HardError = err
|
||||
|
||||
@@ -1126,10 +1124,8 @@ func (e *endpoint) protocolMainLoop(handshake bool) *tcpip.Error {
|
||||
// Mark endpoint as closed.
|
||||
e.mu.Lock()
|
||||
if e.state != StateError {
|
||||
if e.state == StateEstablished || e.state == StateCloseWait {
|
||||
e.stack.Stats().TCP.EstablishedResets.Increment()
|
||||
e.stack.Stats().TCP.CurrentEstablished.Decrement()
|
||||
}
|
||||
e.stack.Stats().TCP.EstablishedResets.Increment()
|
||||
e.stack.Stats().TCP.CurrentEstablished.Decrement()
|
||||
e.state = StateClose
|
||||
}
|
||||
// Lock released below.
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/syscalls/linux/socket_test_util.h"
|
||||
@@ -184,11 +187,31 @@ TEST(ProcNetSnmp, TcpEstab) {
|
||||
EXPECT_EQ(oldPassiveOpens, newPassiveOpens - 1);
|
||||
EXPECT_EQ(oldCurrEstab, newCurrEstab - 2);
|
||||
|
||||
// Send 1 byte from client to server.
|
||||
ASSERT_THAT(send(s_connect.get(), "a", 1, 0), SyscallSucceedsWithValue(1));
|
||||
|
||||
constexpr int kPollTimeoutMs = 20000; // Wait up to 20 seconds for the data.
|
||||
|
||||
// Wait until server-side fd sees the data on its side but don't read it.
|
||||
struct pollfd poll_fd = {s_accept.get(), POLLIN, 0};
|
||||
ASSERT_THAT(RetryEINTR(poll)(&poll_fd, 1, kPollTimeoutMs),
|
||||
SyscallSucceedsWithValue(1));
|
||||
|
||||
// Now close server-side fd without reading the data which leads to a RST
|
||||
// packet sent to client side.
|
||||
s_accept.reset(-1);
|
||||
|
||||
// Wait until client-side fd sees RST packet.
|
||||
struct pollfd poll_fd1 = {s_connect.get(), POLLIN, 0};
|
||||
ASSERT_THAT(RetryEINTR(poll)(&poll_fd1, 1, kPollTimeoutMs),
|
||||
SyscallSucceedsWithValue(1));
|
||||
|
||||
// Now close client-side fd.
|
||||
s_connect.reset(-1);
|
||||
|
||||
// Wait until the process of the netstack.
|
||||
absl::SleepFor(absl::Seconds(1.0));
|
||||
|
||||
snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp"));
|
||||
newCurrEstab = ASSERT_NO_ERRNO_AND_VALUE(GetSNMPMetricFromProc(snmp, "Tcp", "CurrEstab"));
|
||||
newEstabResets = ASSERT_NO_ERRNO_AND_VALUE(GetSNMPMetricFromProc(snmp, "Tcp", "EstabResets"));
|
||||
|
||||
Reference in New Issue
Block a user