Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
292
plugins/inputs/dpdk/dpdk.go
Normal file
292
plugins/inputs/dpdk/dpdk.go
Normal file
|
@ -0,0 +1,292 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
//go:build linux
|
||||
|
||||
package dpdk
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/filter"
|
||||
"github.com/influxdata/telegraf/internal/choice"
|
||||
"github.com/influxdata/telegraf/internal/globpath"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
const (
|
||||
defaultPathToSocket = "/var/run/dpdk/rte/dpdk_telemetry.v2"
|
||||
defaultAccessTimeout = config.Duration(200 * time.Millisecond)
|
||||
maxCommandLength = 56
|
||||
maxCommandLengthWithParams = 1024
|
||||
pluginName = "dpdk"
|
||||
ethdevListCommand = "/ethdev/list"
|
||||
rawdevListCommand = "/rawdev/list"
|
||||
|
||||
dpdkMetadataFieldPidName = "pid"
|
||||
dpdkMetadataFieldVersionName = "version"
|
||||
|
||||
dpdkPluginOptionInMemory = "in_memory"
|
||||
|
||||
unreachableSocketBehaviorIgnore = "ignore"
|
||||
unreachableSocketBehaviorError = "error"
|
||||
)
|
||||
|
||||
type Dpdk struct {
|
||||
SocketPath string `toml:"socket_path"`
|
||||
AccessTimeout config.Duration `toml:"socket_access_timeout"`
|
||||
DeviceTypes []string `toml:"device_types"`
|
||||
EthdevConfig ethdevConfig `toml:"ethdev"`
|
||||
AdditionalCommands []string `toml:"additional_commands"`
|
||||
MetadataFields []string `toml:"metadata_fields"`
|
||||
PluginOptions []string `toml:"plugin_options"`
|
||||
UnreachableSocketBehavior string `toml:"unreachable_socket_behavior"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
connectors []*dpdkConnector
|
||||
rawdevCommands []string
|
||||
ethdevCommands []string
|
||||
ethdevExcludedCommandsFilter filter.Filter
|
||||
socketGlobPath *globpath.GlobPath
|
||||
}
|
||||
|
||||
type ethdevConfig struct {
|
||||
EthdevExcludeCommands []string `toml:"exclude_commands"`
|
||||
}
|
||||
|
||||
func (*Dpdk) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (dpdk *Dpdk) Init() error {
|
||||
dpdk.setupDefaultValues()
|
||||
|
||||
err := dpdk.validateAdditionalCommands()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dpdk.AccessTimeout < 0 {
|
||||
return errors.New("socket_access_timeout should be positive number or equal to 0 (to disable timeouts)")
|
||||
}
|
||||
|
||||
if len(dpdk.AdditionalCommands) == 0 && len(dpdk.DeviceTypes) == 0 {
|
||||
return errors.New("plugin was configured with nothing to read")
|
||||
}
|
||||
|
||||
dpdk.ethdevExcludedCommandsFilter, err = filter.Compile(dpdk.EthdevConfig.EthdevExcludeCommands)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error occurred during filter preparation for ethdev excluded commands: %w", err)
|
||||
}
|
||||
|
||||
if err = choice.Check(dpdk.UnreachableSocketBehavior, []string{unreachableSocketBehaviorError, unreachableSocketBehaviorIgnore}); err != nil {
|
||||
return fmt.Errorf("unreachable_socket_behavior: %w", err)
|
||||
}
|
||||
|
||||
glob, err := globpath.Compile(dpdk.SocketPath + "*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dpdk.socketGlobPath = glob
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dpdk *Dpdk) Start(telegraf.Accumulator) error {
|
||||
return dpdk.maintainConnections()
|
||||
}
|
||||
|
||||
// Gather function gathers all unique commands and processes each command sequentially
|
||||
// Parallel processing could be achieved by running several instances of this plugin with different settings
|
||||
func (dpdk *Dpdk) Gather(acc telegraf.Accumulator) error {
|
||||
if err := dpdk.Start(acc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, dpdkConn := range dpdk.connectors {
|
||||
commands := dpdk.gatherCommands(acc, dpdkConn)
|
||||
for _, command := range commands {
|
||||
dpdkConn.processCommand(acc, dpdk.Log, command, dpdk.MetadataFields)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dpdk *Dpdk) Stop() {
|
||||
for _, connector := range dpdk.connectors {
|
||||
if err := connector.tryClose(); err != nil {
|
||||
dpdk.Log.Warnf("Couldn't close connection for %q: %v", connector.pathToSocket, err)
|
||||
}
|
||||
}
|
||||
dpdk.connectors = nil
|
||||
}
|
||||
|
||||
// Setup default values for dpdk
|
||||
func (dpdk *Dpdk) setupDefaultValues() {
|
||||
if dpdk.SocketPath == "" {
|
||||
dpdk.SocketPath = defaultPathToSocket
|
||||
}
|
||||
|
||||
if dpdk.DeviceTypes == nil {
|
||||
dpdk.DeviceTypes = []string{"ethdev"}
|
||||
}
|
||||
|
||||
if dpdk.MetadataFields == nil {
|
||||
dpdk.MetadataFields = []string{dpdkMetadataFieldPidName, dpdkMetadataFieldVersionName}
|
||||
}
|
||||
|
||||
if dpdk.PluginOptions == nil {
|
||||
dpdk.PluginOptions = []string{dpdkPluginOptionInMemory}
|
||||
}
|
||||
|
||||
if len(dpdk.UnreachableSocketBehavior) == 0 {
|
||||
dpdk.UnreachableSocketBehavior = unreachableSocketBehaviorError
|
||||
}
|
||||
|
||||
dpdk.rawdevCommands = []string{"/rawdev/xstats"}
|
||||
dpdk.ethdevCommands = []string{"/ethdev/stats", "/ethdev/xstats", "/ethdev/info", ethdevLinkStatusCommand}
|
||||
}
|
||||
|
||||
func (dpdk *Dpdk) getDpdkInMemorySocketPaths() []string {
|
||||
filePaths := dpdk.socketGlobPath.Match()
|
||||
|
||||
var results []string
|
||||
for _, filePath := range filePaths {
|
||||
fileInfo, err := os.Stat(filePath)
|
||||
if err != nil || fileInfo.IsDir() || !strings.Contains(filePath, dpdkSocketTemplateName) {
|
||||
continue
|
||||
}
|
||||
|
||||
if isInMemorySocketPath(filePath, dpdk.SocketPath) {
|
||||
results = append(results, filePath)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// Checks that user-supplied commands are unique and match DPDK commands format
|
||||
func (dpdk *Dpdk) validateAdditionalCommands() error {
|
||||
dpdk.AdditionalCommands = uniqueValues(dpdk.AdditionalCommands)
|
||||
|
||||
for _, cmd := range dpdk.AdditionalCommands {
|
||||
if len(cmd) == 0 {
|
||||
return errors.New("got empty command")
|
||||
}
|
||||
|
||||
if cmd[0] != '/' {
|
||||
return fmt.Errorf("%q command should start with slash", cmd)
|
||||
}
|
||||
|
||||
if commandWithoutParams := stripParams(cmd); len(commandWithoutParams) >= maxCommandLength {
|
||||
return fmt.Errorf("%q command is too long. It shall be less than %v characters", commandWithoutParams, maxCommandLength)
|
||||
}
|
||||
|
||||
if len(cmd) >= maxCommandLengthWithParams {
|
||||
return fmt.Errorf("command with parameters %q shall be less than %v characters", cmd, maxCommandLengthWithParams)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Establishes connections do DPDK telemetry sockets
|
||||
func (dpdk *Dpdk) maintainConnections() error {
|
||||
candidates := []string{dpdk.SocketPath}
|
||||
if choice.Contains(dpdkPluginOptionInMemory, dpdk.PluginOptions) {
|
||||
candidates = dpdk.getDpdkInMemorySocketPaths()
|
||||
}
|
||||
|
||||
// Find sockets in the connected-sockets list that are not among
|
||||
// the candidates anymore and thus need to be removed.
|
||||
for i := 0; i < len(dpdk.connectors); i++ {
|
||||
connector := dpdk.connectors[i]
|
||||
if !choice.Contains(connector.pathToSocket, candidates) {
|
||||
dpdk.Log.Debugf("Close unused connection: %s", connector.pathToSocket)
|
||||
if closeErr := connector.tryClose(); closeErr != nil {
|
||||
dpdk.Log.Warnf("Failed to close unused connection: %v", closeErr)
|
||||
}
|
||||
dpdk.connectors = append(dpdk.connectors[:i], dpdk.connectors[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
// Find candidates that are not yet in the connected-sockets list as we
|
||||
// need to connect to those.
|
||||
for _, candidate := range candidates {
|
||||
var found bool
|
||||
for _, connector := range dpdk.connectors {
|
||||
if candidate == connector.pathToSocket {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
connector := newDpdkConnector(candidate, dpdk.AccessTimeout)
|
||||
connectionInitMessage, err := connector.connect()
|
||||
if err != nil {
|
||||
if dpdk.UnreachableSocketBehavior == unreachableSocketBehaviorError {
|
||||
return fmt.Errorf("couldn't connect to socket %s: %w", candidate, err)
|
||||
}
|
||||
dpdk.Log.Warnf("Couldn't connect to socket %s: %v", candidate, err)
|
||||
continue
|
||||
}
|
||||
|
||||
dpdk.Log.Debugf("Successfully connected to the socket: %s. Version: %v running as process with PID %v with len %v",
|
||||
candidate, connectionInitMessage.Version, connectionInitMessage.Pid, connectionInitMessage.MaxOutputLen)
|
||||
dpdk.connectors = append(dpdk.connectors, connector)
|
||||
}
|
||||
}
|
||||
|
||||
if len(dpdk.connectors) == 0 {
|
||||
errMsg := "no active sockets connections present"
|
||||
if dpdk.UnreachableSocketBehavior == unreachableSocketBehaviorError {
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
dpdk.Log.Warnf("Unreachable socket issue occurred: %v", errMsg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gathers all unique commands
|
||||
func (dpdk *Dpdk) gatherCommands(acc telegraf.Accumulator, dpdkConnector *dpdkConnector) []string {
|
||||
var commands []string
|
||||
if choice.Contains("ethdev", dpdk.DeviceTypes) {
|
||||
ethdevCommands := removeSubset(dpdk.ethdevCommands, dpdk.ethdevExcludedCommandsFilter)
|
||||
ethdevCommands, err := dpdkConnector.appendCommandsWithParamsFromList(ethdevListCommand, ethdevCommands)
|
||||
if err != nil {
|
||||
acc.AddError(fmt.Errorf("error occurred during fetching of %q params: %w", ethdevListCommand, err))
|
||||
}
|
||||
commands = append(commands, ethdevCommands...)
|
||||
}
|
||||
|
||||
if choice.Contains("rawdev", dpdk.DeviceTypes) {
|
||||
rawdevCommands, err := dpdkConnector.appendCommandsWithParamsFromList(rawdevListCommand, dpdk.rawdevCommands)
|
||||
if err != nil {
|
||||
acc.AddError(fmt.Errorf("error occurred during fetching of %q params: %w", rawdevListCommand, err))
|
||||
}
|
||||
commands = append(commands, rawdevCommands...)
|
||||
}
|
||||
|
||||
commands = append(commands, dpdk.AdditionalCommands...)
|
||||
return uniqueValues(commands)
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add(pluginName, func() telegraf.Input {
|
||||
dpdk := &Dpdk{
|
||||
// Setting it here (rather than in `Init()`) to distinguish between "zero" value,
|
||||
// default value and don't having value in config at all.
|
||||
AccessTimeout: defaultAccessTimeout,
|
||||
}
|
||||
return dpdk
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue