Skip to content

Commit

Permalink
Add FelixConfiguration option for FloatingIPs (#5861)
Browse files Browse the repository at this point in the history
  • Loading branch information
caseydavenport committed Apr 11, 2022
1 parent d4f9b4c commit 80bc4ac
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 57 deletions.
3 changes: 3 additions & 0 deletions config/config_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ type Config struct {
IpInIpMtu int `config:"int;0"`
IpInIpTunnelAddr net.IP `config:"ipv4;"`

// Feature enablement. Can be either "Enabled" or "Disabled".
FloatingIPs string `config:"oneof(Enabled,Disabled);Disabled"`

// Knobs provided to explicitly control whether we add rules to drop encap traffic
// from workloads. We always add them unless explicitly requested not to add them.
AllowVXLANPacketsFromWorkloads bool `config:"bool;false"`
Expand Down
6 changes: 4 additions & 2 deletions dataplane/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"os/exec"
"runtime/debug"
"strconv"
"strings"
"time"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -174,7 +175,7 @@ func StartDataplaneDriver(configParams *config.Config,
failsafeInboundHostPorts := configParams.FailsafeInboundHostPorts
failsafeOutboundHostPorts := configParams.FailsafeOutboundHostPorts
if configParams.WireguardEnabled {
var found = false
found := false
for _, i := range failsafeInboundHostPorts {
if i.Port == uint16(configParams.WireguardListeningPort) && i.Protocol == "udp" {
log.WithFields(log.Fields{
Expand Down Expand Up @@ -220,7 +221,8 @@ func StartDataplaneDriver(configParams *config.Config,
}

dpConfig := intdataplane.Config{
Hostname: configParams.FelixHostname,
Hostname: configParams.FelixHostname,
FloatingIPsEnabled: strings.EqualFold(configParams.FloatingIPs, string(apiv3.FloatingIPsEnabled)),
IfaceMonitorConfig: ifacemonitor.Config{
InterfaceExcludes: configParams.InterfaceExclude,
ResyncInterval: configParams.InterfaceRefreshInterval,
Expand Down
11 changes: 7 additions & 4 deletions dataplane/linux/endpoint_mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ type endpointManager struct {
ipVersion uint8
wlIfacesRegexp *regexp.Regexp
kubeIPVSSupportEnabled bool
floatingIPsEnabled bool

// Our dependencies.
rawTable iptablesTable
Expand Down Expand Up @@ -221,6 +222,7 @@ func newEndpointManager(
bpfEnabled bool,
bpfEndpointManager hepListener,
callbacks *callbacks,
floatingIPsEnabled bool,
) *endpointManager {
return newEndpointManagerWithShims(
rawTable,
Expand All @@ -238,6 +240,7 @@ func newEndpointManager(
bpfEnabled,
bpfEndpointManager,
callbacks,
floatingIPsEnabled,
)
}

Expand All @@ -257,6 +260,7 @@ func newEndpointManagerWithShims(
bpfEnabled bool,
bpfEndpointManager hepListener,
callbacks *callbacks,
floatingIPsEnabled bool,
) *endpointManager {
wlIfacesPattern := "^(" + strings.Join(wlInterfacePrefixes, "|") + ").*"
wlIfacesRegexp := regexp.MustCompile(wlIfacesPattern)
Expand All @@ -267,6 +271,7 @@ func newEndpointManagerWithShims(
kubeIPVSSupportEnabled: kubeIPVSSupportEnabled,
bpfEnabled: bpfEnabled,
bpfEndpointManager: bpfEndpointManager,
floatingIPsEnabled: floatingIPsEnabled,

rawTable: rawTable,
mangleTable: mangleTable,
Expand Down Expand Up @@ -387,7 +392,6 @@ func (m *endpointManager) ResolveUpdateBatch() error {
}

func (m *endpointManager) CompleteDeferredWork() error {

m.resolveWorkloadEndpoints()

if m.hostEndpointsDirty {
Expand Down Expand Up @@ -626,7 +630,8 @@ func (m *endpointManager) resolveWorkloadEndpoints() {
natInfos = workload.Ipv6Nat
addrSuffix = "/128"
}
if len(natInfos) != 0 {
if m.floatingIPsEnabled && len(natInfos) != 0 {
// Include any floating IP NATs if the feature is enabled.
old := ipStrings
ipStrings = make([]string, len(old)+len(natInfos))
copy(ipStrings, old)
Expand Down Expand Up @@ -743,7 +748,6 @@ func (m *endpointManager) resolveEndpointMarks() {
}

func (m *endpointManager) resolveHostEndpoints() map[string]proto.HostEndpointID {

// Host endpoint resolution
// ------------------------
//
Expand Down Expand Up @@ -866,7 +870,6 @@ func (m *endpointManager) resolveHostEndpoints() map[string]proto.HostEndpointID
}

func (m *endpointManager) updateHostEndpoints() {

// Calculate filtered name/id maps for untracked and pre-DNAT policy, and a reverse map from
// each active host endpoint to the interfaces it is in use for.
newIfaceNameToHostEpID := m.newIfaceNameToHostEpID
Expand Down
66 changes: 55 additions & 11 deletions dataplane/linux/endpoint_mgr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,7 @@ func endpointManagerTests(ipVersion uint8) func() {
false,
hepListener,
newCallbacks(),
true,
)
})

Expand Down Expand Up @@ -1416,7 +1417,6 @@ func endpointManagerTests(ipVersion uint8) func() {
}))
})
})

})

Context("with host endpoint configured before interface signaled", func() {
Expand Down Expand Up @@ -1470,7 +1470,6 @@ func endpointManagerTests(ipVersion uint8) func() {
}

Describe("workload endpoints", func() {

Context("with a workload endpoint", func() {
wlEPID1 := proto.WorkloadEndpointID{
OrchestratorId: "k8s",
Expand Down Expand Up @@ -1514,7 +1513,6 @@ func endpointManagerTests(ipVersion uint8) func() {
It("should have expected chains", expectWlChainsFor("cali12345-ab_policy1"))

Context("with another endpoint with the same interface name and earlier workload ID, and no policy", func() {

JustBeforeEach(func() {
epMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
Id: &proto.WorkloadEndpointID{
Expand All @@ -1541,7 +1539,6 @@ func endpointManagerTests(ipVersion uint8) func() {
It("should have expected chains with no policy", expectWlChainsFor("cali12345-ab"))

Context("with the first endpoint removed", func() {

JustBeforeEach(func() {
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
Id: &wlEPID1,
Expand All @@ -1555,7 +1552,6 @@ func endpointManagerTests(ipVersion uint8) func() {
It("should have expected chains with no policy", expectWlChainsFor("cali12345-ab"))

Context("with the second endpoint removed", func() {

JustBeforeEach(func() {
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
Id: &proto.WorkloadEndpointID{
Expand All @@ -1576,7 +1572,6 @@ func endpointManagerTests(ipVersion uint8) func() {
})

Context("with another endpoint with the same interface name and later workload ID, and no policy", func() {

JustBeforeEach(func() {
epMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
Id: &proto.WorkloadEndpointID{
Expand All @@ -1603,7 +1598,6 @@ func endpointManagerTests(ipVersion uint8) func() {
It("should have expected chains", expectWlChainsFor("cali12345-ab_policy1"))

Context("with the first endpoint removed", func() {

JustBeforeEach(func() {
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
Id: &wlEPID1,
Expand All @@ -1617,7 +1611,6 @@ func endpointManagerTests(ipVersion uint8) func() {
It("should have expected chains with no policy", expectWlChainsFor("cali12345-ab"))

Context("with the second endpoint removed", func() {

JustBeforeEach(func() {
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
Id: &proto.WorkloadEndpointID{
Expand Down Expand Up @@ -1810,6 +1803,59 @@ func endpointManagerTests(ipVersion uint8) func() {
})
})

// Test that by disabling floatingIPs on the endpoint manager, even workload endpoints
// that have floating IP NAT addresses specified will not result in those routes being
// programmed.
Context("with floating IPs disasbled, but added to the endpoint", func() {
JustBeforeEach(func() {
epMgr.floatingIPsEnabled = false
epMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
Id: &wlEPID1,
Endpoint: &proto.WorkloadEndpoint{
State: "active",
Mac: "01:02:03:04:05:06",
Name: "cali12345-ab",
ProfileIds: []string{},
Tiers: []*proto.TierInfo{},
Ipv4Nets: []string{"10.0.240.2/24"},
Ipv6Nets: []string{"2001:db8:2::2/128"},
Ipv4Nat: []*proto.NatInfo{
{ExtIp: "172.16.1.3", IntIp: "10.0.240.2"},
{ExtIp: "172.18.1.4", IntIp: "10.0.240.2"},
},
Ipv6Nat: []*proto.NatInfo{
{ExtIp: "2001:db8:3::2", IntIp: "2001:db8:2::2"},
{ExtIp: "2001:db8:4::2", IntIp: "2001:db8:4::2"},
},
},
})
err := epMgr.ResolveUpdateBatch()
Expect(err).ToNot(HaveOccurred())
err = epMgr.CompleteDeferredWork()
Expect(err).ToNot(HaveOccurred())
})

It("should have expected chains", expectWlChainsFor("cali12345-ab"))

It("should set routes with no floating IPs", func() {
if ipVersion == 6 {
routeTable.checkRoutes("cali12345-ab", []routetable.Target{
{
CIDR: ip.MustParseCIDROrIP("2001:db8:2::2/128"),
DestMAC: testutils.MustParseMAC("01:02:03:04:05:06"),
},
})
} else {
routeTable.checkRoutes("cali12345-ab", []routetable.Target{
{
CIDR: ip.MustParseCIDROrIP("10.0.240.0/24"),
DestMAC: testutils.MustParseMAC("01:02:03:04:05:06"),
},
})
}
})
})

Context("with the endpoint removed", func() {
JustBeforeEach(func() {
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
Expand Down Expand Up @@ -1961,9 +2007,7 @@ type testProcSys struct {
Fail bool
}

var (
procSysFail = errors.New("mock proc sys failure")
)
var procSysFail = errors.New("mock proc sys failure")

func (t *testProcSys) write(path, value string) error {
log.WithFields(log.Fields{
Expand Down
34 changes: 21 additions & 13 deletions dataplane/linux/floating_ip_mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,14 @@ type floatingIPManager struct {
activeSNATChains []*iptables.Chain
natInfo map[proto.WorkloadEndpointID][]*proto.NatInfo
dirtyNATInfo bool
enabled bool
}

func newFloatingIPManager(
natTable iptablesTable,
ruleRenderer rules.RuleRenderer,
ipVersion uint8,
enabled bool,
) *floatingIPManager {
return &floatingIPManager{
natTable: natTable,
Expand All @@ -92,6 +94,7 @@ func newFloatingIPManager(
activeSNATChains: []*iptables.Chain{},
natInfo: map[proto.WorkloadEndpointID][]*proto.NatInfo{},
dirtyNATInfo: true,
enabled: enabled,
}
}

Expand All @@ -114,23 +117,28 @@ func (m *floatingIPManager) CompleteDeferredWork() error {
if m.dirtyNATInfo {
// Collate required DNATs as a map from external IP to internal IP.
dnats := map[string]string{}
for _, natInfos := range m.natInfo {
for _, natInfo := range natInfos {
log.WithFields(log.Fields{
"ExtIP": natInfo.ExtIp,
"IntIP": natInfo.IntIp,
}).Debug("NAT mapping")
if m.enabled {
// We only perform nat if the feature is explicitly enabled, otherwise
// we will simply remove any programmed floating IP NAT fules.
for _, natInfos := range m.natInfo {
for _, natInfo := range natInfos {
log.WithFields(log.Fields{
"ExtIP": natInfo.ExtIp,
"IntIP": natInfo.IntIp,
}).Debug("NAT mapping")

// We shouldn't ever have the same floating IP mapping to multiple
// workload IPs, but if we do we'll program the mapping to the
// alphabetically earlier one.
existingIntIP := dnats[natInfo.ExtIp]
if existingIntIP == "" || natInfo.IntIp < existingIntIP {
log.Debug("Wanted NAT mapping")
dnats[natInfo.ExtIp] = natInfo.IntIp
// We shouldn't ever have the same floating IP mapping to multiple
// workload IPs, but if we do we'll program the mapping to the
// alphabetically earlier one.
existingIntIP := dnats[natInfo.ExtIp]
if existingIntIP == "" || natInfo.IntIp < existingIntIP {
log.Debug("Wanted NAT mapping")
dnats[natInfo.ExtIp] = natInfo.IntIp
}
}
}
}

// Collate required SNATs as a map from internal IP to external IP.
snats := map[string]string{}
for extIP, intIP := range dnats {
Expand Down
Loading

0 comments on commit 80bc4ac

Please sign in to comment.