Skip to content

Commit

Permalink
feat: Make net_(tcp|udp) read limit configurable
Browse files Browse the repository at this point in the history
Defaults to 4GiB otherwise, as earlier.

Fixes: #364
Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
  • Loading branch information
rexagod committed May 12, 2024
1 parent 5cca38b commit 7409825
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 23 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ require (
github.com/google/go-cmp v0.6.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.19.0
k8s.io/utils v0.0.0-20240310230437-4693a0247e57
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY=
k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
22 changes: 15 additions & 7 deletions net_ip_socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@ import (
"os"
"strconv"
"strings"

"k8s.io/utils/ptr"
)

const (
// readLimit is used by io.LimitReader while reading the content of the
var (
// defaultReadLimitPtr is used by io.LimitReader while reading the content of the
// /proc/net/udp{,6} files. The number of lines inside such a file is dynamic
// as each line represents a single used socket.
// In theory, the number of available sockets is 65535 (2^16 - 1) per IP.
// With e.g. 150 Byte per line and the maximum number of 65535,
// the reader needs to handle 150 Byte * 65535 =~ 10 MB for a single IP.
readLimit = 4294967296 // Byte -> 4 GiB
defaultReadLimit = ptr.To(4294967296) // Byte -> 4 GiB
)

// This contains generic data structures for both udp and tcp sockets.
Expand Down Expand Up @@ -73,7 +75,7 @@ type (
}
)

func newNetIPSocket(file string) (NetIPSocket, error) {
func newNetIPSocket(file string, readLimit *int) (NetIPSocket, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
Expand All @@ -83,7 +85,10 @@ func newNetIPSocket(file string) (NetIPSocket, error) {
var netIPSocket NetIPSocket
isUDP := strings.Contains(file, "udp")

lr := io.LimitReader(f, readLimit)
if readLimit == nil {
readLimit = defaultReadLimit
}
lr := io.LimitReader(f, int64(*readLimit))
s := bufio.NewScanner(lr)
s.Scan() // skip first line with headers
for s.Scan() {
Expand All @@ -101,7 +106,7 @@ func newNetIPSocket(file string) (NetIPSocket, error) {
}

// newNetIPSocketSummary creates a new NetIPSocket{,6} from the contents of the given file.
func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) {
func newNetIPSocketSummary(file string, readLimit *int) (*NetIPSocketSummary, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
Expand All @@ -112,7 +117,10 @@ func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) {
var udpPacketDrops uint64
isUDP := strings.Contains(file, "udp")

lr := io.LimitReader(f, readLimit)
if readLimit == nil {
readLimit = defaultReadLimit
}
lr := io.LimitReader(f, int64(*readLimit))
s := bufio.NewScanner(lr)
s.Scan() // skip first line with headers
for s.Scan() {
Expand Down
24 changes: 12 additions & 12 deletions net_tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,37 @@ type (

// NetTCP returns the IPv4 kernel/networking statistics for TCP datagrams
// read from /proc/net/tcp.
func (fs FS) NetTCP() (NetTCP, error) {
return newNetTCP(fs.proc.Path("net/tcp"))
func (fs FS) NetTCP(readLimit *int) (NetTCP, error) {
return newNetTCP(fs.proc.Path("net/tcp"), readLimit)
}

// NetTCP6 returns the IPv6 kernel/networking statistics for TCP datagrams
// read from /proc/net/tcp6.
func (fs FS) NetTCP6() (NetTCP, error) {
return newNetTCP(fs.proc.Path("net/tcp6"))
func (fs FS) NetTCP6(readLimit *int) (NetTCP, error) {
return newNetTCP(fs.proc.Path("net/tcp6"), readLimit)
}

// NetTCPSummary returns already computed statistics like the total queue lengths
// for TCP datagrams read from /proc/net/tcp.
func (fs FS) NetTCPSummary() (*NetTCPSummary, error) {
return newNetTCPSummary(fs.proc.Path("net/tcp"))
func (fs FS) NetTCPSummary(readLimit *int) (*NetTCPSummary, error) {
return newNetTCPSummary(fs.proc.Path("net/tcp"), readLimit)
}

// NetTCP6Summary returns already computed statistics like the total queue lengths
// for TCP datagrams read from /proc/net/tcp6.
func (fs FS) NetTCP6Summary() (*NetTCPSummary, error) {
return newNetTCPSummary(fs.proc.Path("net/tcp6"))
func (fs FS) NetTCP6Summary(readLimit *int) (*NetTCPSummary, error) {
return newNetTCPSummary(fs.proc.Path("net/tcp6"), readLimit)
}

// newNetTCP creates a new NetTCP{,6} from the contents of the given file.
func newNetTCP(file string) (NetTCP, error) {
n, err := newNetIPSocket(file)
func newNetTCP(file string, readLimit *int) (NetTCP, error) {
n, err := newNetIPSocket(file, readLimit)
n1 := NetTCP(n)
return n1, err
}

func newNetTCPSummary(file string) (*NetTCPSummary, error) {
n, err := newNetIPSocketSummary(file)
func newNetTCPSummary(file string, readLimit *int) (*NetTCPSummary, error) {
n, err := newNetIPSocketSummary(file, readLimit)
if n == nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions net_tcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func Test_newNetTCP(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := newNetTCP(tt.file)
got, err := newNetTCP(tt.file, nil)
if (err != nil) != tt.wantErr {
t.Errorf("newNetTCP() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down Expand Up @@ -161,7 +161,7 @@ func Test_newNetTCPSummary(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := newNetTCPSummary(tt.file)
got, err := newNetTCPSummary(tt.file, nil)
if (err != nil) != tt.wantErr {
t.Errorf("newNetTCPSummary() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
4 changes: 2 additions & 2 deletions net_udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ func (fs FS) NetUDP6Summary() (*NetUDPSummary, error) {

// newNetUDP creates a new NetUDP{,6} from the contents of the given file.
func newNetUDP(file string) (NetUDP, error) {
n, err := newNetIPSocket(file)
n, err := newNetIPSocket(file, nil)
n1 := NetUDP(n)
return n1, err
}

func newNetUDPSummary(file string) (*NetUDPSummary, error) {
n, err := newNetIPSocketSummary(file)
n, err := newNetIPSocketSummary(file, nil)
if n == nil {
return nil, err
}
Expand Down

0 comments on commit 7409825

Please sign in to comment.