From 8fec093110efc7145fbcf223a512a2c1c9799d3b Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 12 May 2026 15:29:30 +0530 Subject: [PATCH] Fix delete firewall flow --- .../network/firewall/FirewallManagerImpl.java | 2 +- systemvm/debian/opt/cloud/bin/configure.py | 51 +++++++++++++++++++ ui/src/views/network/PublicIpResource.vue | 14 +++-- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java index 8f6539e5e59..4557de4de4b 100644 --- a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java @@ -894,7 +894,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, success = false; } else { removeRule(rule); - if (rule.getSourceIpAddressId() != null) { + if (rule.getSourceIpAddressId() != null && rule.getVpcId() == null) { //if the rule is the last one for the ip address assigned to VPC, unassign it from the network _vpcMgr.unassignIPFromVpcNetwork(rule.getSourceIpAddressId(), rule.getNetworkId()); } diff --git a/systemvm/debian/opt/cloud/bin/configure.py b/systemvm/debian/opt/cloud/bin/configure.py index a250229ba9e..84c327cfa29 100755 --- a/systemvm/debian/opt/cloud/bin/configure.py +++ b/systemvm/debian/opt/cloud/bin/configure.py @@ -703,6 +703,7 @@ class CsAcl(CsDataBag): self.add_routing_rules() return + desired_firewall_ips = self._get_desired_vpc_firewall_ips() fw_chains_created = set() for item in self.dbag: if item == "id": @@ -725,6 +726,56 @@ class CsAcl(CsDataBag): fw_chains_created.add(src_ip) self.AclIP(self.dbag[item], self.config).create() + if self.config.is_vpc(): + self._cleanup_removed_vpc_firewall_chains(desired_firewall_ips) + + def _get_desired_vpc_firewall_ips(self): + desired_firewall_ips = set() + if not self.config.is_vpc(): + return desired_firewall_ips + + for item in self.dbag: + if item == "id": + continue + rule = self.dbag[item] + if rule.get("purpose") == "Firewall": + src_ip = rule.get("src_ip") + if src_ip: + desired_firewall_ips.add(src_ip) + return desired_firewall_ips + + def _cleanup_removed_vpc_firewall_chains(self, desired_firewall_ips): + """Delete FIREWALL_ chain only when no firewall rule remains for that VPC public IP.""" + try: + mangle_save = CsHelper.execute("iptables-save -t mangle") + existing_firewall_ips = [] + for line in mangle_save: + if line.startswith(":FIREWALL_"): + chain = line.split(" ")[0][1:] + existing_firewall_ips.append(chain.replace("FIREWALL_", "", 1)) + + for src_ip in existing_firewall_ips: + if src_ip in desired_firewall_ips: + continue + self._delete_vpc_firewall_chain(src_ip) + except Exception as e: + logging.debug("Failed VPC firewall chain cleanup: %s", e) + + def _delete_vpc_firewall_chain(self, src_ip): + chain = "FIREWALL_%s" % src_ip + try: + prerouting_rules = CsHelper.execute("iptables -t mangle -S PREROUTING") + for rule in prerouting_rules: + if ("-d %s/32" % src_ip) in rule and ("-j %s" % chain) in rule: + delete_rule = rule.replace("-A PREROUTING", "-D PREROUTING", 1) + CsHelper.execute2("iptables -t mangle %s" % delete_rule, False) + + CsHelper.execute2("iptables -t mangle -F %s" % chain, False) + CsHelper.execute2("iptables -t mangle -X %s" % chain, False) + logging.info("Deleted VPC firewall chain %s as last firewall rule was removed", chain) + except Exception as e: + logging.debug("Failed deleting VPC firewall chain %s: %s", chain, e) + class CsIpv6Firewall(CsDataBag): """ Deal with IPv6 Firewall diff --git a/ui/src/views/network/PublicIpResource.vue b/ui/src/views/network/PublicIpResource.vue index 5a5ea99a003..0f77cb52937 100644 --- a/ui/src/views/network/PublicIpResource.vue +++ b/ui/src/views/network/PublicIpResource.vue @@ -147,11 +147,15 @@ export default { // VPC IPs with static nat keep existing VPN behavior and always show firewall if (this.resource.isstaticnat) { - let tabs = this.defaultTabs - if (this.resource.virtualmachinetype === 'DomainRouter') { - tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn')) - } - this.tabs = hasFirewallCapability ? this.addFirewallTab(tabs) : tabs + const tabs = this.addFirewallTab(this.$route.meta.tabs).map(tab => { + if (tab.name !== 'firewall') { + return tab + } + const staticNatFirewallTab = { ...tab } + delete staticNatFirewallTab.networkServiceFilter + return staticNatFirewallTab + }) + this.tabs = tabs return }