Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
fa844c6
Support Firewall for public IPs in VPC
harikrishna-patnala Feb 25, 2026
ab71e00
UI changes
harikrishna-patnala Mar 5, 2026
bf97ab8
more fixes
harikrishna-patnala Mar 5, 2026
9e90c62
UI fix
harikrishna-patnala May 7, 2026
4928aaf
Firewall tab changes
harikrishna-patnala May 11, 2026
77535bf
Changes in mapping to the VPC and not the tier network
harikrishna-patnala May 11, 2026
d2a8e4b
Fix vpcid
harikrishna-patnala May 12, 2026
3fc9727
Fix delete firewall flow
harikrishna-patnala May 12, 2026
47a15da
remove default offering changes
harikrishna-patnala May 12, 2026
04fb323
Fix unit test
harikrishna-patnala May 12, 2026
69d6698
Fix whitespace
harikrishna-patnala May 12, 2026
d4f06db
remove Unnecessary Stubbing
harikrishna-patnala May 12, 2026
6ec0298
more unit test fixes
harikrishna-patnala May 12, 2026
84e44e8
Update server/src/main/java/org/apache/cloudstack/network/RoutedIpv4M…
harikrishna-patnala May 13, 2026
7ffa4f0
Update server/src/main/java/org/apache/cloudstack/network/RoutedIpv4M…
harikrishna-patnala May 13, 2026
613d190
DB and response changes
harikrishna-patnala May 13, 2026
15e67de
marvin test
harikrishna-patnala May 13, 2026
9d71704
more unit tests
harikrishna-patnala May 13, 2026
413a9f6
Fix UnnecessaryStubbingException
harikrishna-patnala May 13, 2026
e3a4f6a
Fix possible NPE
harikrishna-patnala May 13, 2026
57c1a21
Fix whitespace
harikrishna-patnala May 13, 2026
5b973d4
Fix vpc uuid in response
harikrishna-patnala May 13, 2026
994836a
Add Firewall in clone VPC offering in UI form
harikrishna-patnala May 13, 2026
aa39b20
changes for VPC with firewall and without capabilities
harikrishna-patnala Jun 9, 2026
6f46621
Add VPC firewall check
harikrishna-patnala Jun 9, 2026
f75771b
UI fix for VPC no firewall
harikrishna-patnala Jun 11, 2026
1497807
Make the drop rule add by default
harikrishna-patnala Jun 11, 2026
f0171f9
Fix restart VPC with cleanup
harikrishna-patnala Jun 16, 2026
3dadaa5
Fix cleanup order
harikrishna-patnala Jun 16, 2026
d029be6
Fix FW rule application on a VPC not having tiers
harikrishna-patnala Jul 10, 2026
19d49ab
Fix firewall option in network offering creation when vpc is enabled
harikrishna-patnala Jul 10, 2026
60186e4
Fix UI
harikrishna-patnala Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion api/src/main/java/com/cloud/network/NetworkRuleApplier.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@

import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.vpc.Vpc;

public interface NetworkRuleApplier {
public boolean applyRules(Network network, FirewallRule.Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException;
default boolean applyRules(Network network, FirewallRule.Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
return applyRules(network, null, purpose, rules);
}

boolean applyRules(Network network, Vpc vpc, FirewallRule.Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.vpc.Vpc;

public interface FirewallServiceProvider extends NetworkElement {
/**
* Apply rules
* @param network
* @param rules
* @return
* @throws ResourceUnavailableException
* Apply firewall rules in a network context.
*/
boolean applyFWRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException;
default boolean applyFWRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
return false;
}

/**
* Apply firewall rules in a VPC context.
*/
default boolean applyFWRulesInVPC(Vpc vpc, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
return false;
}
}
4 changes: 3 additions & 1 deletion api/src/main/java/com/cloud/network/rules/FirewallRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ enum TrafficType {

State getState();

long getNetworkId();
Long getNetworkId();

Long getVpcId();

Long getSourceIpAddressId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public State getState() {
}

@Override
public long getNetworkId() {
public Long getNetworkId() {
return networkId;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,9 @@ public State getState() {
}

@Override
public long getNetworkId() {
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
Long ntwkId = null;

if (ip.getAssociatedWithNetworkId() != null) {
ntwkId = ip.getAssociatedWithNetworkId();
}
public Long getNetworkId() {
IpAddress ip = getIp();
Long ntwkId = isVpcIp(ip) ? getVpcNetworkIdForFirewallRule(ip) : getIsolatedNetworkIdForFirewallRule(ip);

if (ntwkId == null) {
throw new InvalidParameterValueException("Unable to create firewall rule for the IP address ID=" + ipAddressId +
Expand All @@ -238,6 +234,12 @@ public long getNetworkId() {
return ntwkId;
}

@Override
public Long getVpcId() {
IpAddress ip = getIp();
return isVpcIp(ip) ? ip.getVpcId() : null;
}

@Override
public long getEntityOwnerId() {
Account account = CallContext.current().getCallingAccount();
Expand Down Expand Up @@ -300,7 +302,21 @@ public String getSyncObjType() {

@Override
public Long getSyncObjId() {
return getIp().getAssociatedWithNetworkId();
Long syncObjId = getIp().getAssociatedWithNetworkId();
return syncObjId != null ? syncObjId : getNetworkId();
}

private boolean isVpcIp(IpAddress ip) {
return ip.getVpcId() != null;
}

private Long getIsolatedNetworkIdForFirewallRule(IpAddress ip) {
return ip.getAssociatedWithNetworkId();
}

private Long getVpcNetworkIdForFirewallRule(IpAddress ip) {
// VPC flow is independent from tier association; manager resolves execution network.
return ip.getNetworkId();
}

private IpAddress getIp() {
Expand All @@ -311,6 +327,7 @@ private IpAddress getIp() {
return ip;
}


@Override
public Integer getIcmpCode() {
if (icmpCode != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public Boolean getOpenFirewall() {
}
}

private Long getVpcId() {
public Long getVpcId() {
if (ipAddressId != null) {
IpAddress ipAddr = _networkService.getIp(ipAddressId);
if (ipAddr == null || !ipAddr.readyToUse()) {
Expand Down Expand Up @@ -275,7 +275,7 @@ public State getState() {
}

@Override
public long getNetworkId() {
public Long getNetworkId() {
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
Long ntwkId = _networkService.getPreferredNetworkIdForPublicIpRuleAssignment(ip, networkId);
if (ntwkId == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,13 @@ public FirewallRule.State getState() {
}

@Override
public long getNetworkId() {
return -1;
public Long getNetworkId() {
return -1L;
}

@Override
public Long getVpcId() {
return null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public class FirewallResponse extends BaseResponse {
@Param(description = "The Network ID of the firewall rule")
private String networkId;

@SerializedName(ApiConstants.VPC_ID)
@Param(description = "The VPC ID of the firewall rule")
private String vpcId;

@SerializedName(ApiConstants.IP_ADDRESS)
@Param(description = "The public IP address for the firewall rule")
private String publicIpAddress;
Expand Down Expand Up @@ -115,6 +119,10 @@ public void setNetworkId(String networkId) {
this.networkId = networkId;
}

public void setVpcId(String vpcId) {
this.vpcId = vpcId;
}

public void setState(String state) {
this.state = state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@
import java.util.Collections;
import java.util.List;

import com.cloud.network.IpAddress;
import com.cloud.network.NetworkService;
import com.cloud.utils.db.EntityManager;
import org.apache.commons.collections.CollectionUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;

Expand All @@ -33,6 +38,12 @@
@RunWith(MockitoJUnitRunner.class)
public class CreateFirewallRuleCmdTest {

@Mock
private EntityManager entityManager;

@Mock
private NetworkService networkService;

private void validateAllIp4Cidr(final CreateFirewallRuleCmd cmd) {
Assert.assertTrue(CollectionUtils.isNotEmpty(cmd.getSourceCidrList()));
Assert.assertEquals(1, cmd.getSourceCidrList().size());
Expand Down Expand Up @@ -88,4 +99,22 @@ public void testGetSourceCidrList_EmptyFirstElementButMore() {
Assert.assertEquals(2, cmd.getSourceCidrList().size());
Assert.assertEquals(cidr, cmd.getSourceCidrList().get(1));
}

@Test
public void testGetNetworkIdVpcWithoutAssociatedNetworkUsesVpcFallbackAndSyncObjId() {
final CreateFirewallRuleCmd cmd = new CreateFirewallRuleCmd();
final IpAddress ip = Mockito.mock(IpAddress.class);

cmd._entityMgr = entityManager;
cmd._networkService = networkService;
ReflectionTestUtils.setField(cmd, "ipAddressId", 42L);

Mockito.when(networkService.getIp(42L)).thenReturn(ip);
Mockito.when(ip.getAssociatedWithNetworkId()).thenReturn(null);
Mockito.when(ip.getVpcId()).thenReturn(100L);
Mockito.when(ip.getNetworkId()).thenReturn(2L);

Assert.assertEquals(Long.valueOf(2L), cmd.getNetworkId());
Assert.assertEquals(Long.valueOf(2L), cmd.getSyncObjId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public abstract class NetworkElementCommand extends Command {
public static final String ZONE_NETWORK_TYPE = "zone.network.type";
public static final String GUEST_BRIDGE = "guest.bridge";
public static final String VPC_PRIVATE_GATEWAY = "vpc.gateway.private";
public static final String VPC_ID = "vpc.id";
public static final String FIREWALL_EGRESS_DEFAULT = "firewall.egress.default";
public static final String NETWORK_PUB_LAST_IP = "network.public.last.ip";
public static final String HYPERVISOR_HOST_PRIVATE_IP = "hypervisor.private.ip";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*/
public class SetFirewallRulesCommand extends NetworkElementCommand {
FirewallRuleTO[] rules;
Long vpcId;

protected SetFirewallRulesCommand() {
}
Expand All @@ -40,10 +41,19 @@ public SetFirewallRulesCommand(List<FirewallRuleTO> rules) {
this.rules = rules.toArray(new FirewallRuleTO[rules.size()]);
}

public SetFirewallRulesCommand(List<FirewallRuleTO> rules, Long vpcId) {
this.rules = rules.toArray(new FirewallRuleTO[rules.size()]);
this.vpcId = vpcId;
}

public FirewallRuleTO[] getRules() {
return rules;
}

public Long getVpcId() {
return vpcId;
}

public String[][] generateFwRules() {
String[][] result = new String[2][];
Set<String> toAdd = new HashSet<String>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,15 @@ public long getDomainId() {
}

@Override
public long getNetworkId() {
public Long getNetworkId() {
return networkId;
}

@Override
public Long getVpcId() {
return null;
}

@Override
public long getId() {
return id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ public boolean configure(final String name, final Map<String, Object> params) th
defaultVPCOffProviders.put(Service.StaticNat, defaultProviders);
defaultVPCOffProviders.put(Service.PortForwarding, defaultProviders);
defaultVPCOffProviders.put(Service.Vpn, defaultProviders);
defaultVPCOffProviders.put(Service.Firewall, defaultProviders);

Transaction.execute(new TransactionCallbackNoReturn() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public interface FirewallRulesDao extends GenericDao<FirewallRuleVO, Long> {

List<FirewallRuleVO> listByNetworkPurposeTrafficType(long networkId, FirewallRule.Purpose purpose, FirewallRule.TrafficType trafficType);

List<FirewallRuleVO> listByVpcPurposeTrafficType(long vpcId, FirewallRule.Purpose purpose, FirewallRule.TrafficType trafficType);

List<FirewallRuleVO> listByIpAndPurposeWithState(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state);

void loadSourceCidrs(FirewallRuleVO rule);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ protected FirewallRulesDaoImpl() {
AllFieldsSearch.and("domain", AllFieldsSearch.entity().getDomainId(), Op.EQ);
AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ);
AllFieldsSearch.and("networkId", AllFieldsSearch.entity().getNetworkId(), Op.EQ);
AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ);
AllFieldsSearch.and("related", AllFieldsSearch.entity().getRelated(), Op.EQ);
AllFieldsSearch.and("trafficType", AllFieldsSearch.entity().getTrafficType(), Op.EQ);
AllFieldsSearch.done();
Expand Down Expand Up @@ -356,6 +357,22 @@ public List<FirewallRuleVO> listByNetworkPurposeTrafficType(long networkId, Purp
return listBy(sc);
}

@Override
public List<FirewallRuleVO> listByVpcPurposeTrafficType(long vpcId, Purpose purpose, TrafficType trafficType) {
SearchCriteria<FirewallRuleVO> sc = AllFieldsSearch.create();
sc.setParameters("vpcId", vpcId);

if (purpose != null) {
sc.setParameters("purpose", purpose);
}

if (trafficType != null) {
sc.setParameters("trafficType", trafficType);
}

return listBy(sc);
}

@Override
@DB
public boolean remove(Long id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ public class FirewallRuleVO implements FirewallRule {
@Column(name = "network_id")
Long networkId;

@Column(name = "vpc_id")
Long vpcId;

@Column(name = "icmp_code")
Integer icmpCode;

Expand Down Expand Up @@ -196,10 +199,18 @@ public State getState() {
}

@Override
public long getNetworkId() {
public Long getNetworkId() {
return networkId;
}

public Long getVpcId() {
return vpcId;
}

public void setVpcId(Long vpcId) {
this.vpcId = vpcId;
}

@Override
public FirewallRuleType getType() {
return type;
Expand All @@ -217,7 +228,7 @@ protected FirewallRuleVO() {
uuid = UUID.randomUUID().toString();
}

public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, long networkId, long accountId, long domainId,
public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, Long networkId, long accountId, long domainId,
Purpose purpose, List<String> sourceCidrs, Integer icmpCode, Integer icmpType, Long related, TrafficType trafficType) {
this.xId = xId;
if (xId == null) {
Expand Down Expand Up @@ -261,7 +272,7 @@ public FirewallRuleVO(String xId, long ipAddressId, int port, String protocol, l
}


public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, long networkId, long accountId, long domainId,
public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, Long networkId, long accountId, long domainId,
Purpose purpose, List<String> sourceCidrs, List<String> destCidrs, Integer icmpCode, Integer icmpType, Long related, TrafficType trafficType) {
this(xId,ipAddressId, portStart, portEnd, protocol, networkId, accountId, domainId, purpose, sourceCidrs, icmpCode, icmpType, related, trafficType);
this.destinationCidrs = destCidrs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -588,3 +588,6 @@ CREATE TABLE IF NOT EXISTS `cloud`.`dns_zone_network_map` (
CONSTRAINT `fk_dns_map__zone_id` FOREIGN KEY (`dns_zone_id`) REFERENCES `dns_zone` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_dns_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- This is part of allowing firewall rules on public IP addresses in VPC network
ALTER TABLE `cloud`.`firewall_rules` MODIFY COLUMN `network_id` BIGINT UNSIGNED NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -2986,9 +2986,8 @@ private void createNetworkOfferingForKubernetes(String offeringName, String offe
defaultKubernetesServiceNetworkOfferingProviders.put(Service.UserData, provider);
if (forVpc) {
defaultKubernetesServiceNetworkOfferingProviders.put(Service.NetworkACL, forNsx ? Network.Provider.Nsx : provider);
} else {
defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, forNsx ? Network.Provider.Nsx : provider);
}
defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, forNsx ? Network.Provider.Nsx : provider);
defaultKubernetesServiceNetworkOfferingProviders.put(Service.Lb, forNsx ? Network.Provider.Nsx : provider);
defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, forNsx ? Network.Provider.Nsx : provider);
defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, forNsx ? Network.Provider.Nsx : provider);
Expand Down
Loading
Loading