Skip to content

Commit 2350d2c

Browse files
Merge pull request #3102 from projectcalico/casey-fips-v3.20
Add FelixConfiguration option for FloatingIPs (#5861)
2 parents d4f9b4c + 80bc4ac commit 2350d2c

10 files changed

+208
-57
lines changed

config/config_params.go

+3
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ type Config struct {
266266
IpInIpMtu int `config:"int;0"`
267267
IpInIpTunnelAddr net.IP `config:"ipv4;"`
268268

269+
// Feature enablement. Can be either "Enabled" or "Disabled".
270+
FloatingIPs string `config:"oneof(Enabled,Disabled);Disabled"`
271+
269272
// Knobs provided to explicitly control whether we add rules to drop encap traffic
270273
// from workloads. We always add them unless explicitly requested not to add them.
271274
AllowVXLANPacketsFromWorkloads bool `config:"bool;false"`

dataplane/driver.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"os/exec"
2424
"runtime/debug"
2525
"strconv"
26+
"strings"
2627
"time"
2728

2829
log "github.com/sirupsen/logrus"
@@ -174,7 +175,7 @@ func StartDataplaneDriver(configParams *config.Config,
174175
failsafeInboundHostPorts := configParams.FailsafeInboundHostPorts
175176
failsafeOutboundHostPorts := configParams.FailsafeOutboundHostPorts
176177
if configParams.WireguardEnabled {
177-
var found = false
178+
found := false
178179
for _, i := range failsafeInboundHostPorts {
179180
if i.Port == uint16(configParams.WireguardListeningPort) && i.Protocol == "udp" {
180181
log.WithFields(log.Fields{
@@ -220,7 +221,8 @@ func StartDataplaneDriver(configParams *config.Config,
220221
}
221222

222223
dpConfig := intdataplane.Config{
223-
Hostname: configParams.FelixHostname,
224+
Hostname: configParams.FelixHostname,
225+
FloatingIPsEnabled: strings.EqualFold(configParams.FloatingIPs, string(apiv3.FloatingIPsEnabled)),
224226
IfaceMonitorConfig: ifacemonitor.Config{
225227
InterfaceExcludes: configParams.InterfaceExclude,
226228
ResyncInterval: configParams.InterfaceRefreshInterval,

dataplane/linux/endpoint_mgr.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ type endpointManager struct {
135135
ipVersion uint8
136136
wlIfacesRegexp *regexp.Regexp
137137
kubeIPVSSupportEnabled bool
138+
floatingIPsEnabled bool
138139

139140
// Our dependencies.
140141
rawTable iptablesTable
@@ -221,6 +222,7 @@ func newEndpointManager(
221222
bpfEnabled bool,
222223
bpfEndpointManager hepListener,
223224
callbacks *callbacks,
225+
floatingIPsEnabled bool,
224226
) *endpointManager {
225227
return newEndpointManagerWithShims(
226228
rawTable,
@@ -238,6 +240,7 @@ func newEndpointManager(
238240
bpfEnabled,
239241
bpfEndpointManager,
240242
callbacks,
243+
floatingIPsEnabled,
241244
)
242245
}
243246

@@ -257,6 +260,7 @@ func newEndpointManagerWithShims(
257260
bpfEnabled bool,
258261
bpfEndpointManager hepListener,
259262
callbacks *callbacks,
263+
floatingIPsEnabled bool,
260264
) *endpointManager {
261265
wlIfacesPattern := "^(" + strings.Join(wlInterfacePrefixes, "|") + ").*"
262266
wlIfacesRegexp := regexp.MustCompile(wlIfacesPattern)
@@ -267,6 +271,7 @@ func newEndpointManagerWithShims(
267271
kubeIPVSSupportEnabled: kubeIPVSSupportEnabled,
268272
bpfEnabled: bpfEnabled,
269273
bpfEndpointManager: bpfEndpointManager,
274+
floatingIPsEnabled: floatingIPsEnabled,
270275

271276
rawTable: rawTable,
272277
mangleTable: mangleTable,
@@ -387,7 +392,6 @@ func (m *endpointManager) ResolveUpdateBatch() error {
387392
}
388393

389394
func (m *endpointManager) CompleteDeferredWork() error {
390-
391395
m.resolveWorkloadEndpoints()
392396

393397
if m.hostEndpointsDirty {
@@ -626,7 +630,8 @@ func (m *endpointManager) resolveWorkloadEndpoints() {
626630
natInfos = workload.Ipv6Nat
627631
addrSuffix = "/128"
628632
}
629-
if len(natInfos) != 0 {
633+
if m.floatingIPsEnabled && len(natInfos) != 0 {
634+
// Include any floating IP NATs if the feature is enabled.
630635
old := ipStrings
631636
ipStrings = make([]string, len(old)+len(natInfos))
632637
copy(ipStrings, old)
@@ -743,7 +748,6 @@ func (m *endpointManager) resolveEndpointMarks() {
743748
}
744749

745750
func (m *endpointManager) resolveHostEndpoints() map[string]proto.HostEndpointID {
746-
747751
// Host endpoint resolution
748752
// ------------------------
749753
//
@@ -866,7 +870,6 @@ func (m *endpointManager) resolveHostEndpoints() map[string]proto.HostEndpointID
866870
}
867871

868872
func (m *endpointManager) updateHostEndpoints() {
869-
870873
// Calculate filtered name/id maps for untracked and pre-DNAT policy, and a reverse map from
871874
// each active host endpoint to the interfaces it is in use for.
872875
newIfaceNameToHostEpID := m.newIfaceNameToHostEpID

dataplane/linux/endpoint_mgr_test.go

+55-11
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@ func endpointManagerTests(ipVersion uint8) func() {
704704
false,
705705
hepListener,
706706
newCallbacks(),
707+
true,
707708
)
708709
})
709710

@@ -1416,7 +1417,6 @@ func endpointManagerTests(ipVersion uint8) func() {
14161417
}))
14171418
})
14181419
})
1419-
14201420
})
14211421

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

14721472
Describe("workload endpoints", func() {
1473-
14741473
Context("with a workload endpoint", func() {
14751474
wlEPID1 := proto.WorkloadEndpointID{
14761475
OrchestratorId: "k8s",
@@ -1514,7 +1513,6 @@ func endpointManagerTests(ipVersion uint8) func() {
15141513
It("should have expected chains", expectWlChainsFor("cali12345-ab_policy1"))
15151514

15161515
Context("with another endpoint with the same interface name and earlier workload ID, and no policy", func() {
1517-
15181516
JustBeforeEach(func() {
15191517
epMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
15201518
Id: &proto.WorkloadEndpointID{
@@ -1541,7 +1539,6 @@ func endpointManagerTests(ipVersion uint8) func() {
15411539
It("should have expected chains with no policy", expectWlChainsFor("cali12345-ab"))
15421540

15431541
Context("with the first endpoint removed", func() {
1544-
15451542
JustBeforeEach(func() {
15461543
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
15471544
Id: &wlEPID1,
@@ -1555,7 +1552,6 @@ func endpointManagerTests(ipVersion uint8) func() {
15551552
It("should have expected chains with no policy", expectWlChainsFor("cali12345-ab"))
15561553

15571554
Context("with the second endpoint removed", func() {
1558-
15591555
JustBeforeEach(func() {
15601556
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
15611557
Id: &proto.WorkloadEndpointID{
@@ -1576,7 +1572,6 @@ func endpointManagerTests(ipVersion uint8) func() {
15761572
})
15771573

15781574
Context("with another endpoint with the same interface name and later workload ID, and no policy", func() {
1579-
15801575
JustBeforeEach(func() {
15811576
epMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
15821577
Id: &proto.WorkloadEndpointID{
@@ -1603,7 +1598,6 @@ func endpointManagerTests(ipVersion uint8) func() {
16031598
It("should have expected chains", expectWlChainsFor("cali12345-ab_policy1"))
16041599

16051600
Context("with the first endpoint removed", func() {
1606-
16071601
JustBeforeEach(func() {
16081602
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
16091603
Id: &wlEPID1,
@@ -1617,7 +1611,6 @@ func endpointManagerTests(ipVersion uint8) func() {
16171611
It("should have expected chains with no policy", expectWlChainsFor("cali12345-ab"))
16181612

16191613
Context("with the second endpoint removed", func() {
1620-
16211614
JustBeforeEach(func() {
16221615
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
16231616
Id: &proto.WorkloadEndpointID{
@@ -1810,6 +1803,59 @@ func endpointManagerTests(ipVersion uint8) func() {
18101803
})
18111804
})
18121805

1806+
// Test that by disabling floatingIPs on the endpoint manager, even workload endpoints
1807+
// that have floating IP NAT addresses specified will not result in those routes being
1808+
// programmed.
1809+
Context("with floating IPs disasbled, but added to the endpoint", func() {
1810+
JustBeforeEach(func() {
1811+
epMgr.floatingIPsEnabled = false
1812+
epMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
1813+
Id: &wlEPID1,
1814+
Endpoint: &proto.WorkloadEndpoint{
1815+
State: "active",
1816+
Mac: "01:02:03:04:05:06",
1817+
Name: "cali12345-ab",
1818+
ProfileIds: []string{},
1819+
Tiers: []*proto.TierInfo{},
1820+
Ipv4Nets: []string{"10.0.240.2/24"},
1821+
Ipv6Nets: []string{"2001:db8:2::2/128"},
1822+
Ipv4Nat: []*proto.NatInfo{
1823+
{ExtIp: "172.16.1.3", IntIp: "10.0.240.2"},
1824+
{ExtIp: "172.18.1.4", IntIp: "10.0.240.2"},
1825+
},
1826+
Ipv6Nat: []*proto.NatInfo{
1827+
{ExtIp: "2001:db8:3::2", IntIp: "2001:db8:2::2"},
1828+
{ExtIp: "2001:db8:4::2", IntIp: "2001:db8:4::2"},
1829+
},
1830+
},
1831+
})
1832+
err := epMgr.ResolveUpdateBatch()
1833+
Expect(err).ToNot(HaveOccurred())
1834+
err = epMgr.CompleteDeferredWork()
1835+
Expect(err).ToNot(HaveOccurred())
1836+
})
1837+
1838+
It("should have expected chains", expectWlChainsFor("cali12345-ab"))
1839+
1840+
It("should set routes with no floating IPs", func() {
1841+
if ipVersion == 6 {
1842+
routeTable.checkRoutes("cali12345-ab", []routetable.Target{
1843+
{
1844+
CIDR: ip.MustParseCIDROrIP("2001:db8:2::2/128"),
1845+
DestMAC: testutils.MustParseMAC("01:02:03:04:05:06"),
1846+
},
1847+
})
1848+
} else {
1849+
routeTable.checkRoutes("cali12345-ab", []routetable.Target{
1850+
{
1851+
CIDR: ip.MustParseCIDROrIP("10.0.240.0/24"),
1852+
DestMAC: testutils.MustParseMAC("01:02:03:04:05:06"),
1853+
},
1854+
})
1855+
}
1856+
})
1857+
})
1858+
18131859
Context("with the endpoint removed", func() {
18141860
JustBeforeEach(func() {
18151861
epMgr.OnUpdate(&proto.WorkloadEndpointRemove{
@@ -1961,9 +2007,7 @@ type testProcSys struct {
19612007
Fail bool
19622008
}
19632009

1964-
var (
1965-
procSysFail = errors.New("mock proc sys failure")
1966-
)
2010+
var procSysFail = errors.New("mock proc sys failure")
19672011

19682012
func (t *testProcSys) write(path, value string) error {
19692013
log.WithFields(log.Fields{

dataplane/linux/floating_ip_mgr.go

+21-13
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,14 @@ type floatingIPManager struct {
7676
activeSNATChains []*iptables.Chain
7777
natInfo map[proto.WorkloadEndpointID][]*proto.NatInfo
7878
dirtyNATInfo bool
79+
enabled bool
7980
}
8081

8182
func newFloatingIPManager(
8283
natTable iptablesTable,
8384
ruleRenderer rules.RuleRenderer,
8485
ipVersion uint8,
86+
enabled bool,
8587
) *floatingIPManager {
8688
return &floatingIPManager{
8789
natTable: natTable,
@@ -92,6 +94,7 @@ func newFloatingIPManager(
9294
activeSNATChains: []*iptables.Chain{},
9395
natInfo: map[proto.WorkloadEndpointID][]*proto.NatInfo{},
9496
dirtyNATInfo: true,
97+
enabled: enabled,
9598
}
9699
}
97100

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

124-
// We shouldn't ever have the same floating IP mapping to multiple
125-
// workload IPs, but if we do we'll program the mapping to the
126-
// alphabetically earlier one.
127-
existingIntIP := dnats[natInfo.ExtIp]
128-
if existingIntIP == "" || natInfo.IntIp < existingIntIP {
129-
log.Debug("Wanted NAT mapping")
130-
dnats[natInfo.ExtIp] = natInfo.IntIp
130+
// We shouldn't ever have the same floating IP mapping to multiple
131+
// workload IPs, but if we do we'll program the mapping to the
132+
// alphabetically earlier one.
133+
existingIntIP := dnats[natInfo.ExtIp]
134+
if existingIntIP == "" || natInfo.IntIp < existingIntIP {
135+
log.Debug("Wanted NAT mapping")
136+
dnats[natInfo.ExtIp] = natInfo.IntIp
137+
}
131138
}
132139
}
133140
}
141+
134142
// Collate required SNATs as a map from internal IP to external IP.
135143
snats := map[string]string{}
136144
for extIP, intIP := range dnats {

0 commit comments

Comments
 (0)