Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connectivity: Ignore expected XFRM errors #2190

Merged
merged 2 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions connectivity/check/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type Parameters struct {
ConnDisruptDispatchInterval time.Duration

ExpectedDropReasons []string
ExpectedXFRMErrors []string

FlushCT bool
SecondaryNetworkIface string
Expand Down
2 changes: 1 addition & 1 deletion connectivity/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func Run(ctx context.Context, ct *check.ConnectivityTest, addExtraTests func(*ch

ct.NewTest("no-ipsec-xfrm-errors").
WithFeatureRequirements(features.RequireMode(features.EncryptionPod, "ipsec")).
WithScenarios(tests.NoIPsecXfrmErrors())
WithScenarios(tests.NoIPsecXfrmErrors(ct.Params().ExpectedXFRMErrors))

if ct.Params().ConnDisruptTestSetup {
// Exit early, as --conn-disrupt-test-setup is only needed to deploy pods which
Expand Down
40 changes: 6 additions & 34 deletions connectivity/tests/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/cilium/cilium-cli/connectivity/check"
"github.com/cilium/cilium-cli/defaults"
"github.com/cilium/cilium-cli/utils/features"
)

// NoErrorsInLogs checks whether there are no error messages in cilium-agent
Expand Down Expand Up @@ -113,42 +114,13 @@ func (n *noUnexpectedPacketDrops) Run(ctx context.Context, t *check.Test) {

func computeExpectedDropReasons(defaultReasons, inputReasons []string) string {
filter := ""
if len(inputReasons) > 0 {
// Build final list of drop reasons based on default reasons, added
// reasons (+ prefix), and removed reasons (- prefix).
addedAllDefaults := false
dropReasons := map[string]bool{}
for _, reason := range inputReasons {
if reason[0] == '+' || reason[0] == '-' {
if !addedAllDefaults {
for _, r := range defaultReasons {
dropReasons[r] = true
}
addedAllDefaults = true
}
}
switch reason[0] {
case '+':
dropReasons[reason[1:]] = true
case '-':
dropReasons[reason[1:]] = false
default:
dropReasons[reason] = true
}
}
dropReasons := features.ComputeFailureExceptions(defaultReasons, inputReasons)

if len(dropReasons) > 0 {
// Build output string in form of '"reason1", "reason2"'.
i := 0
for reason, isIn := range dropReasons {
if !isIn {
continue
}
if i == 0 {
filter = fmt.Sprintf("%q", reason)
} else {
filter = fmt.Sprintf("%s, %q", filter, reason)
}
i++
filter = fmt.Sprintf("%q", dropReasons[0])
for _, reason := range dropReasons[1:] {
filter = fmt.Sprintf("%s, %q", filter, reason)
}
}
return filter
Expand Down
25 changes: 18 additions & 7 deletions connectivity/tests/ipsec_xfrm.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ import (
gojson "encoding/json"
"fmt"
"os"
"slices"
"sort"
"strings"

"github.com/cilium/cilium-cli/connectivity/check"
"github.com/cilium/cilium-cli/defaults"
"github.com/cilium/cilium-cli/utils/features"
)

const (
maxExpectedErrors = 10
)

type ciliumMetricsXfrmError struct {
Expand All @@ -25,11 +31,15 @@ type ciliumMetricsXfrmError struct {
Value uint64 `json:"value"`
}

func NoIPsecXfrmErrors() check.Scenario {
return &noIPsecXfrmErrors{}
func NoIPsecXfrmErrors(expectedErrors []string) check.Scenario {
return &noIPsecXfrmErrors{
features.ComputeFailureExceptions(defaults.ExpectedXFRMErrors, expectedErrors),
}
}

type noIPsecXfrmErrors struct{}
type noIPsecXfrmErrors struct {
expectedErrors []string
}

func (n *noIPsecXfrmErrors) Name() string {
return "no-ipsec-xfrm-error"
Expand All @@ -56,7 +66,6 @@ func (n *noIPsecXfrmErrors) Run(ctx context.Context, t *check.Test) {
}

func (n *noIPsecXfrmErrors) collectXfrmErrors(ctx context.Context, t *check.Test) map[string]string {

ct := t.Context()
xfrmErrors := map[string]string{}
cmd := []string{"cilium", "metrics", "list", "-ojson", "-pcilium_ipsec_xfrm_error"}
Expand All @@ -74,10 +83,12 @@ func (n *noIPsecXfrmErrors) collectXfrmErrors(ctx context.Context, t *check.Test
t.Fatalf("Unable to unmarshal cilium ipsec xfrm error metrics: %s", err)
}
for _, xfrmMetric := range xfrmMetrics {
name := fmt.Sprintf("%s_%s", xfrmMetric.Labels.Type, xfrmMetric.Labels.Error)
if slices.Contains(n.expectedErrors, name) && xfrmMetric.Value < maxExpectedErrors {
continue
}
if xfrmMetric.Value > 0 {
xErrors = append(xErrors,
fmt.Sprintf("%s_%s:%d",
xfrmMetric.Labels.Type, xfrmMetric.Labels.Error, xfrmMetric.Value))
xErrors = append(xErrors, fmt.Sprintf("%s:%d", name, xfrmMetric.Value))
}
sort.Strings(xErrors)
xfrmErrors[pod.Pod.Status.HostIP] = strings.Join(xErrors, ",")
Expand Down
5 changes: 5 additions & 0 deletions defaults/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,9 @@ var (
"Unknown L3 target address",
"No tunnel/encapsulation endpoint (datapath BUG!)",
}

ExpectedXFRMErrors = []string{
"inbound_forward_header", // XfrmFwdHdrError
"inbound_other", // XfrmInError
}
)
2 changes: 2 additions & 0 deletions internal/cli/cmd/connectivity.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ func newCmdConnectivityTest(hooks Hooks) *cobra.Command {

cmd.Flags().StringSliceVar(&params.ExpectedDropReasons, "expected-drop-reasons", defaults.ExpectedDropReasons, "List of expected drop reasons")
cmd.Flags().MarkHidden("expected-drop-reasons")
cmd.Flags().StringSliceVar(&params.ExpectedXFRMErrors, "expected-xfrm-errors", defaults.ExpectedXFRMErrors, "List of expected XFRM errors")
cmd.Flags().MarkHidden("expected-xfrm-errors")

cmd.Flags().BoolVar(&params.FlushCT, "flush-ct", false, "Flush conntrack of Cilium on each node")
cmd.Flags().MarkHidden("flush-ct")
Expand Down
43 changes: 43 additions & 0 deletions utils/features/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,46 @@ func GetIPFamily(addr string) IPFamily {

return IPFamilyAny
}

// ComputeFailureExceptions computes a list of failure exceptions for various
// tests, from a default list of exceptions and a diff given via a CLI flag.
// The diff is given as a list of exceptions, with optional leading +/- signs.
// A minus sign means the exception should be removed from the defaults; a plus
// sign means the exception should be added to the defaults. If there are
// neither minus nor plus signs, then the given exceptions are used directly
// without considering the defaults.
// See the unit tests for examples.
func ComputeFailureExceptions(defaultExceptions, inputExceptions []string) []string {
exceptions := map[string]bool{}
if len(inputExceptions) > 0 {
// Build final list of failure exceptions based on default exceptions,
// added exceptions (+ prefix), and removed exceptions (- prefix).
addedAllDefaults := false
for _, exception := range inputExceptions {
if exception[0] == '+' || exception[0] == '-' {
if !addedAllDefaults {
for _, r := range defaultExceptions {
exceptions[r] = true
}
addedAllDefaults = true
}
}
switch exception[0] {
case '+':
exceptions[exception[1:]] = true
case '-':
exceptions[exception[1:]] = false
default:
exceptions[exception] = true
}
}
}

exceptionList := []string{}
for exception, isIn := range exceptions {
if isIn {
exceptionList = append(exceptionList, exception)
}
}
return exceptionList
}
58 changes: 58 additions & 0 deletions utils/features/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package features

import (
"fmt"
"reflect"
"sort"
"testing"
)

func TestComputeFailureExceptions(t *testing.T) {
defaultExceptions := []string{"reason0", "reason1"}
tests := []struct {
inputExceptions []string
expectedExceptions []string
}{
// Empty list of reasons.
{
inputExceptions: []string{},
expectedExceptions: []string{},
},
// Add a reason to default list.
{
inputExceptions: []string{"+reason2"},
expectedExceptions: []string{"reason0", "reason1", "reason2"},
},
// Remove a reason from default list.
{
inputExceptions: []string{"-reason1"},
expectedExceptions: []string{"reason0"},
},
// Add a reason then remove it.
{
inputExceptions: []string{"+reason2", "-reason2"},
expectedExceptions: []string{"reason0", "reason1"},
},
// Remove a reason then add it back.
{
inputExceptions: []string{"-reason1", "+reason1"},
expectedExceptions: []string{"reason0", "reason1"},
},
}

for _, test := range tests {
t.Run(fmt.Sprintf("InputExceptions: %v", test.inputExceptions), func(t *testing.T) {
result := ComputeFailureExceptions(defaultExceptions, test.inputExceptions)

// computeFailureExceptions doesn't guarantee the order of the
// returned slice so we have to sort both slices.
sort.Strings(result)
if !reflect.DeepEqual(result, test.expectedExceptions) {
t.Errorf("Expected exceptions to be %v, but got: %v", test.expectedExceptions, result)
}
})
}
}