From fe77f9fc14ee823d3f1ac89274b7e328a6e980ff 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/static.go | 21 ++++++++++ felix/rules/static_test.go | 73 +++++++++++++++++++++++++++++++++ 3 files changed, 98 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/static.go b/felix/rules/static.go index df78fdf32aa..9f883d5c4ef 100644 --- a/felix/rules/static.go +++ b/felix/rules/static.go @@ -1276,6 +1276,17 @@ func (r *DefaultRuleRenderer) StaticRawPreroutingChain(ipVersion uint8) *Chain { }) } + // Ensure VXLAN UDP Flows are not tracked in conntrack. + // VXLAN uses different source ports in each direction so + // tracking results in unreplied flows. + if r.VXLANEnabled { + log.Debug("Adding VXLAN NOTRACK iptables rule to PREROUTING chain") + rules = append(rules, Rule{ + Match: Match().Protocol("udp").DestPort(uint16(r.VXLANPort)), + Action: NoTrackAction{}, + }) + } + // Set a mark on the packet if it's from a workload interface. markFromWorkload := r.IptablesMarkScratch0 for _, ifacePrefix := range r.WorkloadIfacePrefixes { @@ -1409,6 +1420,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: NoTrackAction{}, + }) + } + 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..17e780ff2f5 100644 --- a/felix/rules/static_test.go +++ b/felix/rules/static_test.go @@ -960,6 +960,54 @@ 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: NoTrackAction{}, + }, + { + 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: NoTrackAction{}}, + {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 +1060,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: NoTrackAction{}}, + { + 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")