From aa627b16c4ef19f6427cb0859b899d4c50c91eaa Mon Sep 17 00:00:00 2001 From: cyclinder Date: Wed, 3 Jul 2024 18:41:31 +0800 Subject: [PATCH] felix: ensure vxlan udp flows are not tracked in conntrack Signed-off-by: cyclinder --- felix/iptables/match_builder.go | 4 ++ felix/rules/rule_defs.go | 2 + felix/rules/static.go | 19 +++++++++ felix/rules/static_test.go | 72 +++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) diff --git a/felix/iptables/match_builder.go b/felix/iptables/match_builder.go index cd80369c06b..e330f8417f3 100644 --- a/felix/iptables/match_builder.go +++ b/felix/iptables/match_builder.go @@ -251,6 +251,10 @@ func (m MatchCriteria) DestPorts(ports ...uint16) MatchCriteria { return append(m, fmt.Sprintf("-m multiport --destination-ports %s", portsString)) } +func (m MatchCriteria) DestPort(port uint16) MatchCriteria { + return append(m, fmt.Sprintf("-dport %s", port)) +} + func (m MatchCriteria) NotDestPorts(ports ...uint16) MatchCriteria { portsString := PortsToMultiport(ports) return append(m, fmt.Sprintf("-m multiport ! --destination-ports %s", portsString)) diff --git a/felix/rules/rule_defs.go b/felix/rules/rule_defs.go index 091156e4102..0dae4acc84c 100644 --- a/felix/rules/rule_defs.go +++ b/felix/rules/rule_defs.go @@ -96,6 +96,8 @@ const ( ChainRpfSkip = ChainNamePrefix + "rpf-skip" + VXLANNoTrack = "NOTRACK" + WorkloadToEndpointPfx = ChainNamePrefix + "tw-" WorkloadPfxSpecialAllow = "ALLOW" WorkloadFromEndpointPfx = ChainNamePrefix + "fw-" diff --git a/felix/rules/static.go b/felix/rules/static.go index df78fdf32aa..18ac66c1554 100644 --- a/felix/rules/static.go +++ b/felix/rules/static.go @@ -1276,6 +1276,15 @@ func (r *DefaultRuleRenderer) StaticRawPreroutingChain(ipVersion uint8) *Chain { }) } + // ensure VXLAN UDP Flows are not tracked in conntrack + if r.VXLANEnabled { + log.Debug("Adding VXLAN NOTRACK iptables rule") + rules = append(rules, Rule{ + Match: Match().Protocol("udp").DestPort(uint16(r.VXLANPort)), + Action: JumpAction{Target: VXLANNoTrack}, + }) + } + // Set a mark on the packet if it's from a workload interface. markFromWorkload := r.IptablesMarkScratch0 for _, ifacePrefix := range r.WorkloadIfacePrefixes { @@ -1409,6 +1418,16 @@ func (r *DefaultRuleRenderer) StaticRawOutputChain(tcBypassMark uint32) *Chain { // return here without the mark bit set if the interface wasn't one that // we're policing. } + + // ensure VXLAN UDP Flows are not tracked in conntrack + if r.VXLANEnabled { + log.Debug("Adding VXLAN NOTRACK iptables rule") + rules = append(rules, Rule{ + Match: Match().Protocol("udp").DestPort(uint16(r.VXLANPort)), + Action: JumpAction{Target: VXLANNoTrack}, + }) + } + if tcBypassMark == 0 { rules = append(rules, []Rule{ {Match: Match().MarkSingleBitSet(r.IptablesMarkAccept), diff --git a/felix/rules/static_test.go b/felix/rules/static_test.go index d1645eea4c5..d01bf10aeeb 100644 --- a/felix/rules/static_test.go +++ b/felix/rules/static_test.go @@ -960,6 +960,53 @@ var _ = Describe("Static", func() { })) }) + It("IPv4: Should return expected VXLAN notrack PREROUTING chain", func() { + allCalicoMarkBits := rr.IptablesMarkAccept | + rr.IptablesMarkPass | + rr.IptablesMarkScratch0 | + rr.IptablesMarkScratch1 + Expect(rr.StaticRawPreroutingChain(4)).To(Equal([]*Chain{ + { + Name: "cali-PREROUTING", + Rules: []Rule{ + {Action: ClearMarkAction{Mark: allCalicoMarkBits}}, + {Match: Match().Protocol("udp").DestPort(uint16(rr.VXLANPort)), + Action: JumpAction{Target: VXLANNoTrack}}, + { + Match: Match().MarkMatchesWithMask(rr.IptablesMarkScratch0, rr.IptablesMarkScratch0), + Action: JumpAction{Target: ChainRpfSkip}, + }, + {Match: Match().MarkClear(rr.IptablesMarkScratch0), + Action: JumpAction{Target: ChainDispatchFromHostEndpoint}}, + {Match: Match().MarkSingleBitSet(rr.IptablesMarkAccept), + Action: AcceptAction{}}, + }, + }, + })) + }) + + It("IPv4: Should return expected VXLAN notrack OUTPUT chain", func() { + allCalicoMarkBits := rr.IptablesMarkAccept | + rr.IptablesMarkPass | + rr.IptablesMarkScratch0 | + rr.IptablesMarkScratch1 + Expect(rr.StaticRawOutputChain(0)).To(Equal([]*Chain{ + { + Name: "cali-OUTPUT", + Rules: []Rule{ + {Action: ClearMarkAction{Mark: allCalicoMarkBits}}, + {Action: JumpAction{Target: ChainDispatchToHostEndpoint}}, + {Match: Match().MarkSingleBitSet(rr.IptablesMarkAccept), + Action: AcceptAction{}}, + {Match: Match().Protocol("udp").DestPort(uint16(rr.VXLANPort)), + Action: JumpAction{Target: VXLANNoTrack}}, + {Match: Match().MarkSingleBitSet(rr.IptablesMarkAccept), + Action: AcceptAction{}}, + }, + }, + })) + }) + Describe("and IPv4 tunnel IP", func() { BeforeEach(func() { conf.VXLANTunnelAddress = net.IP{10, 0, 0, 1} @@ -1012,6 +1059,31 @@ var _ = Describe("Static", func() { })) }) + It("IPv6: Should return expected VXLAN notrack chain", func() { + allCalicoMarkBits := rr.IptablesMarkAccept | + rr.IptablesMarkPass | + rr.IptablesMarkScratch0 | + rr.IptablesMarkScratch1 + Expect(rr.StaticRawPreroutingChain(6)).To(Equal([]*Chain{ + { + Name: "cali-PREROUTING", + Rules: []Rule{ + {Action: ClearMarkAction{Mark: allCalicoMarkBits}}, + {Match: Match().Protocol("udp").DestPort(uint16(rr.VXLANPort)), + Action: JumpAction{Target: VXLANNoTrack}}, + { + Match: Match().MarkMatchesWithMask(rr.IptablesMarkScratch0, rr.IptablesMarkScratch0), + Action: JumpAction{Target: ChainRpfSkip}, + }, + {Match: Match().MarkClear(rr.IptablesMarkScratch0), + Action: JumpAction{Target: ChainDispatchFromHostEndpoint}}, + {Match: Match().MarkSingleBitSet(rr.IptablesMarkAccept), + Action: AcceptAction{}}, + }, + }, + })) + }) + Describe("and IPv6 tunnel IP", func() { BeforeEach(func() { conf.VXLANTunnelAddressV6 = net.ParseIP("dead:beef::1")