Skip to content
Open
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
5 changes: 4 additions & 1 deletion felix/calc/l3_route_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,11 @@ func (c *L3RouteResolver) flush() {
rt.Borrowed = true
}
if ri.Refs[0].RefType == RefTypeWEP {
// This is not a tunnel ref, so must be a workload.
// This is explicitly a workload endpoint.
if ri.Refs[0].NodeName == c.myNodeName {
// Flag that there's a live WEP on this IP; this avoids
// confusion in the dataplane if we have borrowed IPs
// (which get flagged as both local and remote!).
rt.LocalWorkload = true
rt.Types |= proto.RouteType_LOCAL_WORKLOAD
} else {
Expand Down
12 changes: 7 additions & 5 deletions felix/dataplane/linux/bpf_route_mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,8 @@ func (m *bpfRouteManager) calculateRoute(cidr ip.CIDR) routes.ValueInterface {
}
nodeIP := net.ParseIP(cgRoute.DstNodeIp)
route = m.bpfOps.NewValueWithNextHop(flags, ip.FromNetIP(nodeIP))
} else if rts&proto.RouteType_LOCAL_WORKLOAD == proto.RouteType_LOCAL_WORKLOAD && !cgRoute.Borrowed /* not ours */ {
if !cgRoute.LocalWorkload {
// Just the local IPAM block, not an actual workload.
return nil
}
} else if cgRoute.GetLocalWorkload() {
// Explicitly a local WorkloadEndpoint /32.
if wepIDs, ok := m.cidrToWEPIDs[cidr]; ok {
bestWepScore := -1
var bestWepID *proto.WorkloadEndpointID
Expand Down Expand Up @@ -389,6 +386,7 @@ func (m *bpfRouteManager) calculateRoute(cidr ip.CIDR) routes.ValueInterface {
// hostname.
flags |= routes.FlagsLocalHost
} else if rts&proto.RouteType_REMOTE_WORKLOAD == proto.RouteType_REMOTE_WORKLOAD {
// Either a remote IPAM block or a remote workload with a borrowed IP.
flags |= routes.FlagsRemoteWorkload
if m.wgEnabled {
flags |= routes.FlagTunneled
Expand All @@ -406,6 +404,10 @@ func (m *bpfRouteManager) calculateRoute(cidr ip.CIDR) routes.ValueInterface {
}
nodeIP := net.ParseIP(cgRoute.DstNodeIp)
route = m.bpfOps.NewValueWithNextHop(flags, ip.FromNetIP(nodeIP))
} else if rts&proto.RouteType_LOCAL_WORKLOAD == proto.RouteType_LOCAL_WORKLOAD {
// Local IPAM block. We don't need to have a map entry for that right
// now.
return nil
}

if route == nil && flags != 0 {
Expand Down
66 changes: 64 additions & 2 deletions felix/fv/routing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ cluster routing using Felix
routeSource := testConfig.RouteSource
brokenXSum := testConfig.BrokenXSum
enableIPv6 := testConfig.EnableIPv6
description := fmt.Sprintf("with topology set to IPIPMode %s, routeSource %s, brokenXSum: %v, enableIPv6: %v", ipipMode, routeSource, brokenXSum, enableIPv6)

Describe(fmt.Sprintf("with topology set to IPIPMode %s, routeSource %s, brokenXSum: %v, enableIPv6: %v", ipipMode, routeSource, brokenXSum, enableIPv6), func() {
Describe(description, func() {
var (
infra infrastructure.DatastoreInfra
tc infrastructure.TopologyContainers
Expand Down Expand Up @@ -893,7 +894,68 @@ var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ cluster routing using Felix
})
})

Describe("with a borrowed tunnel IP on one host", func() {
Describe(description+" and borrowed workload IPs", func() {
var (
infra infrastructure.DatastoreInfra
tc infrastructure.TopologyContainers
felixes []*infrastructure.Felix
client client.Interface
w [3]*workload.Workload
w6 [3]*workload.Workload
cc *connectivity.Checker
topologyOptions infrastructure.TopologyOptions
timeout = time.Second * 30
)

BeforeEach(func() {
infra = getInfra()

if (NFTMode() || BPFMode()) && getDataStoreType(infra) == "etcdv3" {
Skip("Skipping NFT / BPF tests for etcdv3 backend.")
}

topologyOptions = createIPIPBaseTopologyOptions(ipipMode, enableIPv6, routeSource, brokenXSum)

cc = &connectivity.Checker{}

// Deploy the topology.
tc, client = infrastructure.StartNNodeTopology(3, topologyOptions, infra)

// Assign tunnel addresses in IPAM based on the topology.
// This will assign blocks to particular nodes so that the
// workload IP assignments below will borrow.
assignTunnelAddresses(infra, tc, client)

// Offset of +1 means that felix[0]'s workload borrows its IP from
// felix[1]'s block and so on.
w, w6, _, _ = setupWorkloadsWithOffset(infra, tc, topologyOptions, client, enableIPv6, 1)
felixes = tc.Felixes
})

It("should have connectivity", func() {
if !ipipTunnelSupported(ipipMode, routeSource) {
Skip("Skipping due to known issue with tunnel IPs not being programmed in WEP mode")
}

for i := 0; i < 3; i++ {
f := felixes[i]
cc.ExpectSome(f, w[i]) // Host to local workload.
cc.ExpectSome(f, w[(i+1)%3]) // Host to next node's workload
cc.ExpectSome(w[i], w[(i+1)%3]) // Local workload to next node's workload.

if enableIPv6 {
cc.ExpectSome(f, w6[i])
cc.ExpectSome(f, w6[(i+1)%3])
cc.ExpectSome(w6[i], w6[(i+1)%3])
}

}

cc.CheckConnectivityWithTimeout(timeout)
})
})

Describe(description+" and a borrowed tunnel IP on one host", func() {
var (
infra infrastructure.DatastoreInfra
tc infrastructure.TopologyContainers
Expand Down
5 changes: 3 additions & 2 deletions felix/routetable/routeclass_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.