From a4cc1de1cca60bd5090ad46b386bc9746a9ab220 Mon Sep 17 00:00:00 2001
From: Konstantin Kuklin <konstantin.kuklin@gmail.com>
Date: Fri, 18 Oct 2024 00:34:20 +0300
Subject: [PATCH 1/2] add netfilter queue support

Signed-off-by: Konstantin Kuklin <konstantin.kuklin@gmail.com>
---
 nfnetlink_queue.go      | 85 +++++++++++++++++++++++++++++++++++++++++
 nfnetlink_queue_test.go | 75 ++++++++++++++++++++++++++++++++++++
 2 files changed, 160 insertions(+)
 create mode 100644 nfnetlink_queue.go
 create mode 100644 nfnetlink_queue_test.go

diff --git a/nfnetlink_queue.go b/nfnetlink_queue.go
new file mode 100644
index 00000000..da23e6e8
--- /dev/null
+++ b/nfnetlink_queue.go
@@ -0,0 +1,85 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+
+	"github.com/prometheus/procfs/internal/util"
+)
+
+const nfNetLinkQueueFormat = "%d %d %d %d %d %d %d %d %d"
+
+// NFNetLinkQueue contains general information about netfilter queues found in /proc/net/netfilter/nfnetlink_queue.
+type NFNetLinkQueue struct {
+	// id of the queue
+	QueueID uint
+	// pid of process handling the queue
+	PeerPID uint
+	// number of packets waiting for a decision
+	QueueTotal uint
+	// indicate how userspace receive packets
+	CopyMode uint
+	// size of copy
+	CopyRange uint
+	// number of items dropped by the kernel because too many packets were waiting a decision.
+	// It queue_total is superior to queue_max_len (1024 per default) the packets are dropped.
+	QueueDropped uint
+	// number of packets dropped by userspace (due to kernel send failure on the netlink socket)
+	QueueUserDropped uint
+	// sequence number of packets queued. It gives a correct approximation of the number of queued packets.
+	SequenceID uint
+	// internal value (number of entity using the queue)
+	Use uint
+}
+
+// NFNetLinkQueue returns information about current state of netfilter queues.
+func (fs FS) NFNetLinkQueue() ([]NFNetLinkQueue, error) {
+	data, err := util.ReadFileNoStat(fs.proc.Path("net/netfilter/nfnetlink_queue"))
+	if err != nil {
+		return nil, err
+	}
+
+	queue := []NFNetLinkQueue{}
+	if len(data) == 0 {
+		return queue, nil
+	}
+
+	scanner := bufio.NewScanner(bytes.NewReader(data))
+	for scanner.Scan() {
+		line := scanner.Text()
+		nFNetLinkQueue, err := parseNFNetLinkQueueLine(line)
+		if err != nil {
+			return nil, err
+		}
+		queue = append(queue, *nFNetLinkQueue)
+	}
+	return queue, nil
+}
+
+// parseNFNetLinkQueueLine parses each line of the /proc/net/netfilter/nfnetlink_queue file.
+func parseNFNetLinkQueueLine(line string) (*NFNetLinkQueue, error) {
+	nFNetLinkQueue := NFNetLinkQueue{}
+	_, err := fmt.Sscanf(
+		line, nfNetLinkQueueFormat,
+		&nFNetLinkQueue.QueueID, &nFNetLinkQueue.PeerPID, &nFNetLinkQueue.QueueTotal, &nFNetLinkQueue.CopyMode,
+		&nFNetLinkQueue.CopyRange, &nFNetLinkQueue.QueueDropped, &nFNetLinkQueue.QueueUserDropped, &nFNetLinkQueue.SequenceID, &nFNetLinkQueue.Use,
+	)
+	if err != nil {
+		return nil, err
+	}
+	return &nFNetLinkQueue, nil
+}
diff --git a/nfnetlink_queue_test.go b/nfnetlink_queue_test.go
new file mode 100644
index 00000000..c5ef81f4
--- /dev/null
+++ b/nfnetlink_queue_test.go
@@ -0,0 +1,75 @@
+// Copyright 2020 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestParseNFNetLinkQueueLine(t *testing.T) {
+	tests := []struct {
+		name           string
+		s              string
+		shouldErr      bool
+		nfNetLinkQueue *NFNetLinkQueue
+	}{
+		{
+			name:      "nf_net_link_queue simple line",
+			s:         "  230  44306     1 2 65531     3     4        5  6",
+			shouldErr: false,
+			nfNetLinkQueue: &NFNetLinkQueue{
+				QueueID:          230,
+				PeerPID:          44306,
+				QueueTotal:       1,
+				CopyMode:         2,
+				CopyRange:        65531,
+				QueueDropped:     3,
+				QueueUserDropped: 4,
+				SequenceID:       5,
+				Use:              6,
+			},
+		},
+		{
+			name:           "empty line",
+			s:              "",
+			shouldErr:      true,
+			nfNetLinkQueue: nil,
+		},
+		{
+			name:           "incorrect parameters count in line",
+			s:              " 1 2 3 4 55555 ",
+			shouldErr:      true,
+			nfNetLinkQueue: nil,
+		},
+	}
+
+	for i, test := range tests {
+		t.Logf("[%02d] test %q", i, test.name)
+
+		nfNetLinkQueue, err := parseNFNetLinkQueueLine(test.s)
+
+		if test.shouldErr && err == nil {
+			t.Errorf("%s: expected an error, but none occurred", test.name)
+		}
+		if !test.shouldErr && err != nil {
+			t.Errorf("%s: unexpected error: %v", test.name, err)
+		}
+
+		if want, have := test.nfNetLinkQueue, nfNetLinkQueue; !reflect.DeepEqual(want, have) {
+			t.Errorf("nfNetLinkQueue:\nwant:\n%+v\nhave:\n%+v", want, have)
+		}
+	}
+
+}

From 3dbfe37d0324e4a452dcfab055c6a3df2285206e Mon Sep 17 00:00:00 2001
From: Konstantin Kuklin <konstantin.kuklin@gmail.com>
Date: Thu, 19 Dec 2024 23:22:21 +0300
Subject: [PATCH 2/2] fixed copyright year

Signed-off-by: Konstantin Kuklin <konstantin.kuklin@gmail.com>
---
 nfnetlink_queue.go      | 2 +-
 nfnetlink_queue_test.go | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/nfnetlink_queue.go b/nfnetlink_queue.go
index da23e6e8..7adf17bf 100644
--- a/nfnetlink_queue.go
+++ b/nfnetlink_queue.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright 2024 The Prometheus Authors
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
diff --git a/nfnetlink_queue_test.go b/nfnetlink_queue_test.go
index c5ef81f4..baf8a10e 100644
--- a/nfnetlink_queue_test.go
+++ b/nfnetlink_queue_test.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright 2024 The Prometheus Authors
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
@@ -71,5 +71,4 @@ func TestParseNFNetLinkQueueLine(t *testing.T) {
 			t.Errorf("nfNetLinkQueue:\nwant:\n%+v\nhave:\n%+v", want, have)
 		}
 	}
-
 }