From 8dcc07011bac29572765c4ab1350ece24caf3ddc Mon Sep 17 00:00:00 2001 From: Jason Ball Date: Mon, 18 May 2026 09:58:45 +1000 Subject: [PATCH] =?UTF-8?q?systemvm:=20ipv6=20fw=5Finput=20=E2=80=94=20acc?= =?UTF-8?q?ept=20return=20traffic=20from=20established,related=20connectio?= =?UTF-8?q?ns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The systemvm Virtual Router's nftables `ip6 ip6_firewall fw_input` chain is created with policy=drop and only ICMPv6 accept rules. The IPv4 INPUT chain has the equivalent `iifname "eth2" ct state established,related accept` rule (added by `fw_router_routing()`); the IPv6 path has no such rule. Effect: any v6 connection the VR itself initiates outbound (BGP to upstream PE peers, NTP, DNS lookups, etc.) has its return traffic silently dropped at the v6 INPUT hook before TCP processes it. For Isolated v6 ROUTED networks this is fatal — BGP IPv6 sessions cannot establish, tenant /64 prefixes are never advertised upstream, and VMs in the network are unreachable from the IPv6 internet. PR #10970 added the equivalent rule to the FORWARD chain only (covering tenant VM return traffic). This commit adds the matching rule to the INPUT chain (covering VR-originated return traffic) by introducing `fw_router_routing_v6()` as the IPv6 mirror of `fw_router_routing()`. Verified end-to-end on ACS 4.22.0.0 KVM: before the patch, v6 BGP sessions stay in `Connect` indefinitely; tcpdump confirms PE responds with SYN-ACK but VR's TCP stack never sees the SYN-ACK (MD5 counters zero — drop happens at netfilter). After the patch, v6 BGP sessions reach `Established` within seconds and remain stable across subsequent tenant firewall rule updates. Fixes: #13171 Signed-off-by: Jason Ball --- systemvm/debian/opt/cloud/bin/cs/CsAddress.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py index bde4a976e31c..004c86276aa6 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py @@ -326,6 +326,7 @@ def __init__(self, dev, config): self.config = config self.nft_ipv4_fw = config.get_nft_ipv4_fw() self.nft_ipv4_acl = config.get_nft_ipv4_acl() + self.nft_ipv6_fw = config.get_ipv6_fw() def setAddress(self, address): self.address = address @@ -714,6 +715,22 @@ def fw_router_routing(self): self.nft_ipv4_fw.append({'type': "", 'chain': 'INPUT', 'rule': "iifname %s ip saddr %s tcp dport 8080 ct state new counter accept" % (self.dev, guestNetworkCidr)}) + def fw_router_routing_v6(self): + if self.config.is_vpc() or not self.config.is_routed(): + return + # IPv6 INPUT chain defaults — mirror of fw_router_routing() for v4. + # Without these, return traffic for VR-initiated v6 connections (e.g. + # BGP SYN-ACKs to upstream PE peers) is silently dropped by the + # default-DROP policy on fw_input. PR #10970 added the equivalent + # rule to fw_forward only; this completes that fix for INPUT. + self.nft_ipv6_fw.append({'type': "", 'chain': 'fw_input', + 'rule': "iifname lo counter accept"}) + self.nft_ipv6_fw.append({'type': "", 'chain': 'fw_input', + 'rule': "iifname eth2 ct state established,related counter accept"}) + if self.get_type() in ["guest"]: + self.nft_ipv6_fw.append({'type': "", 'chain': 'fw_input', + 'rule': "iifname %s ct state established,related counter accept" % self.dev}) + def fw_vpcrouter_routing(self): if not self.config.is_vpc() or not self.config.is_routed(): return @@ -839,6 +856,7 @@ def post_config_change(self, method): self.fw_vpcrouter() self.fw_router_routing() self.fw_vpcrouter_routing() + self.fw_router_routing_v6() self.fw_dhcpserver() cmdline = self.config.cmdline()