Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add udp drops #538

Merged
merged 5 commits into from Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 23 additions & 3 deletions net_ip_socket.go
Expand Up @@ -50,10 +50,13 @@ type (
// UsedSockets shows the total number of parsed lines representing the
// number of used sockets.
UsedSockets uint64
// Drops shows the total number of dropped packets of all UPD sockets.
Drops *uint64
}

// netIPSocketLine represents the fields parsed from a single line
// in /proc/net/{t,u}dp{,6}. Fields which are not used by IPSocket are skipped.
// Drops is non-nil for udp{,6}, but nil for tcp{,6}.
// For the proc file format details, see https://linux.die.net/man/5/proc.
netIPSocketLine struct {
Sl uint64
Expand All @@ -66,6 +69,7 @@ type (
RxQueue uint64
UID uint64
Inode uint64
Drops *uint64
}
)

Expand All @@ -77,13 +81,14 @@ func newNetIPSocket(file string) (NetIPSocket, error) {
defer f.Close()

var netIPSocket NetIPSocket
isUDP := strings.Contains(file, "udp")

lr := io.LimitReader(f, readLimit)
s := bufio.NewScanner(lr)
s.Scan() // skip first line with headers
for s.Scan() {
fields := strings.Fields(s.Text())
line, err := parseNetIPSocketLine(fields)
line, err := parseNetIPSocketLine(fields, isUDP)
if err != nil {
return nil, err
}
Expand All @@ -104,19 +109,25 @@ func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) {
defer f.Close()

var netIPSocketSummary NetIPSocketSummary
var udpPacketDrops uint64
isUDP := strings.Contains(file, "udp")

lr := io.LimitReader(f, readLimit)
s := bufio.NewScanner(lr)
s.Scan() // skip first line with headers
for s.Scan() {
fields := strings.Fields(s.Text())
line, err := parseNetIPSocketLine(fields)
line, err := parseNetIPSocketLine(fields, isUDP)
if err != nil {
return nil, err
}
netIPSocketSummary.TxQueueLength += line.TxQueue
netIPSocketSummary.RxQueueLength += line.RxQueue
netIPSocketSummary.UsedSockets++
if isUDP {
udpPacketDrops += *line.Drops
netIPSocketSummary.Drops = &udpPacketDrops
}
}
if err := s.Err(); err != nil {
return nil, err
Expand Down Expand Up @@ -149,7 +160,7 @@ func parseIP(hexIP string) (net.IP, error) {
}

// parseNetIPSocketLine parses a single line, represented by a list of fields.
func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) {
line := &netIPSocketLine{}
if len(fields) < 10 {
return nil, fmt.Errorf(
Expand Down Expand Up @@ -224,5 +235,14 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
return nil, fmt.Errorf("%s: Cannot parse inode value in %q: %w", ErrFileParse, line.Inode, err)
}

// drops
if isUDP {
drops, err := strconv.ParseUint(fields[12], 0, 64)
discordianfish marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("%s: Cannot parse drops value in %q: %w", ErrFileParse, drops, err)
}
line.Drops = &drops
}

return line, nil
}
10 changes: 9 additions & 1 deletion net_ip_socket_test.go
Expand Up @@ -25,6 +25,7 @@ func Test_parseNetIPSocketLine(t *testing.T) {
name string
want *netIPSocketLine
wantErr bool
isUDP bool
}{
{
name: "reading valid lines, no issue should happened",
Expand Down Expand Up @@ -96,10 +97,17 @@ func Test_parseNetIPSocketLine(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "error case - parse Drops - not a valid uint",
fields: []string{"1:", "00000000:0000", "00000000:0000", "07", "00000000:00000001", "0:0", "0", "10", "0", "39309", "2", "000000009bd60d72", "-5"},
want: nil,
wantErr: true,
isUDP: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseNetIPSocketLine(tt.fields)
got, err := parseNetIPSocketLine(tt.fields, tt.isUDP)
if (err != nil) != tt.wantErr {
t.Errorf("parseNetIPSocketLine() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
15 changes: 13 additions & 2 deletions net_udp_test.go
Expand Up @@ -41,6 +41,7 @@ func Test_newNetUDP(t *testing.T) {
RxQueue: 1,
UID: 0,
Inode: 2740,
Drops: intToU64(100),
},
&netIPSocketLine{
Sl: 1,
Expand All @@ -53,6 +54,7 @@ func Test_newNetUDP(t *testing.T) {
RxQueue: 0,
UID: 0,
Inode: 2740,
Drops: intToU64(100),
},
&netIPSocketLine{
Sl: 2,
Expand All @@ -65,6 +67,7 @@ func Test_newNetUDP(t *testing.T) {
RxQueue: 1,
UID: 0,
Inode: 2740,
Drops: intToU64(100),
},
},
wantErr: false,
Expand All @@ -84,6 +87,7 @@ func Test_newNetUDP(t *testing.T) {
RxQueue: 0,
UID: 981,
Inode: 21040,
Drops: intToU64(0),
},
&netIPSocketLine{
Sl: 6073,
Expand All @@ -96,6 +100,7 @@ func Test_newNetUDP(t *testing.T) {
RxQueue: 0,
UID: 1000,
Inode: 11337031,
Drops: intToU64(0),
},
},
wantErr: false,
Expand Down Expand Up @@ -137,13 +142,13 @@ func Test_newNetUDPSummary(t *testing.T) {
{
name: "udp file found, no error should come up",
file: "testdata/fixtures/proc/net/udp",
want: &NetUDPSummary{TxQueueLength: 2, RxQueueLength: 2, UsedSockets: 3},
want: &NetUDPSummary{TxQueueLength: 2, RxQueueLength: 2, UsedSockets: 3, Drops: intToU64(300)},
wantErr: false,
},
{
name: "udp6 file found, no error should come up",
file: "testdata/fixtures/proc/net/udp6",
want: &NetUDPSummary{TxQueueLength: 0, RxQueueLength: 0, UsedSockets: 2},
want: &NetUDPSummary{TxQueueLength: 0, RxQueueLength: 0, UsedSockets: 2, Drops: intToU64(0)},
wantErr: false,
},
{
Expand Down Expand Up @@ -172,3 +177,9 @@ func Test_newNetUDPSummary(t *testing.T) {
})
}
}

// intToU64 convert int to uint64 and return it pointer.
func intToU64(i int) *uint64 {
cast := uint64(i)
return &cast
}