Skip to content

Commit

Permalink
Add FV test for borrowed VXLAN tunnel IP
Browse files Browse the repository at this point in the history
  • Loading branch information
caseydavenport committed Jan 10, 2025
1 parent 0112791 commit 0f78f7e
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 49 deletions.
2 changes: 1 addition & 1 deletion felix/dataplane/linux/vxlan_mgr.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016-2021 Tigera, Inc. All rights reserved.
// Copyright (c) 2016-2025 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
26 changes: 14 additions & 12 deletions felix/fv/connectivity/conncheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,14 @@ func (c *Checker) ExpectNone(from ConnectionSource, to ConnectionTarget, explici
// and ConnectionTarget with details configurable with ExpectationOption(s).
// This is a super set of ExpectSome()
func (c *Checker) Expect(expected Expected,
from ConnectionSource, to ConnectionTarget, opts ...ExpectationOption) {

from ConnectionSource, to ConnectionTarget, opts ...ExpectationOption,
) {
c.expect(expected, from, to, opts...)
}

func (c *Checker) ExpectLoss(from ConnectionSource, to ConnectionTarget,
duration time.Duration, maxPacketLossPercent float64, maxPacketLossNumber int, explicitPort ...uint16) {

duration time.Duration, maxPacketLossPercent float64, maxPacketLossNumber int, explicitPort ...uint16,
) {
// Packet loss measurements shouldn't be retried.
c.RetriesDisabled = true

Expand All @@ -140,8 +140,8 @@ func (c *Checker) ExpectLoss(from ConnectionSource, to ConnectionTarget,
}

func (c *Checker) expect(expected Expected, from ConnectionSource, to ConnectionTarget,
opts ...ExpectationOption) {

opts ...ExpectationOption,
) {
UnactivatedCheckers.Add(c)
if c.ReverseDirection {
from, to = to.(ConnectionSource), from.(ConnectionTarget)
Expand Down Expand Up @@ -683,7 +683,6 @@ func (e Expectation) Matches(response *Result, checkSNAT bool) bool {
return false
}
}

}

return true
Expand Down Expand Up @@ -766,7 +765,8 @@ func (cmd *CheckCmd) run(cName string, logMsg string) *Result {
logCxt.Debugf("Entering connectivity.Check(%v,%v,%v,%v,%v)",
cmd.ip, cmd.port, cmd.protocol, cmd.sendLen, cmd.recvLen)

args := []string{"exec", cName,
args := []string{
"exec", cName,
"test-connection", "--protocol=" + cmd.protocol,
fmt.Sprintf("--duration=%d", int(cmd.duration.Seconds())),
fmt.Sprintf("--sendlen=%d", cmd.sendLen),
Expand Down Expand Up @@ -816,7 +816,8 @@ func (cmd *CheckCmd) run(cName string, logMsg string) *Result {
err = connectionCmd.Wait()
logCxt.WithFields(log.Fields{
"stdout": string(wOut),
"stderr": string(wErr)}).WithError(err).Info(logMsg)
"stderr": string(wErr),
}).WithError(err).Info(logMsg)

var resp Result
r := regexp.MustCompile(`RESULT=(.*)\n`)
Expand Down Expand Up @@ -878,7 +879,6 @@ func WithTimeout(t time.Duration) CheckOption {

// Check executes the connectivity check
func Check(cName, logMsg, ip, port, protocol string, opts ...CheckOption) *Result {

const defaultPingTimeout = 2 * time.Second
cmd := CheckCmd{
nsPath: "-",
Expand All @@ -895,8 +895,10 @@ func Check(cName, logMsg, ip, port, protocol string, opts ...CheckOption) *Resul
return cmd.run(cName, logMsg)
}

const ConnectionTypeStream = "stream"
const ConnectionTypePing = "ping"
const (
ConnectionTypeStream = "stream"
ConnectionTypePing = "ping"
)

type ConnConfig struct {
ConnType string
Expand Down
14 changes: 5 additions & 9 deletions felix/fv/infrastructure/infra_etcd.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018-2021 Tigera, Inc. All rights reserved.
// Copyright (c) 2018-2025 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -115,16 +115,12 @@ func (eds *EtcdDatastoreInfra) SetExpectedIPIPTunnelAddr(felix *Felix, cidr *net
}
}

func (eds *EtcdDatastoreInfra) SetExpectedVXLANTunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needBGP bool) {
if needBGP {
felix.ExpectedVXLANTunnelAddr = fmt.Sprintf("%d.%d.%d.0", cidr.IP[0], cidr.IP[1], idx)
}
func (eds *EtcdDatastoreInfra) SetExpectedVXLANTunnelAddr(felix *Felix, ip string) {
felix.ExpectedVXLANTunnelAddr = ip
}

func (eds *EtcdDatastoreInfra) SetExpectedVXLANV6TunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needBGP bool) {
if needBGP {
felix.ExpectedVXLANV6TunnelAddr = fmt.Sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%d:0", cidr.IP[0], cidr.IP[1], cidr.IP[2], cidr.IP[3], cidr.IP[4], cidr.IP[5], cidr.IP[6], cidr.IP[7], cidr.IP[8], cidr.IP[9], cidr.IP[10], cidr.IP[11], idx)
}
func (eds *EtcdDatastoreInfra) SetExpectedVXLANV6TunnelAddr(felix *Felix, ip string) {
felix.ExpectedVXLANV6TunnelAddr = ip
}

func (eds *EtcdDatastoreInfra) SetExpectedWireguardTunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needWireguard bool) {
Expand Down
16 changes: 7 additions & 9 deletions felix/fv/infrastructure/infra_k8s.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018-2024 Tigera, Inc. All rights reserved.
// Copyright (c) 2018-2025 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -639,16 +639,14 @@ func (kds *K8sDatastoreInfra) SetExpectedIPIPTunnelAddr(felix *Felix, cidr *net.
felix.ExtraSourceIPs = append(felix.ExtraSourceIPs, felix.ExpectedIPIPTunnelAddr)
}

func (kds *K8sDatastoreInfra) SetExpectedVXLANTunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needBGP bool) {
felix.ExpectedVXLANTunnelAddr = fmt.Sprintf("%d.%d.%d.0", cidr.IP[0], cidr.IP[1], idx)
felix.ExtraSourceIPs = append(felix.ExtraSourceIPs, felix.ExpectedVXLANTunnelAddr)
func (kds *K8sDatastoreInfra) SetExpectedVXLANTunnelAddr(felix *Felix, ip string) {
felix.ExpectedVXLANTunnelAddr = ip
felix.ExtraSourceIPs = append(felix.ExtraSourceIPs, ip)
}

func (kds *K8sDatastoreInfra) SetExpectedVXLANV6TunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needBGP bool) {
felix.ExpectedVXLANV6TunnelAddr = net.ParseIP(fmt.Sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%d:0",
cidr.IP[0], cidr.IP[1], cidr.IP[2], cidr.IP[3], cidr.IP[4], cidr.IP[5], cidr.IP[6],
cidr.IP[7], cidr.IP[8], cidr.IP[9], cidr.IP[10], cidr.IP[11], idx)).String()
felix.ExtraSourceIPs = append(felix.ExtraSourceIPs, felix.ExpectedVXLANV6TunnelAddr)
func (kds *K8sDatastoreInfra) SetExpectedVXLANV6TunnelAddr(felix *Felix, ip string) {
felix.ExpectedVXLANV6TunnelAddr = ip
felix.ExtraSourceIPs = append(felix.ExtraSourceIPs, ip)
}

func (kds *K8sDatastoreInfra) SetExpectedWireguardTunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needWg bool) {
Expand Down
4 changes: 2 additions & 2 deletions felix/fv/infrastructure/infrastructure.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ type DatastoreInfra interface {
// SetExpectedVXLANTunnelAddr will set the Felix object's
// ExpectedVXLANTunnelAddr field, if we expect Felix to see that field being
// set after it has started up for the first time.
SetExpectedVXLANTunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needVXLAN bool)
SetExpectedVXLANV6TunnelAddr(felix *Felix, cidr *net.IPNet, idx int, needVXLAN bool)
SetExpectedVXLANTunnelAddr(felix *Felix, ip string)
SetExpectedVXLANV6TunnelAddr(felix *Felix, ip string)
// SetExpectedWireguardTunnelAddr will set the Felix object's
// ExpectedWireguardTunnelAddr field, if we expect Felix to see that field being
// set after it has started up for the first time.
Expand Down
8 changes: 5 additions & 3 deletions felix/fv/infrastructure/topology.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2017-2022 Tigera, Inc. All rights reserved.
// Copyright (c) 2017-2025 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -53,6 +53,7 @@ type TopologyOptions struct {
IPIPEnabled bool
IPIPRoutesEnabled bool
VXLANMode api.VXLANMode
VXLANStrategy VXLANStrategy
WireguardEnabled bool
WireguardEnabledV6 bool
InitialFelixConfiguration *api.FelixConfiguration
Expand Down Expand Up @@ -334,6 +335,7 @@ func StartNNodeTopology(
Expect(err).To(BeNil())
_, IPv6CIDR, err := net.ParseCIDR(opts.IPv6PoolCIDR)
Expect(err).To(BeNil())

for i := 0; i < n; i++ {
opts.ExtraEnvVars["BPF_LOG_PFX"] = ""
felix := tc.Felixes[i]
Expand All @@ -358,11 +360,11 @@ func StartNNodeTopology(
expectedIPs = append(expectedIPs, felix.ExpectedIPIPTunnelAddr)
}
if opts.VXLANMode != api.VXLANModeNever {
infra.SetExpectedVXLANTunnelAddr(felix, IPv4CIDR, i, n > 1)
infra.SetExpectedVXLANTunnelAddr(felix, opts.VXLANStrategy.TunnelAddress(i))
expectedIPs = append(expectedIPs, felix.ExpectedVXLANTunnelAddr)
if opts.EnableIPv6 {
expectedIPs = append(expectedIPs, felix.IPv6)
infra.SetExpectedVXLANV6TunnelAddr(felix, IPv6CIDR, i, n > 1)
infra.SetExpectedVXLANV6TunnelAddr(felix, opts.VXLANStrategy.TunnelAddressV6(i))
expectedIPs = append(expectedIPs, felix.ExpectedVXLANV6TunnelAddr)
}
}
Expand Down
101 changes: 101 additions & 0 deletions felix/fv/infrastructure/vxlan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright (c) 2025 Tigera, Inc. All rights reserved.
//
// 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 infrastructure

import (
"fmt"
"net"

. "github.com/onsi/gomega"
)

// VXLANStrategy is a strategy for assigning VXLAN configuration to a topology.
type VXLANStrategy interface {
// Returns the tunnel address to use for the Felix with the given index.
TunnelAddress(i int) string
TunnelAddressV6(i int) string
}

// defaultVXLANStrategy implements VXLANStrategy, assigning a block to each Felix.
type defaultVXLANStrategy struct {
v4Pool *net.IPNet
v6Pool *net.IPNet
}

func NewDefaultVXLANStrategy(v4Pool, v6Pool string) VXLANStrategy {
_, v4cidr, err := net.ParseCIDR(v4Pool)
Expect(err).To(BeNil())
_, v6cidr, err := net.ParseCIDR(v6Pool)
Expect(err).To(BeNil())

return &defaultVXLANStrategy{
v4Pool: v4cidr,
v6Pool: v6cidr,
}
}

func (s *defaultVXLANStrategy) TunnelAddress(i int) string {
return fmt.Sprintf("%d.%d.%d.0", s.v4Pool.IP[0], s.v4Pool.IP[1], i)
}

func (s *defaultVXLANStrategy) TunnelAddressV6(i int) string {
cidr := s.v6Pool
return net.ParseIP(fmt.Sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%d:0",
cidr.IP[0], cidr.IP[1], cidr.IP[2], cidr.IP[3], cidr.IP[4], cidr.IP[5], cidr.IP[6],
cidr.IP[7], cidr.IP[8], cidr.IP[9], cidr.IP[10], cidr.IP[11], i)).String()
}

// borrowedVXLANStrategy is a strategy for assigning VXLAN configuration to a topology
// where one node borrows its tunnel address from the IPAM block of another.
type borrowedIPVXLANStrategy struct {
v4Pool *net.IPNet
v6Pool *net.IPNet
numFelixes int
}

func NewBorrowedIPVXLANStrategy(v4Pool, v6Pool string, numFelixes int) VXLANStrategy {
_, v4cidr, err := net.ParseCIDR(v4Pool)
Expect(err).To(BeNil())
_, v6cidr, err := net.ParseCIDR(v6Pool)
Expect(err).To(BeNil())

return &borrowedIPVXLANStrategy{
v4Pool: v4cidr,
v6Pool: v6cidr,
numFelixes: numFelixes,
}
}

func (s *borrowedIPVXLANStrategy) TunnelAddress(i int) string {
if i == s.numFelixes-1 {
// For most nodes, use the first IP of the block. However, for the last node,
// we borrow its IP from the first node's block.
return fmt.Sprintf("%d.%d.%d.1", s.v4Pool.IP[0], s.v4Pool.IP[1], 0)
}
return fmt.Sprintf("%d.%d.%d.0", s.v4Pool.IP[0], s.v4Pool.IP[1], i)
}

func (s *borrowedIPVXLANStrategy) TunnelAddressV6(i int) string {
cidr := s.v6Pool
if i == s.numFelixes-1 {
// For most nodes, use the first IP of the block. However, for the last node,
// we borrow its IP from the first node's block.
return net.ParseIP(fmt.Sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%d:1",
cidr.IP[0], cidr.IP[1], cidr.IP[2], cidr.IP[3], cidr.IP[4], cidr.IP[5], cidr.IP[6],
cidr.IP[7], cidr.IP[8], cidr.IP[9], cidr.IP[10], cidr.IP[11], 0)).String()
}
return net.ParseIP(fmt.Sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%d:0",
cidr.IP[0], cidr.IP[1], cidr.IP[2], cidr.IP[3], cidr.IP[4], cidr.IP[5], cidr.IP[6],
cidr.IP[7], cidr.IP[8], cidr.IP[9], cidr.IP[10], cidr.IP[11], i)).String()
}
Loading

0 comments on commit 0f78f7e

Please sign in to comment.