build(deps): bump the golang group across 1 directory with 3 updates

Bumps the golang group with 2 updates in the / directory: [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) and [github.com/safchain/ethtool](https://github.com/safchain/ethtool).


Updates `github.com/onsi/ginkgo/v2` from 2.17.3 to 2.19.0
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.17.3...v2.19.0)

Updates `github.com/safchain/ethtool` from 0.3.0 to 0.4.0
- [Release notes](https://github.com/safchain/ethtool/releases)
- [Commits](https://github.com/safchain/ethtool/compare/v0.3.0...v0.4.0)

Updates `golang.org/x/sys` from 0.20.0 to 0.21.0
- [Commits](https://github.com/golang/sys/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/safchain/ethtool
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2024-06-17 15:23:00 +00:00
committed by GitHub
parent b96f963c7a
commit 508c94caec
25 changed files with 714 additions and 83 deletions

View File

@ -1,3 +1,23 @@
## 2.19.0
### Features
[Label Sets](https://onsi.github.io/ginkgo/#label-sets) allow for more expressive and flexible label filtering.
## 2.18.0
### Features
- Add --slience-skips and --force-newlines [f010b65]
- fail when no tests were run and --fail-on-empty was set [d80eebe]
### Fixes
- Fix table entry context edge case [42013d6]
### Maintenance
- Bump golang.org/x/tools from 0.20.0 to 0.21.0 (#1406) [fcf1fd7]
- Bump github.com/onsi/gomega from 1.33.0 to 1.33.1 (#1399) [8bb14fd]
- Bump golang.org/x/net from 0.24.0 to 0.25.0 (#1407) [04bfad7]
## 2.17.3
### Fixes

View File

@ -6,8 +6,10 @@ Your contributions to Ginkgo are essential for its long-term maintenance and imp
- Ensure adequate test coverage:
- When adding to the Ginkgo library, add unit and/or integration tests (under the `integration` folder).
- When adding to the Ginkgo CLI, note that there are very few unit tests. Please add an integration test.
- Make sure all the tests succeed via `ginkgo -r -p`
- Vet your changes via `go vet ./...`
- Update the documentation. Ginkgo uses `godoc` comments and documentation in `docs/index.md`. You can run `bundle exec jekyll serve` in the `docs` directory to preview your changes.
- Run `make` or:
- Install ginkgo locally via `go install ./...`
- Make sure all the tests succeed via `ginkgo -r -p`
- Vet your changes via `go vet ./...`
- Update the documentation. Ginkgo uses `godoc` comments and documentation in `docs/index.md`. You can run `bundle && bundle exec jekyll serve` in the `docs` directory to preview your changes.
Thanks for supporting Ginkgo!
Thanks for supporting Ginkgo!

11
vendor/github.com/onsi/ginkgo/v2/Makefile generated vendored Normal file
View File

@ -0,0 +1,11 @@
# default task since it's first
.PHONY: all
all: vet test
.PHONY: test
test:
go run github.com/onsi/ginkgo/v2/ginkgo -r -p
.PHONY: vet
vet:
go vet ./...

View File

@ -489,10 +489,15 @@ func (suite *Suite) runSpecs(description string, suiteLabels Labels, suitePath s
newGroup(suite).run(specs.AtIndices(groupedSpecIndices[groupedSpecIdx]))
}
if specs.HasAnySpecsMarkedPending() && suite.config.FailOnPending {
if suite.config.FailOnPending && specs.HasAnySpecsMarkedPending() {
suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected pending specs and --fail-on-pending is set")
suite.report.SuiteSucceeded = false
}
if suite.config.FailOnEmpty && specs.CountWithoutSkip() == 0 {
suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected no specs ran and --fail-on-empty is set")
suite.report.SuiteSucceeded = false
}
}
if ranBeforeSuite {

View File

@ -202,6 +202,11 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
v := r.conf.Verbosity()
inParallel := report.RunningInParallel
//should we completely omit this spec?
if report.State.Is(types.SpecStateSkipped) && r.conf.SilenceSkips {
return
}
header := r.specDenoter
if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) {
header = fmt.Sprintf("[%s]", report.LeafNodeType)
@ -278,9 +283,12 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) {
}
}
// If we have no content to show, jsut emit the header and return
// If we have no content to show, just emit the header and return
if !reportHasContent {
r.emit(r.f(highlightColor + header + "{{/}}"))
if r.conf.ForceNewlines {
r.emit("\n")
}
return
}

View File

@ -177,6 +177,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
{"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")},
{"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")},
{"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)},
{"FailOnEmpty", fmt.Sprintf("%t", report.SuiteConfig.FailOnEmpty)},
{"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)},
{"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)},
{"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)},

View File

@ -269,11 +269,15 @@ func generateTable(description string, isSubtree bool, args ...interface{}) {
internalNodeArgs = append(internalNodeArgs, entry.decorations...)
hasContext := false
if internalBodyType.NumIn() > 0. {
if internalBodyType.NumIn() > 0 {
if internalBodyType.In(0).Implements(specContextType) {
hasContext = true
} else if internalBodyType.In(0).Implements(contextType) && (len(entry.parameters) == 0 || !reflect.TypeOf(entry.parameters[0]).Implements(contextType)) {
} else if internalBodyType.In(0).Implements(contextType) {
hasContext = true
if len(entry.parameters) > 0 && reflect.TypeOf(entry.parameters[0]) != nil && reflect.TypeOf(entry.parameters[0]).Implements(contextType) {
// we allow you to pass in a non-nil context
hasContext = false
}
}
}

View File

@ -25,6 +25,7 @@ type SuiteConfig struct {
SkipFiles []string
LabelFilter string
FailOnPending bool
FailOnEmpty bool
FailFast bool
FlakeAttempts int
MustPassRepeatedly int
@ -90,6 +91,8 @@ type ReporterConfig struct {
FullTrace bool
ShowNodeEvents bool
GithubOutput bool
SilenceSkips bool
ForceNewlines bool
JSONReport string
JUnitReport string
@ -275,6 +278,8 @@ var SuiteConfigFlags = GinkgoFlags{
Usage: "If set, ginkgo will stop running a test suite after a failure occurs."},
{KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags",
Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."},
{KeyPath: "S.FailOnEmpty", Name: "fail-on-empty", SectionKey: "failure",
Usage: "If set, ginkgo will mark the test suite as failed if no specs are run."},
{KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."},
@ -334,6 +339,10 @@ var ReporterConfigFlags = GinkgoFlags{
Usage: "If set, default reporter prints node > Enter and < Exit events when specs fail"},
{KeyPath: "R.GithubOutput", Name: "github-output", SectionKey: "output",
Usage: "If set, default reporter prints easier to manage output in Github Actions."},
{KeyPath: "R.SilenceSkips", Name: "silence-skips", SectionKey: "output",
Usage: "If set, default reporter will not print out skipped tests."},
{KeyPath: "R.ForceNewlines", Name: "force-newlines", SectionKey: "output",
Usage: "If set, default reporter will ensure a newline appears after each test."},
{KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output",
Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."},

View File

@ -45,6 +45,83 @@ func orAction(a, b LabelFilter) LabelFilter {
return func(labels []string) bool { return a(labels) || b(labels) }
}
func labelSetFor(key string, labels []string) map[string]bool {
key = strings.ToLower(strings.TrimSpace(key))
out := map[string]bool{}
for _, label := range labels {
components := strings.SplitN(label, ":", 2)
if len(components) < 2 {
continue
}
if key == strings.ToLower(strings.TrimSpace(components[0])) {
out[strings.ToLower(strings.TrimSpace(components[1]))] = true
}
}
return out
}
func isEmptyLabelSetAction(key string) LabelFilter {
return func(labels []string) bool {
return len(labelSetFor(key, labels)) == 0
}
}
func containsAnyLabelSetAction(key string, expectedValues []string) LabelFilter {
return func(labels []string) bool {
set := labelSetFor(key, labels)
for _, value := range expectedValues {
if set[value] {
return true
}
}
return false
}
}
func containsAllLabelSetAction(key string, expectedValues []string) LabelFilter {
return func(labels []string) bool {
set := labelSetFor(key, labels)
for _, value := range expectedValues {
if !set[value] {
return false
}
}
return true
}
}
func consistsOfLabelSetAction(key string, expectedValues []string) LabelFilter {
return func(labels []string) bool {
set := labelSetFor(key, labels)
if len(set) != len(expectedValues) {
return false
}
for _, value := range expectedValues {
if !set[value] {
return false
}
}
return true
}
}
func isSubsetOfLabelSetAction(key string, expectedValues []string) LabelFilter {
expectedSet := map[string]bool{}
for _, value := range expectedValues {
expectedSet[value] = true
}
return func(labels []string) bool {
set := labelSetFor(key, labels)
for value := range set {
if !expectedSet[value] {
return false
}
}
return true
}
}
type lfToken uint
const (
@ -58,6 +135,9 @@ const (
lfTokenOr
lfTokenRegexp
lfTokenLabel
lfTokenSetKey
lfTokenSetOperation
lfTokenSetArgument
lfTokenEOF
)
@ -71,6 +151,8 @@ func (l lfToken) Precedence() int {
return 2
case lfTokenNot:
return 3
case lfTokenSetOperation:
return 4
}
return -1
}
@ -93,6 +175,12 @@ func (l lfToken) String() string {
return "/regexp/"
case lfTokenLabel:
return "label"
case lfTokenSetKey:
return "set_key"
case lfTokenSetOperation:
return "set_operation"
case lfTokenSetArgument:
return "set_argument"
case lfTokenEOF:
return "EOF"
}
@ -148,6 +236,35 @@ func (tn *treeNode) constructLabelFilter(input string) (LabelFilter, error) {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("RegExp compilation error: %s", err))
}
return matchLabelRegexAction(re), nil
case lfTokenSetOperation:
tokenSetOperation := strings.ToLower(tn.value)
if tokenSetOperation == "isempty" {
return isEmptyLabelSetAction(tn.leftNode.value), nil
}
if tn.rightNode == nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("Set operation '%s' is missing an argument.", tn.value))
}
rawValues := strings.Split(tn.rightNode.value, ",")
values := make([]string, len(rawValues))
for i := range rawValues {
values[i] = strings.ToLower(strings.TrimSpace(rawValues[i]))
if strings.ContainsAny(values[i], "&|!,()/") {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.rightNode.location, fmt.Sprintf("Invalid label value '%s' in set operation argument.", values[i]))
} else if values[i] == "" {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.rightNode.location, "Empty label value in set operation argument.")
}
}
switch tokenSetOperation {
case "containsany":
return containsAnyLabelSetAction(tn.leftNode.value, values), nil
case "containsall":
return containsAllLabelSetAction(tn.leftNode.value, values), nil
case "consistsof":
return consistsOfLabelSetAction(tn.leftNode.value, values), nil
case "issubsetof":
return isSubsetOfLabelSetAction(tn.leftNode.value, values), nil
}
}
if tn.rightNode == nil {
@ -203,7 +320,17 @@ func (tn *treeNode) toString(indent int) string {
return out
}
var validSetOperations = map[string]string{
"containsany": "containsAny",
"containsall": "containsAll",
"consistsof": "consistsOf",
"issubsetof": "isSubsetOf",
"isempty": "isEmpty",
}
func tokenize(input string) func() (*treeNode, error) {
lastToken := lfTokenInvalid
lastValue := ""
runes, i := []rune(input), 0
peekIs := func(r rune) bool {
@ -233,6 +360,53 @@ func tokenize(input string) func() (*treeNode, error) {
}
node := &treeNode{location: i}
defer func() {
lastToken = node.token
lastValue = node.value
}()
if lastToken == lfTokenSetKey {
//we should get a valid set operation next
value, n := consumeUntil(" )")
if validSetOperations[strings.ToLower(value)] == "" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, fmt.Sprintf("Invalid set operation '%s'.", value))
}
i += n
node.token, node.value = lfTokenSetOperation, value
return node, nil
}
if lastToken == lfTokenSetOperation {
//we should get an argument next, if we aren't isempty
var arg = ""
origI := i
if runes[i] == '{' {
i += 1
value, n := consumeUntil("}")
if i+n >= len(runes) {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i-1, "Missing closing '}' in set operation argument?")
}
i += n + 1
arg = value
} else {
value, n := consumeUntil("&|!,()/")
i += n
arg = strings.TrimSpace(value)
}
if strings.ToLower(lastValue) == "isempty" && arg != "" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, fmt.Sprintf("isEmpty does not take arguments, was passed '%s'.", arg))
}
if arg == "" && strings.ToLower(lastValue) != "isempty" {
if i < len(runes) && runes[i] == '/' {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, "Set operations do not support regular expressions.")
} else {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, fmt.Sprintf("Set operation '%s' requires an argument.", lastValue))
}
}
// note that we sent an empty SetArgument token if we are isempty
node.token, node.value = lfTokenSetArgument, arg
return node, nil
}
switch runes[i] {
case '&':
if !peekIs('&') {
@ -264,8 +438,38 @@ func tokenize(input string) func() (*treeNode, error) {
i += n + 1
node.token, node.value = lfTokenRegexp, value
default:
value, n := consumeUntil("&|!,()/")
value, n := consumeUntil("&|!,()/:")
i += n
value = strings.TrimSpace(value)
//are we the beginning of a set operation?
if i < len(runes) && runes[i] == ':' {
if peekIs(' ') {
if value == "" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Missing set key.")
}
i += 1
//we are the beginning of a set operation
node.token, node.value = lfTokenSetKey, value
return node, nil
}
additionalValue, n := consumeUntil("&|!,()/")
additionalValue = strings.TrimSpace(additionalValue)
if additionalValue == ":" {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Missing set operation.")
}
i += n
value += additionalValue
}
valueToCheckForSetOperation := strings.ToLower(value)
for setOperation := range validSetOperations {
idx := strings.Index(valueToCheckForSetOperation, " "+setOperation)
if idx > 0 {
return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i-n+idx+1, fmt.Sprintf("Looks like you are using the set operator '%s' but did not provide a set key. Did you forget the ':'?", validSetOperations[setOperation]))
}
}
node.token, node.value = lfTokenLabel, strings.TrimSpace(value)
}
return node, nil
@ -307,7 +511,7 @@ LOOP:
switch node.token {
case lfTokenEOF:
break LOOP
case lfTokenLabel, lfTokenRegexp:
case lfTokenLabel, lfTokenRegexp, lfTokenSetKey:
if current.rightNode != nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Found two adjacent labels. You need an operator between them.")
}
@ -326,6 +530,18 @@ LOOP:
node.setLeftNode(nodeToStealFrom.rightNode)
nodeToStealFrom.setRightNode(node)
current = node
case lfTokenSetOperation:
if current.rightNode == nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Set operation '%s' missing left hand operand.", node.value))
}
node.setLeftNode(current.rightNode)
current.setRightNode(node)
current = node
case lfTokenSetArgument:
if current.rightNode != nil {
return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Unexpected set argument '%s'.", node.token))
}
current.setRightNode(node)
case lfTokenCloseGroup:
firstUnmatchedOpenNode := current.firstUnmatchedOpenNode()
if firstUnmatchedOpenNode == nil {
@ -354,5 +570,14 @@ func ValidateAndCleanupLabel(label string, cl CodeLocation) (string, error) {
if strings.ContainsAny(out, "&|!,()/") {
return "", GinkgoErrors.InvalidLabel(label, cl)
}
if out[0] == ':' {
return "", GinkgoErrors.InvalidLabel(label, cl)
}
if strings.Contains(out, ":") {
components := strings.SplitN(out, ":", 2)
if len(components) < 2 || components[1] == "" {
return "", GinkgoErrors.InvalidLabel(label, cl)
}
}
return out, nil
}

View File

@ -1,3 +1,3 @@
package types
const VERSION = "2.17.3"
const VERSION = "2.19.0"

7
vendor/github.com/safchain/ethtool/.yamllint generated vendored Normal file
View File

@ -0,0 +1,7 @@
---
extends: default
rules:
document-start: disable
truthy:
check-keys: false

View File

@ -47,33 +47,41 @@ const (
// ethtool stats related constants.
const (
ETH_GSTRING_LEN = 32
ETH_SS_STATS = 1
ETH_SS_FEATURES = 4
ETH_GSTRING_LEN = 32
ETH_SS_STATS = 1
ETH_SS_PRIV_FLAGS = 2
ETH_SS_FEATURES = 4
// CMD supported
ETHTOOL_GSET = 0x00000001 /* Get settings. */
ETHTOOL_SSET = 0x00000002 /* Set settings. */
ETHTOOL_GDRVINFO = 0x00000003 /* Get driver info. */
ETHTOOL_GSTRINGS = 0x0000001b /* get specified string set */
ETHTOOL_GSTATS = 0x0000001d /* get NIC-specific statistics */
// other CMDs from ethtool-copy.h of ethtool-3.5 package
ETHTOOL_GSET = 0x00000001 /* Get settings. */
ETHTOOL_SSET = 0x00000002 /* Set settings. */
ETHTOOL_GMSGLVL = 0x00000007 /* Get driver message level */
ETHTOOL_SMSGLVL = 0x00000008 /* Set driver msg level. */
ETHTOOL_GCHANNELS = 0x0000003c /* Get no of channels */
ETHTOOL_SCHANNELS = 0x0000003d /* Set no of channels */
ETHTOOL_GCOALESCE = 0x0000000e /* Get coalesce config */
ETHTOOL_GMSGLVL = 0x00000007 /* Get driver message level */
ETHTOOL_SMSGLVL = 0x00000008 /* Set driver msg level. */
/* Get link status for host, i.e. whether the interface *and* the
* physical port (if there is one) are up (ethtool_value). */
* physical port (if there is one) are up (ethtool_value). */
ETHTOOL_GLINK = 0x0000000a
ETHTOOL_GMODULEINFO = 0x00000042 /* Get plug-in module information */
ETHTOOL_GMODULEEEPROM = 0x00000043 /* Get plug-in module eeprom */
ETHTOOL_GCOALESCE = 0x0000000e /* Get coalesce config */
ETHTOOL_SCOALESCE = 0x0000000f /* Set coalesce config */
ETHTOOL_GRINGPARAM = 0x00000010 /* Get ring parameters */
ETHTOOL_SRINGPARAM = 0x00000011 /* Set ring parameters. */
ETHTOOL_GPAUSEPARAM = 0x00000012 /* Get pause parameters */
ETHTOOL_SPAUSEPARAM = 0x00000013 /* Set pause parameters. */
ETHTOOL_GSTRINGS = 0x0000001b /* Get specified string set */
ETHTOOL_GSTATS = 0x0000001d /* Get NIC-specific statistics */
ETHTOOL_GPERMADDR = 0x00000020 /* Get permanent hardware address */
ETHTOOL_GFLAGS = 0x00000025 /* Get flags bitmap(ethtool_value) */
ETHTOOL_GPFLAGS = 0x00000027 /* Get driver-private flags bitmap */
ETHTOOL_SPFLAGS = 0x00000028 /* Set driver-private flags bitmap */
ETHTOOL_GSSET_INFO = 0x00000037 /* Get string set info */
ETHTOOL_GFEATURES = 0x0000003a /* Get device offload settings */
ETHTOOL_SFEATURES = 0x0000003b /* Change device offload settings */
ETHTOOL_GFLAGS = 0x00000025 /* Get flags bitmap(ethtool_value) */
ETHTOOL_GSSET_INFO = 0x00000037 /* Get string set info */
ETHTOOL_GCHANNELS = 0x0000003c /* Get no of channels */
ETHTOOL_SCHANNELS = 0x0000003d /* Set no of channels */
ETHTOOL_GET_TS_INFO = 0x00000041 /* Get time stamping and PHC info */
ETHTOOL_GMODULEINFO = 0x00000042 /* Get plug-in module information */
ETHTOOL_GMODULEEEPROM = 0x00000043 /* Get plug-in module eeprom */
)
// MAX_GSTRINGS maximum number of stats entries that ethtool can
@ -85,6 +93,41 @@ const (
PERMADDR_LEN = 32
)
// ethtool sset_info related constants
const (
MAX_SSET_INFO = 64
)
var supportedCapabilities = []struct {
name string
mask uint64
speed uint64
}{
{"10baseT_Half", unix.ETHTOOL_LINK_MODE_10baseT_Half_BIT, 10_000_000},
{"10baseT_Full", unix.ETHTOOL_LINK_MODE_10baseT_Full_BIT, 10_000_000},
{"100baseT_Half", unix.ETHTOOL_LINK_MODE_100baseT_Half_BIT, 100_000_000},
{"100baseT_Full", unix.ETHTOOL_LINK_MODE_100baseT_Full_BIT, 100_000_000},
{"1000baseT_Half", unix.ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 1_000_000_000},
{"1000baseT_Full", unix.ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 1_000_000_000},
{"10000baseT_Full", unix.ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 10_000_000_000},
{"2500baseT_Full", unix.ETHTOOL_LINK_MODE_2500baseT_Full_BIT, 2_500_000_000},
{"1000baseKX_Full", unix.ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 1_000_000_000},
{"10000baseKX_Full", unix.ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 10_000_000_000},
{"10000baseKR_Full", unix.ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 10_000_000_000},
{"10000baseR_FEC", unix.ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 10_000_000_000},
{"20000baseMLD2_Full", unix.ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT, 20_000_000_000},
{"20000baseKR2_Full", unix.ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 20_000_000_000},
{"40000baseKR4_Full", unix.ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 40_000_000_000},
{"40000baseCR4_Full", unix.ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 40_000_000_000},
{"40000baseSR4_Full", unix.ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 40_000_000_000},
{"40000baseLR4_Full", unix.ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 40_000_000_000},
{"56000baseKR4_Full", unix.ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT, 56_000_000_000},
{"56000baseCR4_Full", unix.ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT, 56_000_000_000},
{"56000baseSR4_Full", unix.ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT, 56_000_000_000},
{"56000baseLR4_Full", unix.ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT, 56_000_000_000},
{"25000baseCR_Full", unix.ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 25_000_000_000},
}
type ifreq struct {
ifr_name [IFNAMSIZ]byte
ifr_data uintptr
@ -94,8 +137,8 @@ type ifreq struct {
type ethtoolSsetInfo struct {
cmd uint32
reserved uint32
sset_mask uint32
data uintptr
sset_mask uint64
data [MAX_SSET_INFO]uint32
}
type ethtoolGetFeaturesBlock struct {
@ -315,6 +358,27 @@ type ethtoolPermAddr struct {
data [PERMADDR_LEN]byte
}
// Ring is a ring config for an interface
type Ring struct {
Cmd uint32
RxMaxPending uint32
RxMiniMaxPending uint32
RxJumboMaxPending uint32
TxMaxPending uint32
RxPending uint32
RxMiniPending uint32
RxJumboPending uint32
TxPending uint32
}
// Pause is a pause config for an interface
type Pause struct {
Cmd uint32
Autoneg uint32
RxPause uint32
TxPause uint32
}
type Ethtool struct {
fd int
}
@ -421,6 +485,15 @@ func (e *Ethtool) GetCoalesce(intf string) (Coalesce, error) {
return coalesce, nil
}
// SetCoalesce sets the coalesce config for the given interface name.
func (e *Ethtool) SetCoalesce(intf string, coalesce Coalesce) (Coalesce, error) {
coalesce, err := e.setCoalesce(intf, coalesce)
if err != nil {
return Coalesce{}, err
}
return coalesce, nil
}
// GetTimestampingInformation returns the PTP timestamping information for the given interface name.
func (e *Ethtool) GetTimestampingInformation(intf string) (TimestampingInformation, error) {
ts, err := e.getTimestampingInformation(intf)
@ -516,6 +589,16 @@ func (e *Ethtool) getCoalesce(intf string) (Coalesce, error) {
return coalesce, nil
}
func (e *Ethtool) setCoalesce(intf string, coalesce Coalesce) (Coalesce, error) {
coalesce.Cmd = ETHTOOL_SCOALESCE
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&coalesce))); err != nil {
return Coalesce{}, err
}
return coalesce, nil
}
func (e *Ethtool) getTimestampingInformation(intf string) (TimestampingInformation, error) {
ts := TimestampingInformation{
Cmd: ETHTOOL_GET_TS_INFO,
@ -567,10 +650,74 @@ func (e *Ethtool) getModuleEeprom(intf string) (ethtoolEeprom, ethtoolModInfo, e
return eeprom, modInfo, nil
}
// GetRing retrieves ring parameters of the given interface name.
func (e *Ethtool) GetRing(intf string) (Ring, error) {
ring := Ring{
Cmd: ETHTOOL_GRINGPARAM,
}
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&ring))); err != nil {
return Ring{}, err
}
return ring, nil
}
// SetRing sets ring parameters of the given interface name.
func (e *Ethtool) SetRing(intf string, ring Ring) (Ring, error) {
ring.Cmd = ETHTOOL_SRINGPARAM
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&ring))); err != nil {
return Ring{}, err
}
return ring, nil
}
// GetPause retrieves pause parameters of the given interface name.
func (e *Ethtool) GetPause(intf string) (Pause, error) {
pause := Pause{
Cmd: ETHTOOL_GPAUSEPARAM,
}
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&pause))); err != nil {
return Pause{}, err
}
return pause, nil
}
// SetPause sets pause parameters of the given interface name.
func (e *Ethtool) SetPause(intf string, pause Pause) (Pause, error) {
pause.Cmd = ETHTOOL_SPAUSEPARAM
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&pause))); err != nil {
return Pause{}, err
}
return pause, nil
}
func isFeatureBitSet(blocks [MAX_FEATURE_BLOCKS]ethtoolGetFeaturesBlock, index uint) bool {
return (blocks)[index/32].active&(1<<(index%32)) != 0
}
type FeatureState struct {
Available bool
Requested bool
Active bool
NeverChanged bool
}
func getFeatureStateBits(blocks [MAX_FEATURE_BLOCKS]ethtoolGetFeaturesBlock, index uint) FeatureState {
return FeatureState{
Available: (blocks)[index/32].available&(1<<(index%32)) != 0,
Requested: (blocks)[index/32].requested&(1<<(index%32)) != 0,
Active: (blocks)[index/32].active&(1<<(index%32)) != 0,
NeverChanged: (blocks)[index/32].never_changed&(1<<(index%32)) != 0,
}
}
func setFeatureBit(blocks *[MAX_FEATURE_BLOCKS]ethtoolSetFeaturesBlock, index uint, value bool) {
blockIndex, bitIndex := index/32, index%32
@ -583,18 +730,19 @@ func setFeatureBit(blocks *[MAX_FEATURE_BLOCKS]ethtoolSetFeaturesBlock, index ui
}
}
// FeatureNames shows supported features by their name.
func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
func (e *Ethtool) getNames(intf string, mask int) (map[string]uint, error) {
ssetInfo := ethtoolSsetInfo{
cmd: ETHTOOL_GSSET_INFO,
sset_mask: 1 << ETH_SS_FEATURES,
sset_mask: 1 << mask,
data: [MAX_SSET_INFO]uint32{},
}
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&ssetInfo))); err != nil {
return nil, err
}
length := uint32(ssetInfo.data)
/* we only read data on first index because single bit was set in sset_mask(0x10) */
length := ssetInfo.data[0]
if length == 0 {
return map[string]uint{}, nil
} else if length > MAX_GSTRINGS {
@ -603,7 +751,7 @@ func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
gstrings := ethtoolGStrings{
cmd: ETHTOOL_GSTRINGS,
string_set: ETH_SS_FEATURES,
string_set: uint32(mask),
len: length,
data: [MAX_GSTRINGS * ETH_GSTRING_LEN]byte{},
}
@ -612,7 +760,7 @@ func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
return nil, err
}
var result = make(map[string]uint)
result := make(map[string]uint)
for i := 0; i != int(length); i++ {
b := gstrings.data[i*ETH_GSTRING_LEN : i*ETH_GSTRING_LEN+ETH_GSTRING_LEN]
key := goString(b)
@ -624,6 +772,11 @@ func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
return result, nil
}
// FeatureNames shows supported features by their name.
func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
return e.getNames(intf, ETH_SS_FEATURES)
}
// Features retrieves features of the given interface name.
func (e *Ethtool) Features(intf string) (map[string]bool, error) {
names, err := e.FeatureNames(intf)
@ -645,7 +798,7 @@ func (e *Ethtool) Features(intf string) (map[string]bool, error) {
return nil, err
}
var result = make(map[string]bool, length)
result := make(map[string]bool, length)
for key, index := range names {
result[key] = isFeatureBitSet(features.blocks, index)
}
@ -653,6 +806,36 @@ func (e *Ethtool) Features(intf string) (map[string]bool, error) {
return result, nil
}
// FeaturesWithState retrieves features of the given interface name,
// with extra flags to explain if they can be enabled
func (e *Ethtool) FeaturesWithState(intf string) (map[string]FeatureState, error) {
names, err := e.FeatureNames(intf)
if err != nil {
return nil, err
}
length := uint32(len(names))
if length == 0 {
return map[string]FeatureState{}, nil
}
features := ethtoolGfeatures{
cmd: ETHTOOL_GFEATURES,
size: (length + 32 - 1) / 32,
}
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&features))); err != nil {
return nil, err
}
var result = make(map[string]FeatureState, length)
for key, index := range names {
result[key] = getFeatureStateBits(features.blocks, index)
}
return result, nil
}
// Change requests a change in the given device's features.
func (e *Ethtool) Change(intf string, config map[string]bool) error {
names, err := e.FeatureNames(intf)
@ -678,6 +861,68 @@ func (e *Ethtool) Change(intf string, config map[string]bool) error {
return e.ioctl(intf, uintptr(unsafe.Pointer(&features)))
}
// PrivFlagsNames shows supported private flags by their name.
func (e *Ethtool) PrivFlagsNames(intf string) (map[string]uint, error) {
return e.getNames(intf, ETH_SS_PRIV_FLAGS)
}
// PrivFlags retrieves private flags of the given interface name.
func (e *Ethtool) PrivFlags(intf string) (map[string]bool, error) {
names, err := e.PrivFlagsNames(intf)
if err != nil {
return nil, err
}
length := uint32(len(names))
if length == 0 {
return map[string]bool{}, nil
}
var val ethtoolLink
val.cmd = ETHTOOL_GPFLAGS
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&val))); err != nil {
return nil, err
}
result := make(map[string]bool, length)
for name, mask := range names {
result[name] = val.data&(1<<mask) != 0
}
return result, nil
}
// UpdatePrivFlags requests a change in the given device's private flags.
func (e *Ethtool) UpdatePrivFlags(intf string, config map[string]bool) error {
names, err := e.PrivFlagsNames(intf)
if err != nil {
return err
}
var curr ethtoolLink
curr.cmd = ETHTOOL_GPFLAGS
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&curr))); err != nil {
return err
}
var update ethtoolLink
update.cmd = ETHTOOL_SPFLAGS
update.data = curr.data
for name, value := range config {
if index, ok := names[name]; ok {
if value {
update.data |= 1 << index
} else {
update.data &= ^(1 << index)
}
} else {
return fmt.Errorf("unsupported priv flag %q", name)
}
}
return e.ioctl(intf, uintptr(unsafe.Pointer(&update)))
}
// Get state of a link.
func (e *Ethtool) LinkState(intf string) (uint32, error) {
x := ethtoolLink{
@ -726,7 +971,7 @@ func (e *Ethtool) Stats(intf string) (map[string]uint64, error) {
return nil, err
}
var result = make(map[string]uint64)
result := make(map[string]uint64)
for i := 0; i != int(drvinfo.n_stats); i++ {
b := gstrings.data[i*ETH_GSTRING_LEN : i*ETH_GSTRING_LEN+ETH_GSTRING_LEN]
strEnd := strings.Index(string(b), "\x00")
@ -798,3 +1043,36 @@ func PermAddr(intf string) (string, error) {
defer e.Close()
return e.PermAddr(intf)
}
func supportedSpeeds(mask uint64) (ret []struct {
name string
mask uint64
speed uint64
}) {
for _, mode := range supportedCapabilities {
if ((1 << mode.mask) & mask) != 0 {
ret = append(ret, mode)
}
}
return ret
}
// SupportedLinkModes returns the names of the link modes supported by the interface.
func SupportedLinkModes(mask uint64) []string {
var ret []string
for _, mode := range supportedSpeeds(mask) {
ret = append(ret, mode.name)
}
return ret
}
// SupportedSpeed returns the maximum capacity of this interface.
func SupportedSpeed(mask uint64) uint64 {
var ret uint64
for _, mode := range supportedSpeeds(mask) {
if mode.speed > ret {
ret = mode.speed
}
}
return ret
}

View File

@ -83,28 +83,28 @@ func (f *EthtoolCmd) reflect(retv *map[string]uint64) {
typeField := val.Type().Field(i)
t := valueField.Interface()
//tt := reflect.TypeOf(t)
//fmt.Printf(" t %T %v tt %T %v\n", t, t, tt, tt)
switch t.(type) {
// tt := reflect.TypeOf(t)
// fmt.Printf(" t %T %v tt %T %v\n", t, t, tt, tt)
switch tt := t.(type) {
case uint32:
//fmt.Printf(" t is uint32\n")
(*retv)[typeField.Name] = uint64(t.(uint32))
// fmt.Printf(" t is uint32\n")
(*retv)[typeField.Name] = uint64(tt)
case uint16:
(*retv)[typeField.Name] = uint64(t.(uint16))
(*retv)[typeField.Name] = uint64(tt)
case uint8:
(*retv)[typeField.Name] = uint64(t.(uint8))
(*retv)[typeField.Name] = uint64(tt)
case int32:
(*retv)[typeField.Name] = uint64(t.(int32))
(*retv)[typeField.Name] = uint64(tt)
case int16:
(*retv)[typeField.Name] = uint64(t.(int16))
(*retv)[typeField.Name] = uint64(tt)
case int8:
(*retv)[typeField.Name] = uint64(t.(int8))
(*retv)[typeField.Name] = uint64(tt)
default:
(*retv)[typeField.Name+"_unknown_type"] = 0
}
//tag := typeField.Tag
//fmt.Printf("Field Name: %s,\t Field Value: %v,\t Tag Value: %s\n",
// tag := typeField.Tag
// fmt.Printf("Field Name: %s,\t Field Value: %v,\t Tag Value: %s\n",
// typeField.Name, valueField.Interface(), tag.Get("tag_name"))
}
}
@ -185,7 +185,7 @@ func (e *Ethtool) CmdGetMapped(intf string) (map[string]uint64, error) {
return nil, ep
}
var result = make(map[string]uint64)
result := make(map[string]uint64)
// ref https://gist.github.com/drewolson/4771479
// Golang Reflection Example