1
0
Fork 0

Adding upstream version 1.34.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 07:26:29 +02:00
parent e393c3af3f
commit 4978089aab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
4963 changed files with 677545 additions and 0 deletions

View file

@ -0,0 +1,62 @@
# Netgear Switch Discovery Protocol Input Plugin
This plugin gathers metrics from devices via the
[Netgear Switch Discovery Protocol][nsdp] for all available switches and ports.
⭐ Telegraf v1.34.0
🏷️ network
💻 all
[nsdp]: https://en.wikipedia.org/wiki/Netgear_Switch_Discovery_Protocol
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
In addition to the plugin-specific configuration settings, plugins support
additional global and plugin configuration settings. These settings are used to
modify metrics, tags, and field or create aliases and configure ordering, etc.
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
## Configuration
```toml @sample.conf
# Gather Netgear Switch Discovery Protocol status
[[inputs.nsdp]]
## The target address to use for status gathering. Either Broadcast (default)
## or the address of a single well-known device.
# address = "255.255.255.255:63322"
## The maximum number of device responses to wait for. 0 means no limit.
## NSDP works asynchronously. Without a limit (0) the plugin always waits
## the amount given in timeout for possible responses. By setting this
## option to the known number of devices, the plugin completes
## processing as soon as the last device has answered.
# device_limit = 0
## The maximum duration to wait for device responses.
# timeout = "2s"
```
## Metrics
- `nsdp_device_port`
- tags
- `device` - The device identifier (MAC/HW address)
- `device_ip` - The device's IP address
- `device_name` - The device's name
- `device_model` - The device's model
- `device_port` - The port id the fields are referring to
- fields
- `bytes_sent` (uint) - Number of bytes sent via this port
- `bytes_recv` (uint) - Number of bytes received via this port
- `packets_total` (uint) - Total number of packets processed on this port
- `broadcasts_total` (uint) - Total number of broadcasts processed on this port
- `multicasts_total` (uint) - Total number of multicasts processed on this port
- `errors_total` (uint) - Total number of errors encountered on this port
## Example Output
```text
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=1 broadcasts_total=0u,bytes_recv=3879427866u,bytes_sent=506548796u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014578000
```

134
plugins/inputs/nsdp/nsdp.go Normal file
View file

@ -0,0 +1,134 @@
//go:generate ../../../tools/readme_config_includer/generator
package nsdp
import (
_ "embed"
"errors"
"fmt"
"net"
"strconv"
"time"
"github.com/tdrn-org/go-nsdp"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/inputs"
)
//go:embed sample.conf
var sampleConfig string
type NSDP struct {
Address string `toml:"address"`
DeviceLimit uint `toml:"device_limit"`
Timeout config.Duration `toml:"timeout"`
Log telegraf.Logger `toml:"-"`
conn *nsdp.Conn
}
func (*NSDP) SampleConfig() string {
return sampleConfig
}
func (n *NSDP) Init() error {
if n.Address == "" {
n.Address = nsdp.IPv4BroadcastTarget
}
if n.Timeout <= 0 {
return errors.New("timeout must be greater than zero")
}
return nil
}
func (n *NSDP) Start(telegraf.Accumulator) error {
conn, err := nsdp.NewConn(n.Address, n.Log.Level().Includes(telegraf.Trace))
if err != nil {
return fmt.Errorf("failed to create connection to address %s: %w", n.Address, err)
}
conn.ReceiveDeviceLimit = n.DeviceLimit
conn.ReceiveTimeout = time.Duration(n.Timeout)
n.conn = conn
return nil
}
func (n *NSDP) Stop() {
if n.conn == nil {
return
}
n.conn.Close()
n.conn = nil
}
func (n *NSDP) Gather(acc telegraf.Accumulator) error {
if n.conn == nil {
if err := n.Start(nil); err != nil {
return err
}
}
// Send request to query devices including infos (model, name, IP) and status (port statistics)
request := nsdp.NewMessage(nsdp.ReadRequest)
request.AppendTLV(nsdp.EmptyDeviceModel())
request.AppendTLV(nsdp.EmptyDeviceName())
request.AppendTLV(nsdp.EmptyDeviceIP())
request.AppendTLV(nsdp.EmptyPortStatistic())
responses, err := n.conn.SendReceiveMessage(request)
if err != nil {
// Close malfunctioning connection and re-connect on next Gather call
n.Stop()
return fmt.Errorf("failed to query address %s: %w", n.Address, err)
}
// Create metrics for each responding device
for device, response := range responses {
n.Log.Tracef("Processing device: %s", device)
gatherDevice(acc, device, response)
}
return nil
}
func gatherDevice(acc telegraf.Accumulator, device string, response *nsdp.Message) {
var deviceModel string
var deviceName string
var deviceIP net.IP
portStats := make(map[uint8]*nsdp.PortStatistic, 0)
for _, tlv := range response.Body {
switch tlv.Type() {
case nsdp.TypeDeviceModel:
deviceModel = tlv.(*nsdp.DeviceModel).Model
case nsdp.TypeDeviceName:
deviceName = tlv.(*nsdp.DeviceName).Name
case nsdp.TypeDeviceIP:
deviceIP = tlv.(*nsdp.DeviceIP).IP
case nsdp.TypePortStatistic:
portStat := tlv.(*nsdp.PortStatistic)
portStats[portStat.Port] = portStat
}
}
for port, stat := range portStats {
tags := map[string]string{
"device": device,
"device_ip": deviceIP.String(),
"device_name": deviceName,
"device_model": deviceModel,
"device_port": strconv.FormatUint(uint64(port), 10),
}
fields := map[string]interface{}{
"bytes_sent": stat.Sent,
"bytes_recv": stat.Received,
"packets_total": stat.Packets,
"broadcasts_total": stat.Broadcasts,
"multicasts_total": stat.Multicasts,
"errors_total": stat.Errors,
}
acc.AddCounter("nsdp_device_port", fields, tags)
}
}
func init() {
inputs.Add("nsdp", func() telegraf.Input {
return &NSDP{Timeout: config.Duration(2 * time.Second)}
})
}

View file

@ -0,0 +1,112 @@
package nsdp
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/tdrn-org/go-nsdp"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/parsers/influx"
"github.com/influxdata/telegraf/testutil"
)
func TestLoadConfig(t *testing.T) {
// Verify plugin can be loaded from config
conf := config.NewConfig()
require.NoError(t, conf.LoadConfig("testdata/conf/nsdp.conf"))
require.Len(t, conf.Inputs, 1)
plugin, ok := conf.Inputs[0].Input.(*NSDP)
require.True(t, ok)
// Verify successful Init
require.NoError(t, plugin.Init())
// Verify everything is setup according to config file
require.Equal(t, "127.0.0.1:63322", plugin.Address)
require.Equal(t, uint(1), plugin.DeviceLimit)
require.Equal(t, config.Duration(5*time.Second), plugin.Timeout)
}
func TestInvalidTimeoutConfig(t *testing.T) {
plugin := &NSDP{
Timeout: config.Duration(0 * time.Second),
}
// Verify failing Init
require.EqualError(t, plugin.Init(), "timeout must be greater than zero")
}
func TestGather(t *testing.T) {
// Setup and start test responder
responder, err := nsdp.NewTestResponder("localhost:0")
require.NoError(t, err)
defer responder.Stop() //nolint:errcheck // ignore error
responder.AddResponses(
"0102000000000000bcd07432b8dc123456789abc000037b94e53445000000000"+
"0001000847533130384576330003000773776974636832000600040a01000410"+
"0000310100000000e73b5f1a000000001e31523c000000000000000000000000"+
"0000000000000000000000000000000000000000100000310200000000152d5e"+
"ae0000000052ea11ea0000000000000000000000000000000000000000000000"+
"000000000000000000100000310300000000068561aa00000000bcc8cb350000"+
"0000000000000000000000000000000000000000000000000000000000001000"+
"0031040000000002d5fe00000000002b37dad900000000000000000000000000"+
"0000000000000000000000000000000000000010000031050000000000000000"+
"0000000000000000000000000000000000000000000000000000000000000000"+
"0000000000000000100000310600000000000000000000000000000000000000"+
"0000000000000000000000000000000000000000000000000000000000100000"+
"3107000000000000000000000000000000000000000000000000000000000000"+
"0000000000000000000000000000000000001000003108000000000000000000"+
"0000000000000000000000000000000000000000000000000000000000000000"+
"00000000000000ffff0000",
"0102000000000000bcd07432b8dccba987654321000037b94e53445000000000"+
"0001000847533130384576330003000773776974636831000600040a01000310"+
"00003101000000059a9d833200000000303e8eb5000000000000000000000000"+
"0000000000000000000000000000000000000000100000310200000000000000"+
"0000000000000000000000000000000000000000000000000000000000000000"+
"0000000000000000001000003103000000000d9a35e4000000026523c6660000"+
"0000000000000000000000000000000000000000000000000000000000001000"+
"003104000000000041c7530000000002cd94ba00000000000000000000000000"+
"0000000000000000000000000000000000000010000031050000000021b9ca41"+
"000000031a9bff61000000000000000000000000000000000000000000000000"+
"0000000000000000100000310600000000000000000000000000000000000000"+
"0000000000000000000000000000000000000000000000000000000000100000"+
"3107000000000000000000000000000000000000000000000000000000000000"+
"0000000000000000000000000000000000001000003108000000000000000000"+
"0000000000000000000000000000000000000000000000000000000000000000"+
"00000000000000ffff0000",
)
require.NoError(t, responder.Start())
// Setup the plugin to target the test responder
plugin := &NSDP{
Address: responder.Target(),
DeviceLimit: 2,
Timeout: config.Duration(2 * time.Second),
Log: testutil.Logger{Name: "nsdp"},
}
// Verify successful Init
require.NoError(t, plugin.Init())
// Verify successfull Gather
var acc testutil.Accumulator
require.NoError(t, acc.GatherError(plugin.Gather))
// Verify collected metrics are as expected
expectedMetrics := loadExpectedMetrics(t, "testdata/metrics/nsdp_device_port.txt", telegraf.Counter)
testutil.RequireMetricsEqual(t, expectedMetrics, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())
}
func loadExpectedMetrics(t *testing.T, file string, vt telegraf.ValueType) []telegraf.Metric {
parser := &influx.Parser{}
require.NoError(t, parser.Init())
expectedMetrics, err := testutil.ParseMetricsFromFile(file, parser)
require.NoError(t, err)
for index := range expectedMetrics {
expectedMetrics[index].SetType(vt)
}
return expectedMetrics
}

View file

@ -0,0 +1,15 @@
# Gather Netgear Switch Discovery Protocol status
[[inputs.nsdp]]
## The target address to use for status gathering. Either Broadcast (default)
## or the address of a single well-known device.
# address = "255.255.255.255:63322"
## The maximum number of device responses to wait for. 0 means no limit.
## NSDP works asynchronously. Without a limit (0) the plugin always waits
## the amount given in timeout for possible responses. By setting this
## option to the known number of devices, the plugin completes
## processing as soon as the last device has answered.
# device_limit = 0
## The maximum duration to wait for device responses.
# timeout = "2s"

View file

@ -0,0 +1,15 @@
# Gather Netgear Switch Discovery Protocol status
[[inputs.nsdp]]
## The target address to use for status gathering. Either Broadcast (default)
## or the address of a single well-known device.
address = "127.0.0.1:63322"
## The maximum number of device responses to wait for. 0 means no limit.
## NSDP works asynchronously. Without a limit (0) the plugin always waits
## the amount given in timeout for possible responses. By setting this
## option to the known number of devices, the plugin completes
## processing as soon as the last device has answered.
device_limit = 1
## The maximum duration to wait for device responses.
timeout = "5s"

View file

@ -0,0 +1,16 @@
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=1 broadcasts_total=0u,bytes_recv=3879427866u,bytes_sent=506548796u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014578000
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=2 broadcasts_total=0u,bytes_recv=355294894u,bytes_sent=1391071722u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014606000
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=3 broadcasts_total=0u,bytes_recv=109404586u,bytes_sent=3167275829u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014615000
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=4 broadcasts_total=0u,bytes_recv=47578624u,bytes_sent=725080793u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=5 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=6 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=7 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000
nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=8 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=1 broadcasts_total=0u,bytes_recv=24068850482u,bytes_sent=809406133u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014647000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=2 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=3 broadcasts_total=0u,bytes_recv=228210148u,bytes_sent=10286777958u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014657000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=4 broadcasts_total=0u,bytes_recv=4310867u,bytes_sent=47027386u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014668000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=5 broadcasts_total=0u,bytes_recv=565824065u,bytes_sent=13331332961u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=6 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=7 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000
nsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=8 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000