This is an automated email from the ASF dual-hosted git repository.

winterhazel pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 96ca1b2a7c1 Add option to control MAC address reuse for VR public NICs 
(#13001)
96ca1b2a7c1 is described below

commit 96ca1b2a7c1c80bc5b284e008e9c96d49a276b4a
Author: Bernardo De Marco Gonçalves <[email protected]>
AuthorDate: Wed May 6 13:41:11 2026 -0300

    Add option to control MAC address reuse for VR public NICs (#13001)
---
 api/src/main/java/com/cloud/network/Network.java   |   2 +
 .../java/com/cloud/network/NetworkProfile.java     |   5 +
 api/src/main/java/com/cloud/network/vpc/Vpc.java   |   2 +
 .../java/com/cloud/network/vpc/VpcService.java     |   4 +-
 .../org/apache/cloudstack/api/ApiConstants.java    |   7 +
 .../api/command/user/network/CreateNetworkCmd.java |   9 +
 .../api/command/user/network/UpdateNetworkCmd.java |   9 +
 .../api/command/user/vpc/CreateVPCCmd.java         |   9 +
 .../api/command/user/vpc/UpdateVPCCmd.java         |   9 +
 .../cloudstack/api/response/NetworkResponse.java   |   8 +
 .../cloudstack/api/response/VpcResponse.java       |   8 +
 .../api/command/user/vpc/UpdateVPCCmdTest.java     |   2 +-
 .../service/NetworkOrchestrationService.java       |   5 +
 .../engine/orchestration/NetworkOrchestrator.java  |  24 +-
 .../main/java/com/cloud/network/dao/NetworkVO.java |  13 +
 .../src/main/java/com/cloud/network/vpc/VpcVO.java |  12 +
 .../resources/META-INF/db/schema-42210to42300.sql  |   4 +
 .../main/java/com/cloud/api/ApiResponseHelper.java |   8 +
 .../cloud/network/NetworkMigrationManagerImpl.java |   2 +-
 .../java/com/cloud/network/NetworkServiceImpl.java |  31 ++-
 .../cloud/network/router/NetworkHelperImpl.java    | 122 ++++++---
 .../java/com/cloud/network/vpc/VpcManagerImpl.java |  16 +-
 .../deployment/RouterDeploymentDefinition.java     |   6 +-
 .../deployment/VpcRouterDeploymentDefinition.java  |   7 +-
 .../com/cloud/network/NetworkServiceImplTest.java  |  50 +++-
 .../network/router/NetworkHelperImplTest.java      | 288 ++++++++++++++++++++-
 .../com/cloud/network/vpc/VpcManagerImplTest.java  |  10 +-
 .../java/com/cloud/vpc/MockNetworkManagerImpl.java |  10 +-
 ui/public/locales/en.json                          |   1 +
 ui/public/locales/pt_BR.json                       |   1 +
 ui/src/config/section/network.js                   |  30 ++-
 ui/src/views/AutogenView.vue                       |   5 +
 ui/src/views/network/CreateIsolatedNetworkForm.vue |  22 +-
 ui/src/views/network/CreateVpc.vue                 |  20 +-
 ui/src/views/network/UpdateNetwork.vue             |  28 +-
 35 files changed, 691 insertions(+), 98 deletions(-)

diff --git a/api/src/main/java/com/cloud/network/Network.java 
b/api/src/main/java/com/cloud/network/Network.java
index 0846306f70f..e41eb880ffd 100644
--- a/api/src/main/java/com/cloud/network/Network.java
+++ b/api/src/main/java/com/cloud/network/Network.java
@@ -510,4 +510,6 @@ public interface Network extends ControlledEntity, 
StateObject<Network.State>, I
     Integer getPrivateMtu();
 
     Integer getNetworkCidrSize();
+
+    boolean getKeepMacAddressOnPublicNic();
 }
diff --git a/api/src/main/java/com/cloud/network/NetworkProfile.java 
b/api/src/main/java/com/cloud/network/NetworkProfile.java
index 2e8efb48930..d690344a0e3 100644
--- a/api/src/main/java/com/cloud/network/NetworkProfile.java
+++ b/api/src/main/java/com/cloud/network/NetworkProfile.java
@@ -385,6 +385,11 @@ public class NetworkProfile implements Network {
         return networkCidrSize;
     }
 
+    @Override
+    public boolean getKeepMacAddressOnPublicNic() {
+        return true;
+    }
+
     @Override
     public String toString() {
         return String.format("NetworkProfile %s",
diff --git a/api/src/main/java/com/cloud/network/vpc/Vpc.java 
b/api/src/main/java/com/cloud/network/vpc/Vpc.java
index b94089d2d43..a0686e2bf7d 100644
--- a/api/src/main/java/com/cloud/network/vpc/Vpc.java
+++ b/api/src/main/java/com/cloud/network/vpc/Vpc.java
@@ -107,4 +107,6 @@ public interface Vpc extends ControlledEntity, Identity, 
InternalIdentity {
     String getIp6Dns2();
 
     boolean useRouterIpAsResolver();
+
+    boolean getKeepMacAddressOnPublicNic();
 }
diff --git a/api/src/main/java/com/cloud/network/vpc/VpcService.java 
b/api/src/main/java/com/cloud/network/vpc/VpcService.java
index c1546609d2b..3d0ba43263f 100644
--- a/api/src/main/java/com/cloud/network/vpc/VpcService.java
+++ b/api/src/main/java/com/cloud/network/vpc/VpcService.java
@@ -58,7 +58,7 @@ public interface VpcService {
      */
     Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, 
String displayText, String cidr, String networkDomain,
                   String ip4Dns1, String ip4Dns2, String ip6Dns1, String 
ip6Dns2, Boolean displayVpc, Integer publicMtu, Integer cidrSize,
-                  Long asNumber, List<Long> bgpPeerIds, Boolean 
useVrIpResolver) throws ResourceAllocationException;
+                  Long asNumber, List<Long> bgpPeerIds, Boolean 
useVrIpResolver, boolean keepMacAddressOnPublicNic) throws 
ResourceAllocationException;
 
     /**
      * Persists VPC record in the database
@@ -104,7 +104,7 @@ public interface VpcService {
      * @throws ResourceUnavailableException if during restart some resources 
may not be available
      * @throws InsufficientCapacityException if for instance no address space, 
compute or storage is sufficiently available
      */
-    Vpc updateVpc(long vpcId, String vpcName, String displayText, String 
customId, Boolean displayVpc, Integer mtu, String sourceNatIp) throws 
ResourceUnavailableException, InsufficientCapacityException;
+    Vpc updateVpc(long vpcId, String vpcName, String displayText, String 
customId, Boolean displayVpc, Integer mtu, String sourceNatIp, Boolean 
keepMacAddressOnPublicNic) throws ResourceUnavailableException, 
InsufficientCapacityException;
 
     /**
      * Lists VPC(s) based on the parameters passed to the API call
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java 
b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 6fb7cb0612c..4d4ead277e5 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -1356,6 +1356,13 @@ public class ApiConstants {
     public static final String OBJECT_STORAGE_LIMIT = "objectstoragelimit";
     public static final String OBJECT_STORAGE_TOTAL = "objectstoragetotal";
 
+    public static final String KEEP_MAC_ADDRESS_ON_PUBLIC_NIC = 
"keepmacaddressonpublicnic";
+
+    public static final String 
PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC =
+            "Indicates whether to use the same MAC address for the public NIC 
of VRs on the same network. If \"true\", when creating redundant routers or 
recreating" +
+                    " a VR, CloudStack will use the same MAC address for the 
public NIC of all VRs. Otherwise, if \"false\", new public NICs will always 
have " +
+                    " a new MAC address.";
+
     public static final String PARAMETER_DESCRIPTION_ACTIVATION_RULE = "Quota 
tariff's activation rule. It can receive a JS script that results in either " +
             "a boolean or a numeric value: if it results in a boolean value, 
the tariff value will be applied according to the result; if it results in a 
numeric value, the " +
             "numeric value will be applied; if the result is neither a boolean 
nor a numeric value, the tariff will not be applied. If the rule is not 
informed, the tariff " +
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
index cbf6df081b3..ee5b8568e83 100644
--- 
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
@@ -199,6 +199,11 @@ public class CreateNetworkCmd extends BaseCmd implements 
UserCmd {
     @Parameter(name=ApiConstants.AS_NUMBER, type=CommandType.LONG, since = 
"4.20.0", description="the AS Number of the network")
     private Long asNumber;
 
+    @Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            description = 
ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            type = CommandType.BOOLEAN, since = "4.23.0", authorized = 
{RoleType.Admin})
+    private Boolean keepMacAddressOnPublicNic;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -286,6 +291,10 @@ public class CreateNetworkCmd extends BaseCmd implements 
UserCmd {
         return sourceNatIP;
     }
 
+    public Boolean getKeepMacAddressOnPublicNic() {
+        return keepMacAddressOnPublicNic;
+    }
+
     @Override
     public boolean isDisplay() {
         if(displayNetwork == null)
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
index 2e638f1e2f7..7b6841d6097 100644
--- 
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
@@ -105,6 +105,11 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd 
implements UserCmd {
     @Parameter(name = ApiConstants.SOURCE_NAT_IP, type = CommandType.STRING, 
description = "IPV4 address to be assigned to the public interface of the 
network router. This address must already be acquired for this network", since 
= "4.19")
     private String sourceNatIP;
 
+    @Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            description = 
ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            type = CommandType.BOOLEAN, since = "4.23.0", authorized = 
{RoleType.Admin})
+    private Boolean keepMacAddressOnPublicNic;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -186,6 +191,10 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd 
implements UserCmd {
         return sourceNatIP;
     }
 
+    public Boolean getKeepMacAddressOnPublicNic() {
+        return keepMacAddressOnPublicNic;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
index 2adbbd66408..86309d7f28a 100644
--- 
a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
@@ -130,6 +130,11 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd 
implements UserCmd {
             description="(optional) for NSX based VPCs: when set to true, use 
the VR IP as nameserver, otherwise use DNS1 and DNS2")
     private Boolean useVrIpResolver;
 
+    @Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            description = 
ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            type = CommandType.BOOLEAN, since = "4.23.0", authorized = 
{RoleType.Admin})
+    private boolean keepMacAddressOnPublicNic = true;
+
     // ///////////////////////////////////////////////////
     // ///////////////// Accessors ///////////////////////
     // ///////////////////////////////////////////////////
@@ -214,6 +219,10 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd 
implements UserCmd {
         return BooleanUtils.toBoolean(useVrIpResolver);
     }
 
+    public boolean getKeepMacAddressOnPublicNic() {
+        return keepMacAddressOnPublicNic;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java
index f2327c9073f..6cfdb895977 100644
--- 
a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java
@@ -69,6 +69,11 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd 
implements UserCmd {
             since = "4.19")
     private String sourceNatIP;
 
+    @Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            description = 
ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
+            type = CommandType.BOOLEAN, since = "4.23.0", authorized = 
{RoleType.Admin})
+    private Boolean keepMacAddressOnPublicNic;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -97,6 +102,10 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd 
implements UserCmd {
         return sourceNatIP;
     }
 
+    public Boolean getKeepMacAddressOnPublicNic() {
+        return keepMacAddressOnPublicNic;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java 
b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
index 7c4b733a80f..3a3663af255 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
@@ -331,6 +331,10 @@ public class NetworkResponse extends 
BaseResponseWithAssociatedNetwork implement
     @Param(description = "The BGP peers for the network", since = "4.20.0")
     private Set<BgpPeerResponse> bgpPeers;
 
+    @SerializedName(ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC)
+    @Param(description = 
ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC, since = 
"4.23.0")
+    private Boolean keepMacAddressOnPublicNic;
+
     public NetworkResponse() {}
 
     public Boolean getDisplayNetwork() {
@@ -702,4 +706,8 @@ public class NetworkResponse extends 
BaseResponseWithAssociatedNetwork implement
     public void setIpv6Dns2(String ipv6Dns2) {
         this.ipv6Dns2 = ipv6Dns2;
     }
+
+    public void setKeepMacAddressOnPublicNic(Boolean 
keepMacAddressOnPublicNic) {
+        this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
+    }
 }
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java 
b/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java
index acfabb11350..34d50d5b9f9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java
@@ -185,6 +185,10 @@ public class VpcResponse extends 
BaseResponseWithAnnotations implements Controll
     @Param(description = "The BGP peers for the VPC", since = "4.20.0")
     private Set<BgpPeerResponse> bgpPeers;
 
+    @SerializedName(ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC)
+    @Param(description = 
ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC, since = 
"4.23.0")
+    private Boolean keepMacAddressOnPublicNic;
+
     public void setId(final String id) {
         this.id = id;
     }
@@ -366,4 +370,8 @@ public class VpcResponse extends 
BaseResponseWithAnnotations implements Controll
         }
         this.bgpPeers.add(bgpPeer);
     }
+
+    public void setKeepMacAddressOnPublicNic(Boolean 
keepMacAddressOnPublicNic) {
+        this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
+    }
 }
diff --git 
a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java
 
b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java
index acb2dc68597..9d56cffd671 100644
--- 
a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java
+++ 
b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java
@@ -93,7 +93,7 @@ public class UpdateVPCCmdTest extends TestCase {
         responseGenerator = Mockito.mock(ResponseGenerator.class);
         cmd._responseGenerator = responseGenerator;
         Mockito.verify(_vpcService, 
Mockito.times(0)).updateVpc(Mockito.anyLong(), Mockito.anyString(), 
Mockito.anyString(),
-                Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), 
Mockito.anyString());
+                Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), 
Mockito.anyString(), Mockito.anyBoolean());
 
     }
 }
diff --git 
a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
 
b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
index b7b548fb940..030c1277efe 100644
--- 
a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
+++ 
b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
@@ -220,6 +220,11 @@ public interface NetworkOrchestrationService {
                                Boolean displayNetworkEnabled, String 
isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String 
routerIp, String routerIpv6,
                                String ip4Dns1, String ip4Dns2, String ip6Dns1, 
String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize) 
throws ConcurrentOperationException, InsufficientCapacityException, 
ResourceAllocationException;
 
+    Network createGuestNetwork(long networkOfferingId, String name, String 
displayText, String gateway, String cidr, String vlanId, boolean 
bypassVlanOverlapCheck, String networkDomain, Account owner,
+                               Long domainId, PhysicalNetwork physicalNetwork, 
long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String 
ip6Gateway, String ip6Cidr,
+                               Boolean displayNetworkEnabled, String 
isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String 
routerIp, String routerIpv6,
+                               String ip4Dns1, String ip4Dns2, String ip6Dns1, 
String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize, 
boolean keepMacAddressOnPublicNic) throws ConcurrentOperationException, 
InsufficientCapacityException, ResourceAllocationException;
+
     UserDataServiceProvider getPasswordResetProvider(Network network);
 
     UserDataServiceProvider getSSHKeyResetProvider(Network network);
diff --git 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index 7d455e7d6dc..4262ee701aa 100644
--- 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -863,6 +863,7 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                 vpcId, offering.isRedundantRouter(), 
predefined.getExternalId());
         vo.setDisplayNetwork(isDisplayNetworkEnabled == null || 
isDisplayNetworkEnabled);
         vo.setStrechedL2Network(offering.isSupportingStrechedL2());
+        
vo.setKeepMacAddressOnPublicNic(predefined.getKeepMacAddressOnPublicNic());
         return vo;
     }
 
@@ -2724,7 +2725,7 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
         return createGuestNetwork(networkOfferingId, name, displayText, 
gateway, cidr, vlanId,
                 bypassVlanOverlapCheck, null, owner, null, pNtwk, 
pNtwk.getDataCenterId(), ACLType.Account, null,
                 vpcId, null, null, true, null, null, null, true, null, null,
-                null, null, null, null, null, null);
+                null, null, null, null, null, null, true);
     }
 
     @Override
@@ -2735,10 +2736,25 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                                       final Boolean isDisplayNetworkEnabled, 
final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String 
externalId,
                                       String routerIp, String routerIpv6, 
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2,
                                       Pair<Integer, Integer> vrIfaceMTUs, 
Integer networkCidrSize) throws ConcurrentOperationException, 
InsufficientCapacityException, ResourceAllocationException {
+        return createGuestNetwork(networkOfferingId, name, displayText, 
gateway, cidr, vlanId, bypassVlanOverlapCheck,
+                networkDomain, owner, domainId, pNtwk, zoneId, aclType, 
subdomainAccess, vpcId, ip6Gateway, ip6Cidr,
+                isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, 
externalId, false, routerIp, routerIpv6,
+                ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, vrIfaceMTUs, 
networkCidrSize, true);
+    }
+
+    @Override
+    @DB
+    public Network createGuestNetwork(final long networkOfferingId, final 
String name, final String displayText, final String gateway, final String cidr, 
String vlanId,
+                                      boolean bypassVlanOverlapCheck, String 
networkDomain, final Account owner, final Long domainId, final PhysicalNetwork 
pNtwk,
+                                      final long zoneId, final ACLType 
aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, 
final String ip6Cidr,
+                                      final Boolean isDisplayNetworkEnabled, 
final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String 
externalId,
+                                      String routerIp, String routerIpv6, 
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2,
+                                      Pair<Integer, Integer> vrIfaceMTUs, 
Integer networkCidrSize, boolean keepMacAddressOnPublicNic) throws 
ConcurrentOperationException, InsufficientCapacityException, 
ResourceAllocationException {
         // create Isolated/Shared/L2 network
         return createGuestNetwork(networkOfferingId, name, displayText, 
gateway, cidr, vlanId, bypassVlanOverlapCheck,
                 networkDomain, owner, domainId, pNtwk, zoneId, aclType, 
subdomainAccess, vpcId, ip6Gateway, ip6Cidr,
-                isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, 
externalId, false, routerIp, routerIpv6, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, 
vrIfaceMTUs, networkCidrSize);
+                isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, 
externalId, false, routerIp, routerIpv6,
+                ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, vrIfaceMTUs, 
networkCidrSize, keepMacAddressOnPublicNic);
     }
 
     @DB
@@ -2747,7 +2763,8 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                                        final long zoneId, final ACLType 
aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, 
final String ip6Cidr,
                                        final Boolean isDisplayNetworkEnabled, 
final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String 
externalId,
                                        final Boolean isPrivateNetwork, String 
routerIp, String routerIpv6, final String ip4Dns1, final String ip4Dns2,
-                                       final String ip6Dns1, final String 
ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize) throws 
ConcurrentOperationException, InsufficientCapacityException, 
ResourceAllocationException {
+                                       final String ip6Dns1, final String 
ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize,
+                                       boolean keepMacAddressOnPublicNic) 
throws ConcurrentOperationException, InsufficientCapacityException, 
ResourceAllocationException {
 
         final NetworkOfferingVO ntwkOff = 
_networkOfferingDao.findById(networkOfferingId);
         final DataCenterVO zone = _dcDao.findById(zoneId);
@@ -3095,6 +3112,7 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                     }
                 }
                 userNetwork.setNetworkCidrSize(networkCidrSize);
+                
userNetwork.setKeepMacAddressOnPublicNic(keepMacAddressOnPublicNic);
                 final List<? extends Network> networks = setupNetwork(owner, 
ntwkOff, userNetwork, plan, name, displayText, true, domainId, aclType, 
subdomainAccessFinal, vpcId,
                         isDisplayNetworkEnabled);
                 Network network;
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java 
b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java
index 02abaacd854..f2572ba91c2 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java
@@ -203,9 +203,13 @@ public class NetworkVO implements Network {
     @Column(name = "private_mtu")
     Integer privateMtu;
 
+    @Column(name = "keep_mac_address_on_public_nic")
+    private boolean keepMacAddressOnPublicNic = true;
+
     @Transient
     Integer networkCidrSize;
 
+
     public NetworkVO() {
         uuid = UUID.randomUUID().toString();
     }
@@ -773,4 +777,13 @@ public class NetworkVO implements Network {
     public void setNetworkCidrSize(Integer networkCidrSize) {
         this.networkCidrSize = networkCidrSize;
     }
+
+    @Override
+    public boolean getKeepMacAddressOnPublicNic() {
+        return keepMacAddressOnPublicNic;
+    }
+
+    public void setKeepMacAddressOnPublicNic(boolean 
keepMacAddressOnPublicNic) {
+        this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
+    }
 }
diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java 
b/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java
index e942eadb8ff..742d3f2f82e 100644
--- a/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java
@@ -108,6 +108,9 @@ public class VpcVO implements Vpc {
     @Column(name = "use_router_ip_resolver")
     boolean useRouterIpResolver = false;
 
+    @Column(name = "keep_mac_address_on_public_nic")
+    private boolean keepMacAddressOnPublicNic = true;
+
     @Transient
     boolean rollingRestart = false;
 
@@ -321,4 +324,13 @@ public class VpcVO implements Vpc {
     public void setUseRouterIpResolver(boolean useRouterIpResolver) {
         this.useRouterIpResolver = useRouterIpResolver;
     }
+
+    @Override
+    public boolean getKeepMacAddressOnPublicNic() {
+        return keepMacAddressOnPublicNic;
+    }
+
+    public void setKeepMacAddressOnPublicNic(boolean 
keepMacAddressOnPublicNic) {
+        this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
+    }
 }
diff --git 
a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql 
b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql
index c0feb06e76a..c99f798d3d5 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql
@@ -127,3 +127,7 @@ CREATE TABLE IF NOT EXISTS 
`cloud_usage`.`quota_tariff_usage` (
     PRIMARY KEY (`id`),
     CONSTRAINT `fk_quota_tariff_usage__tariff_id` FOREIGN KEY (`tariff_id`) 
REFERENCES `cloud_usage`.`quota_tariff` (`id`),
     CONSTRAINT `fk_quota_tariff_usage__quota_usage_id` FOREIGN KEY 
(`quota_usage_id`) REFERENCES `cloud_usage`.`quota_usage` (`id`));
+
+-- Add the 'keep_mac_address_on_public_nic' column to the 'cloud.networks' and 
'cloud.vpc' tables
+CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.networks', 
'keep_mac_address_on_public_nic', 'TINYINT(1) NOT NULL DEFAULT 1');
+CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc', 
'keep_mac_address_on_public_nic', 'TINYINT(1) NOT NULL DEFAULT 1');
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java 
b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index 11ac3d639e9..a8551b4c669 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -2890,6 +2890,11 @@ public class ApiResponseHelper implements 
ResponseGenerator, ResourceIdSupport {
             }
         }
 
+        if (CallContext.current().getCallingAccount().getType() == 
Account.Type.ADMIN &&
+                network.getVpcId() == null && network.getGuestType() == 
Network.GuestType.Isolated) {
+            
response.setKeepMacAddressOnPublicNic(network.getKeepMacAddressOnPublicNic());
+        }
+
         response.setObjectName("network");
         return response;
     }
@@ -3653,6 +3658,9 @@ public class ApiResponseHelper implements 
ResponseGenerator, ResourceIdSupport {
             }
         }
 
+        if (CallContext.current().getCallingAccount().getType() == 
Account.Type.ADMIN) {
+            
response.setKeepMacAddressOnPublicNic(vpc.getKeepMacAddressOnPublicNic());
+        }
         response.setObjectName("vpc");
         return response;
     }
diff --git 
a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java 
b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
index 450f08c46e3..a09867b8ffc 100644
--- a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
@@ -301,7 +301,7 @@ public class NetworkMigrationManagerImpl implements 
NetworkMigrationManager {
 
             copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, 
vpc.getAccountId(), vpc.getName(),
                     vpc.getDisplayText(), vpc.getCidr(), 
vpc.getNetworkDomain(), vpc.getIp4Dns1(), vpc.getIp4Dns2(),
-                    vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay(), 
vpc.getPublicMtu(), null, null, null, vpc.useRouterIpAsResolver());
+                    vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay(), 
vpc.getPublicMtu(), null, null, null, vpc.useRouterIpAsResolver(), 
vpc.getKeepMacAddressOnPublicNic());
 
             copyOfVpcId = copyOfVpc.getId();
             //on resume of migration the uuid will be swapped already. So the 
copy will have the value of the original vpcid.
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java 
b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index c9884f8c469..d18fd043f69 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -1549,6 +1549,8 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
 
         DataCenter zone = getAndValidateZone(cmd, pNtwk);
 
+        boolean keepMacAddressOnPublicNic = 
getAndValidateSupportForKeepMacAddressOnPublicNicParameter(cmd.getKeepMacAddressOnPublicNic(),
 ntwkOff);
+
         _accountMgr.checkAccess(owner, ntwkOff, zone);
 
         validateZoneAvailability(caller, zone);
@@ -1834,7 +1836,7 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
 
         Network network = commitNetwork(networkOfferingId, gateway, startIP, 
endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, 
displayText, caller, physicalNetworkId, zone.getId(),
                 domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, 
endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, 
privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan,
-                externalId, routerIPv4, routerIPv6, associatedNetwork, 
ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs, networkCidrSize);
+                externalId, routerIPv4, routerIPv6, associatedNetwork, 
ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs, networkCidrSize, 
keepMacAddressOnPublicNic);
 
         // retrieve, acquire and associate the correct IP addresses
         checkAndSetRouterSourceNatIp(owner, cmd, network);
@@ -1879,6 +1881,24 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
         }
     }
 
+    protected boolean 
getAndValidateSupportForKeepMacAddressOnPublicNicParameter(Boolean 
keepMacAddressOnPublicNic, NetworkOffering networkOffering) {
+        if (networkOffering.isForVpc() && keepMacAddressOnPublicNic != null) {
+            throw new InvalidParameterValueException(
+                    String.format("The [%s] parameter cannot be specified on 
the creation of VPC tiers.", ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC)
+            );
+        }
+
+        GuestType guestType = networkOffering.getGuestType();
+        if (guestType != GuestType.Isolated && keepMacAddressOnPublicNic != 
null) {
+            throw new InvalidParameterValueException(String.format(
+                    "The [%s] parameter can only be specified on the creation 
of [%s] networks.",
+                    ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC, 
GuestType.Isolated
+            ));
+        }
+
+        return keepMacAddressOnPublicNic == null || keepMacAddressOnPublicNic;
+    }
+
     @Override
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription 
= "creating network")
@@ -2282,7 +2302,7 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
                                   final Boolean displayNetwork, final Long 
aclId, final String isolatedPvlan, final PVlanType isolatedPvlanType, final 
NetworkOffering ntwkOff, final PhysicalNetwork pNtwk, final ACLType aclType, 
final Account ownerFinal,
                                   final String cidr, final boolean createVlan, 
final String externalId, String routerIp, String routerIpv6,
                                   final Network associatedNetwork, final 
String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String 
ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs,
-                                  final Integer networkCidrSize) throws 
InsufficientCapacityException, ResourceAllocationException {
+                                  final Integer networkCidrSize, final boolean 
keepMacAddressOnPublicNic) throws InsufficientCapacityException, 
ResourceAllocationException {
         try {
             Network network = Transaction.execute(new 
TransactionCallbackWithException<Network, Exception>() {
                 @Override
@@ -2348,7 +2368,7 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
                         }
                         network = 
_networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, 
cidr, vlanId, bypassVlanOverlapCheck, networkDomain, owner, sharedDomainId, 
pNtwk,
                                 zoneId, aclType, subdomainAccess, vpcId, 
ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan, isolatedPvlanType, 
externalId, routerIp, routerIpv6, ip4Dns1, ip4Dns2,
-                                ip6Dns1, ip6Dns2, vrIfaceMTUs, 
networkCidrSize);
+                                ip6Dns1, ip6Dns2, vrIfaceMTUs, 
networkCidrSize, keepMacAddressOnPublicNic);
                     }
 
                     if (createVlan && network != null) {
@@ -3156,6 +3176,7 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
         String ip4Dns2 = cmd.getIp4Dns2();
         String ip6Dns1 = cmd.getIp6Dns1();
         String ip6Dns2 = cmd.getIp6Dns2();
+        Boolean keepMacAddressOnPublicNic = cmd.getKeepMacAddressOnPublicNic();
 
         boolean restartNetwork = false;
 
@@ -3214,6 +3235,10 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
             network.setUuid(customId);
         }
 
+        if (keepMacAddressOnPublicNic != null) {
+            
network.setKeepMacAddressOnPublicNic(getAndValidateSupportForKeepMacAddressOnPublicNicParameter(keepMacAddressOnPublicNic,
 offering));
+        }
+
         // display flag is not null and has changed
         if (displayNetwork != null && displayNetwork != 
network.getDisplayNetwork()) {
             // Update resource count if it needs to be updated
diff --git 
a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java 
b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
index 684f196ce9f..56534a8ee7d 100644
--- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
+++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
@@ -737,55 +737,91 @@ public class NetworkHelperImpl implements NetworkHelper {
     }
 
     protected LinkedHashMap<Network, List<? extends NicProfile>> 
configurePublicNic(final RouterDeploymentDefinition routerDeploymentDefinition, 
final boolean hasGuestNic) throws InsufficientAddressCapacityException {
-        final LinkedHashMap<Network, List<? extends NicProfile>> publicConfig 
= new LinkedHashMap<Network, List<? extends NicProfile>>(3);
-
-        if (routerDeploymentDefinition.isPublicNetwork()) {
-            logger.debug("Adding NIC for Virtual Router in Public network ");
-            // if source nat service is supported by the network, get the 
source
-            // nat ip address
-            final NicProfile defaultNic = new NicProfile();
-            defaultNic.setDefaultNic(true);
-            final PublicIp sourceNatIp = 
routerDeploymentDefinition.getSourceNatIP();
-            defaultNic.setIPv4Address(sourceNatIp.getAddress().addr());
-            defaultNic.setIPv4Gateway(sourceNatIp.getGateway());
-            defaultNic.setIPv4Netmask(sourceNatIp.getNetmask());
-            defaultNic.setMacAddress(sourceNatIp.getMacAddress());
-            // get broadcast from public network
-            final Network pubNet = 
_networkDao.findById(sourceNatIp.getNetworkId());
-            if (pubNet.getBroadcastDomainType() == BroadcastDomainType.Vxlan) {
-                defaultNic.setBroadcastType(BroadcastDomainType.Vxlan);
-                
defaultNic.setBroadcastUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
-                
defaultNic.setIsolationUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
-            } else {
-                defaultNic.setBroadcastType(BroadcastDomainType.Vlan);
-                defaultNic.setBroadcastUri(sourceNatIp.getVlanTag() != null ? 
BroadcastDomainType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
-                defaultNic.setIsolationUri(sourceNatIp.getVlanTag() != null ?  
IsolationType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
-            }
-
-            //If guest nic has already been added we will have 2 devices in 
the list.
-            if (hasGuestNic) {
-                defaultNic.setDeviceId(2);
-            }
+        final LinkedHashMap<Network, List<? extends NicProfile>> publicConfig 
= new LinkedHashMap<>(3);
+        if (!routerDeploymentDefinition.isPublicNetwork()) {
+            return publicConfig;
+        }
 
-            final NetworkOffering publicOffering = 
_networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork).get(0);
-            final List<? extends Network> publicNetworks = 
_networkMgr.setupNetwork(s_systemAccount, publicOffering, 
routerDeploymentDefinition.getPlan(), null, null, false);
-            final String publicIp = defaultNic.getIPv4Address();
-            // We want to use the identical MAC address for RvR on public
-            // interface if possible
-            final NicVO peerNic = 
_nicDao.findByIp4AddressAndNetworkId(publicIp, publicNetworks.get(0).getId());
-            if (peerNic != null) {
-                logger.info("Use same MAC as previous RvR, the MAC is " + 
peerNic.getMacAddress());
-                defaultNic.setMacAddress(peerNic.getMacAddress());
-            }
-            if (routerDeploymentDefinition.getGuestNetwork() != null) {
-                ipv6Service.updateNicIpv6(defaultNic, 
routerDeploymentDefinition.getDest().getDataCenter(), 
routerDeploymentDefinition.getGuestNetwork());
-            }
-            publicConfig.put(publicNetworks.get(0), new 
ArrayList<NicProfile>(Arrays.asList(defaultNic)));
+        final PublicIp sourceNatIp = 
routerDeploymentDefinition.getSourceNatIP();
+        final NicProfile defaultNic = new NicProfile();
+        configurePublicVrNicBasedOnSourceNatIp(defaultNic, sourceNatIp);
+        if (hasGuestNic) {
+            logger.debug("Guest NIC has already been configured, therefore 
setting device ID of new VR (with source NAT [{}]) public NIC to [2].", 
sourceNatIp);
+            defaultNic.setDeviceId(2);
         }
 
+        final NetworkOffering publicOffering = 
_networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork).get(0);
+        final List<? extends Network> publicNetworks = 
_networkMgr.setupNetwork(s_systemAccount, publicOffering, 
routerDeploymentDefinition.getPlan(), null, null, false);
+
+        setPublicNicMacAddressSameAsPeerNic(defaultNic, publicNetworks.get(0), 
routerDeploymentDefinition);
+
+        if (routerDeploymentDefinition.getGuestNetwork() != null) {
+            ipv6Service.updateNicIpv6(defaultNic, 
routerDeploymentDefinition.getDest().getDataCenter(), 
routerDeploymentDefinition.getGuestNetwork());
+        }
+        publicConfig.put(publicNetworks.get(0), List.of(defaultNic));
         return publicConfig;
     }
 
+    /**
+     * Configures the public NIC of a Virtual Router based on the provided 
source NAT IP.
+     * @param nic Virtual Router public NIC to be configured.
+     * @param sourceNatIp Source NAT IP which should be used to configure the 
Virtual Router's public NIC.
+     */
+    protected void configurePublicVrNicBasedOnSourceNatIp(NicProfile nic, 
PublicIp sourceNatIp) {
+        logger.debug("Configuring public NIC of VR with source NAT IP equal to 
[{}]", sourceNatIp.getAddress().addr());
+        nic.setDefaultNic(true);
+        nic.setIPv4Address(sourceNatIp.getAddress().addr());
+        nic.setIPv4Gateway(sourceNatIp.getGateway());
+        nic.setIPv4Netmask(sourceNatIp.getNetmask());
+        nic.setMacAddress(sourceNatIp.getMacAddress());
+
+        Network publicNetwork = 
_networkDao.findById(sourceNatIp.getNetworkId());
+        if (publicNetwork.getBroadcastDomainType() == 
BroadcastDomainType.Vxlan) {
+            nic.setBroadcastType(BroadcastDomainType.Vxlan);
+            
nic.setBroadcastUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
+            
nic.setIsolationUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
+        } else {
+            nic.setBroadcastType(BroadcastDomainType.Vlan);
+            nic.setBroadcastUri(sourceNatIp.getVlanTag() != null ? 
BroadcastDomainType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
+            nic.setIsolationUri(sourceNatIp.getVlanTag() != null ? 
IsolationType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
+        }
+    }
+
+    /**
+     * Sets the MAC address of the new VR's public NIC the same as the 
previous VR's public NIC MAC address if
+     * {@link RouterDeploymentDefinition#getKeepMacAddressOnPublicNic()} is 
set to {@code true} and a peer NIC is found; otherwise,
+     * does nothing.
+     */
+    protected void setPublicNicMacAddressSameAsPeerNic(NicProfile defaultNic, 
Network publicNetwork, RouterDeploymentDefinition routerDeploymentDefinition) 
throws InsufficientAddressCapacityException {
+        String publicIp = defaultNic.getIPv4Address();
+        logger.info("Verifying if we will use same MAC address for public NIC 
of new VR (with source NAT [{}]).", publicIp);
+
+        logger.debug("Searching for peer NIC for public IP [{}] and network 
[{}].", publicIp, publicNetwork.getUuid());
+        NicVO peerNic = _nicDao.findByIp4AddressAndNetworkId(publicIp, 
publicNetwork.getId());
+        if (peerNic == null) {
+            logger.info("We will not use the same MAC address for public NIC 
of new VR as we have not found a peer NIC for public IP [{}] and network [{}].",
+                    publicIp, publicNetwork.getUuid());
+            return;
+        }
+
+        logger.info("Found peer NIC [{}] for public IP [{}] and network 
[{}].", peerNic.getUuid(), publicIp, publicNetwork.getUuid());
+        boolean keepMacAddressOnPublicNic = 
routerDeploymentDefinition.getKeepMacAddressOnPublicNic();
+        String macAddressLog = String.format("same MAC address for public NIC 
of new VR (with source NAT [%s]) as the [keep_mac_address_on_public_nic] 
property is configured as [%s].", publicIp, keepMacAddressOnPublicNic);
+        if (keepMacAddressOnPublicNic) {
+            logger.info("Using {}", macAddressLog);
+            defaultNic.setMacAddress(peerNic.getMacAddress());
+            return;
+        }
+
+        logger.info("Not using {}", macAddressLog);
+        boolean fetchNewMacAddress = 
peerNic.getMacAddress().equals(defaultNic.getMacAddress());
+        if (fetchNewMacAddress) {
+            logger.debug("Fetching new MAC address for public NIC of new VR, 
since the MAC address of the peer NIC [UUID: {}, MAC address: {}] is equal to 
the predefined MAC address of the current NIC.", peerNic.getUuid(), 
peerNic.getMacAddress());
+            routerDeploymentDefinition.findSourceNatIP();
+            configurePublicVrNicBasedOnSourceNatIp(defaultNic, 
routerDeploymentDefinition.getSourceNatIP());
+        }
+    }
+
     @Override
     public LinkedHashMap<Network, List<? extends NicProfile>> 
configureDefaultNics(final RouterDeploymentDefinition 
routerDeploymentDefinition) throws ConcurrentOperationException, 
InsufficientAddressCapacityException {
 
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java 
b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index 5b4ab908ca4..c5f36e85655 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -1568,7 +1568,7 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = 
"creating vpc", create = true)
     public Vpc createVpc(final long zoneId, final long vpcOffId, final long 
vpcOwnerId, final String vpcName, final String displayText, final String cidr, 
String networkDomain,
                          final String ip4Dns1, final String ip4Dns2, final 
String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer 
publicMtu,
-                         final Integer cidrSize, final Long asNumber, final 
List<Long> bgpPeerIds, Boolean useVrIpResolver) throws 
ResourceAllocationException {
+                         final Integer cidrSize, final Long asNumber, final 
List<Long> bgpPeerIds, Boolean useVrIpResolver, boolean 
keepMacAddressOnPublicNic) throws ResourceAllocationException {
         final Account caller = CallContext.current().getCallingAccount();
         final Account owner = _accountMgr.getAccount(vpcOwnerId);
 
@@ -1668,6 +1668,7 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
         vpc.setPublicMtu(publicMtu);
         vpc.setDisplay(Boolean.TRUE.equals(displayVpc));
         vpc.setUseRouterIpResolver(Boolean.TRUE.equals(useVrIpResolver));
+        vpc.setKeepMacAddressOnPublicNic(keepMacAddressOnPublicNic);
 
         try (CheckedReservation vpcReservation = new CheckedReservation(owner, 
ResourceType.vpc, null, null, 1L, reservationDao, _resourceLimitMgr)) {
             if (vpc.getCidr() == null && cidrSize != null) {
@@ -1728,7 +1729,8 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
         List<Long> bgpPeerIds = (cmd instanceof CreateVPCCmdByAdmin) ? 
((CreateVPCCmdByAdmin)cmd).getBgpPeerIds() : null;
         Vpc vpc = createVpc(cmd.getZoneId(), cmd.getVpcOffering(), 
cmd.getEntityOwnerId(), cmd.getVpcName(), cmd.getDisplayText(),
             cmd.getCidr(), cmd.getNetworkDomain(), cmd.getIp4Dns1(), 
cmd.getIp4Dns2(), cmd.getIp6Dns1(),
-            cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu(), 
cmd.getCidrSize(), cmd.getAsNumber(), bgpPeerIds, cmd.getUseVrIpResolver());
+            cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu(), 
cmd.getCidrSize(), cmd.getAsNumber(), bgpPeerIds,
+            cmd.getUseVrIpResolver(), cmd.getKeepMacAddressOnPublicNic());
 
         String sourceNatIP = cmd.getSourceNatIP();
         boolean forNsx = isVpcForProvider(Provider.Nsx, vpc);
@@ -1940,12 +1942,14 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
 
     @Override
     public Vpc updateVpc(UpdateVPCCmd cmd) throws 
ResourceUnavailableException, InsufficientCapacityException {
-        return updateVpc(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), 
cmd.getCustomId(), cmd.isDisplayVpc(), cmd.getPublicMtu(), 
cmd.getSourceNatIP());
+        return updateVpc(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), 
cmd.getCustomId(),
+                cmd.isDisplayVpc(), cmd.getPublicMtu(), cmd.getSourceNatIP(), 
cmd.getKeepMacAddressOnPublicNic());
     }
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = 
"updating vpc")
-    public Vpc updateVpc(final long vpcId, final String vpcName, final String 
displayText, final String customId, final Boolean displayVpc, Integer mtu, 
String sourceNatIp) throws ResourceUnavailableException, 
InsufficientCapacityException {
+    public Vpc updateVpc(final long vpcId, final String vpcName, final String 
displayText, final String customId,
+                         final Boolean displayVpc, Integer mtu, String 
sourceNatIp, Boolean keepMacAddressOnPublicNic) throws 
ResourceUnavailableException, InsufficientCapacityException {
         final Account caller = CallContext.current().getCallingAccount();
 
         // Verify input parameters
@@ -1977,6 +1981,10 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
             vpc.setDisplay(displayVpc);
         }
 
+        if (keepMacAddressOnPublicNic != null) {
+            vpc.setKeepMacAddressOnPublicNic(keepMacAddressOnPublicNic);
+        }
+
         mtu = validateMtu(vpcToUpdate, mtu);
         if (mtu != null) {
             updateMtuOfVpcNetwork(vpcToUpdate, vpc, mtu);
diff --git 
a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java
 
b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java
index 4187586736d..77cd7890e41 100644
--- 
a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java
+++ 
b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java
@@ -394,7 +394,7 @@ public class RouterDeploymentDefinition {
         }
     }
 
-    protected void findSourceNatIP() throws 
InsufficientAddressCapacityException, ConcurrentOperationException {
+    public void findSourceNatIP() throws InsufficientAddressCapacityException, 
ConcurrentOperationException {
         sourceNatIp = null;
         DataCenter zone = dest.getDataCenter();
         Long zoneId = null;
@@ -548,4 +548,8 @@ public class RouterDeploymentDefinition {
 
         return needReset;
     }
+
+    public boolean getKeepMacAddressOnPublicNic() {
+        return guestNetwork == null || 
guestNetwork.getKeepMacAddressOnPublicNic();
+    }
 }
diff --git 
a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
 
b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
index 063565ebf46..9e432265f2a 100644
--- 
a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
+++ 
b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
@@ -117,7 +117,7 @@ public class VpcRouterDeploymentDefinition extends 
RouterDeploymentDefinition {
     }
 
     @Override
-    protected void findSourceNatIP() throws 
InsufficientAddressCapacityException, ConcurrentOperationException {
+    public void findSourceNatIP() throws InsufficientAddressCapacityException, 
ConcurrentOperationException {
         sourceNatIp = null;
         DataCenter zone = dest.getDataCenter();
         Long zoneId = null;
@@ -219,4 +219,9 @@ public class VpcRouterDeploymentDefinition extends 
RouterDeploymentDefinition {
     public boolean isRollingRestart() {
         return vpc.isRollingRestart();
     }
+
+    @Override
+    public boolean getKeepMacAddressOnPublicNic() {
+        return vpc == null || vpc.getKeepMacAddressOnPublicNic();
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java 
b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
index 51b2dad3dec..cd7d40d6895 100644
--- a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
@@ -460,7 +460,7 @@ public class NetworkServiceImplTest {
                 null, null, false, null, accountMock, null, phyNet,
                 1L, null, null, null, null, null,
                 true, null, null, null, null, null,
-                null, null, null, null, new Pair<>(1500, privateMtu), null);
+                null, null, null, null, new Pair<>(1500, privateMtu), null, 
true);
     }
     @Test
     public void testValidateMtuConfigWhenMtusExceedThreshold() {
@@ -1330,4 +1330,52 @@ public class NetworkServiceImplTest {
         Mockito.verify(accountJoin).addAnd("type", SearchCriteria.Op.EQ, 
Account.Type.PROJECT);
         Mockito.verify(sc).addAnd("id", SearchCriteria.Op.SC, accountJoin);
     }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void 
getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestThrowExceptionWhenParamIsSpecifiedOnTiersCreation()
 {
+        networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
+        Mockito.when(networkOfferingVO.isForVpc()).thenReturn(true);
+
+        
service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(true, 
networkOfferingVO);
+    }
+
+    @Test
+    public void 
getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnTrueByDefaultOnTiersCreation()
 {
+        networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
+        Mockito.when(networkOfferingVO.isForVpc()).thenReturn(true);
+
+        
Assert.assertTrue(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(null,
 networkOfferingVO));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void 
getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestThrowExceptionWhenParamIsSpecifiedOnNonIsolatedNetworksCreation()
 {
+        networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
+        
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.Shared);
+
+        
service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(true, 
networkOfferingVO);
+    }
+
+    @Test
+    public void 
getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnTrueByDefaultOnNonIsolatedNetworksCreation()
 {
+        networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
+        
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.L2);
+
+        
Assert.assertTrue(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(null,
 networkOfferingVO));
+    }
+
+    @Test
+    public void 
getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnTrueByDefaultOnIsolatedNetworksCreation()
 {
+        networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
+        
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.Isolated);
+
+        
Assert.assertTrue(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(null,
 networkOfferingVO));
+    }
+
+    @Test
+    public void 
getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnSpecifiedValueOnIsolatedNetworksCreation()
 {
+        networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
+        
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.Isolated);
+
+        
Assert.assertFalse(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(false,
 networkOfferingVO));
+    }
 }
diff --git 
a/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java 
b/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java
index 4237ef7f6f6..e4773d01de9 100644
--- a/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java
+++ b/server/src/test/java/com/cloud/network/router/NetworkHelperImplTest.java
@@ -24,18 +24,31 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.network.Ipv6Service;
+import com.cloud.network.Network;
+import com.cloud.network.Networks;
+import com.cloud.network.addr.PublicIp;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.utils.net.Ip;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
 import 
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import 
org.apache.cloudstack.network.router.deployment.RouterDeploymentDefinition;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.AgentManager;
@@ -57,6 +70,9 @@ import com.cloud.vm.VirtualMachineName;
 import com.cloud.vm.dao.DomainRouterDao;
 import com.cloud.vm.dao.NicDao;
 
+import java.util.List;
+import java.util.Map;
+
 
 @RunWith(MockitoJUnitRunner.class)
 public class NetworkHelperImplTest {
@@ -69,32 +85,59 @@ public class NetworkHelperImplTest {
     @Mock
     DomainRouterDao routerDao;
 
+    @Spy
     @InjectMocks
-    protected NetworkHelperImpl nwHelper = new NetworkHelperImpl();
+    protected NetworkHelperImpl networkHelperSpy = new NetworkHelperImpl();
+
     @Mock
     NetworkOrchestrationService networkOrchestrationService;
+
     @Mock
     NetworkDao networkDao;
+
     @Mock
     NetworkModel networkModel;
+
     @Mock
-    NicDao nicDao;
+    private NicDao nicDaoMock;
 
     @Mock
     private RouterDeploymentDefinition routerDeploymentDefinition;
+
     @Mock
     private VirtualRouterProvider virtualProvider;
+
     @Mock
     private Account owner;
+
     @Mock
     private ServiceOfferingVO routerOffering;
+
     @Mock
     private VMTemplateVO template;
 
+    @Mock
+    private PublicIp publicIpMock;
+
+    @Mock
+    private RouterDeploymentDefinition routerDeploymentDefinitionMock;
+
+    @Mock
+    private Ipv6Service ipv6ServiceMock;
+
+    @Mock
+    private NicVO nicVoMock;
+
+    @Mock
+    private Network networkMock;
+
+    private NicProfile nicProfile = new NicProfile();
+
     @Before
     public void setUp() {
-        nwHelper._networkDao = networkDao;
-        nwHelper._networkModel = networkModel;
+        networkHelperSpy._networkDao = networkDao;
+        networkHelperSpy._networkModel = networkModel;
+
         when(template.getId()).thenReturn(1L);
         when(template.isDynamicallyScalable()).thenReturn(true);
         when(virtualProvider.getId()).thenReturn(1L);
@@ -107,7 +150,7 @@ public class NetworkHelperImplTest {
     public void testSendCommandsToRouterWrongRouterVersion()
             throws AgentUnavailableException, OperationTimedoutException, 
ResourceUnavailableException {
         // Prepare
-        NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
+        NetworkHelperImpl nwHelperUT = networkHelperSpy;
         VirtualRouter vr = mock(VirtualRouter.class);
         doReturn(false).when(nwHelperUT).checkRouterVersion(vr);
 
@@ -122,7 +165,7 @@ public class NetworkHelperImplTest {
     public void testSendCommandsToRouter()
             throws AgentUnavailableException, OperationTimedoutException, 
ResourceUnavailableException {
         // Prepare
-        NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
+        NetworkHelperImpl nwHelperUT = networkHelperSpy;
         VirtualRouter vr = mock(VirtualRouter.class);
         when(vr.getHostId()).thenReturn(HOST_ID);
         doReturn(true).when(nwHelperUT).checkRouterVersion(vr);
@@ -160,7 +203,7 @@ public class NetworkHelperImplTest {
     public void testSendCommandsToRouterWithTrueResult()
             throws AgentUnavailableException, OperationTimedoutException, 
ResourceUnavailableException {
         // Prepare
-        NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
+        NetworkHelperImpl nwHelperUT = networkHelperSpy;
         VirtualRouter vr = mock(VirtualRouter.class);
         when(vr.getHostId()).thenReturn(HOST_ID);
         doReturn(true).when(nwHelperUT).checkRouterVersion(vr);
@@ -198,7 +241,7 @@ public class NetworkHelperImplTest {
     public void testSendCommandsToRouterWithNoAnswers()
             throws AgentUnavailableException, OperationTimedoutException, 
ResourceUnavailableException {
         // Prepare
-        NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
+        NetworkHelperImpl nwHelperUT = networkHelperSpy;
         VirtualRouter vr = mock(VirtualRouter.class);
         when(vr.getHostId()).thenReturn(HOST_ID);
         doReturn(true).when(nwHelperUT).checkRouterVersion(vr);
@@ -227,7 +270,7 @@ public class NetworkHelperImplTest {
         boolean offerHA = false;
         Long vpcId = 900L;
         
when(routerDao.persist(any(DomainRouterVO.class))).thenAnswer(invocation -> 
invocation.getArgument(0));
-        DomainRouterVO result = nwHelper.createOrUpdateDomainRouter(
+        DomainRouterVO result = networkHelperSpy.createOrUpdateDomainRouter(
                 null, id, routerDeploymentDefinition, owner, userId, 
routerOffering, offerHA, vpcId, template);
         assertNotNull(result);
         assertEquals(id, result.getId());
@@ -261,11 +304,234 @@ public class NetworkHelperImplTest {
                 owner.getDomainId(), owner.getId(), userId, 
routerDeploymentDefinition.isRedundant(), VirtualRouter.RedundantState.UNKNOWN,
                 offerHA, false, vpcId);
         existing.setDynamicallyScalable(false);
-        DomainRouterVO result = nwHelper.createOrUpdateDomainRouter(
+        DomainRouterVO result = networkHelperSpy.createOrUpdateDomainRouter(
                 existing, id, routerDeploymentDefinition, owner, userId, 
routerOffering, offerHA, vpcId, template);
         verify(routerDao).update(existing.getId(), existing);
         assertEquals(template.getId(), result.getTemplateId());
         assertEquals(Hypervisor.HypervisorType.KVM, 
result.getHypervisorType());
         assertTrue(result.isDynamicallyScalable());
     }
+
+
+    private NicProfile getExpectedNicProfile(boolean vxlan, String vlanTag) {
+        NicProfile nic = new NicProfile();
+        nic.setDefaultNic(true);
+        nic.setIPv4Address("192.168.0.10");
+        nic.setIPv4Gateway("192.168.0.1");
+        nic.setIPv4Netmask("255.255.255.0");
+        nic.setMacAddress("ff-ff-ff-ff-ff-ff");
+
+        if (vxlan) {
+            nic.setBroadcastType(Networks.BroadcastDomainType.Vxlan);
+            
nic.setBroadcastUri(Networks.BroadcastDomainType.Vxlan.toUri(vlanTag));
+            
nic.setIsolationUri(Networks.BroadcastDomainType.Vxlan.toUri(vlanTag));
+        } else {
+            nic.setBroadcastType(Networks.BroadcastDomainType.Vlan);
+            nic.setBroadcastUri(vlanTag != null ? 
Networks.BroadcastDomainType.Vlan.toUri(vlanTag) : null);
+            nic.setIsolationUri(vlanTag != null ? 
Networks.IsolationType.Vlan.toUri(vlanTag) : null);
+        }
+
+        return nic;
+    }
+
+    @Test
+    public void configurePublicVrNicBasedOnSourceNatIpTestConfigureVxLanNic() {
+        String vlanTag = "200";
+        NicProfile expected = getExpectedNicProfile(true, vlanTag);
+
+        Ip ipMock = Mockito.mock(Ip.class);
+        NetworkVO publicNetworkMock = Mockito.mock(NetworkVO.class);
+        long networkId = 1L;
+        Mockito.when(publicIpMock.getAddress()).thenReturn(ipMock);
+        Mockito.when(ipMock.addr()).thenReturn(expected.getIPv4Address());
+        
Mockito.when(publicIpMock.getGateway()).thenReturn(expected.getIPv4Gateway());
+        
Mockito.when(publicIpMock.getNetmask()).thenReturn(expected.getIPv4Netmask());
+        
Mockito.when(publicIpMock.getMacAddress()).thenReturn(expected.getMacAddress());
+        Mockito.when(publicIpMock.getNetworkId()).thenReturn(networkId);
+        
Mockito.when(networkDao.findById(networkId)).thenReturn(publicNetworkMock);
+        
Mockito.when(publicNetworkMock.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Vxlan);
+        Mockito.when(publicIpMock.getVlanTag()).thenReturn(vlanTag);
+
+        networkHelperSpy.configurePublicVrNicBasedOnSourceNatIp(nicProfile, 
publicIpMock);
+
+        Assert.assertTrue(nicProfile.isDefaultNic());
+        Assert.assertEquals(expected.getIPv4Address(), 
nicProfile.getIPv4Address());
+        Assert.assertEquals(expected.getIPv4Gateway(), 
nicProfile.getIPv4Gateway());
+        Assert.assertEquals(expected.getIPv4Netmask(), 
nicProfile.getIPv4Netmask());
+        Assert.assertEquals(expected.getMacAddress(), 
nicProfile.getMacAddress());
+        Assert.assertEquals(expected.getBroadcastType(), 
nicProfile.getBroadcastType());
+        Assert.assertEquals(expected.getBroadCastUri(), 
nicProfile.getBroadCastUri());
+        Assert.assertEquals(expected.getIsolationUri(), 
nicProfile.getIsolationUri());
+    }
+
+    @Test
+    public void 
configurePublicVrNicBasedOnSourceNatIpTestConfigureVlanNicWithVlanTag() {
+        String vlanTag = "200";
+        NicProfile expected = getExpectedNicProfile(false, vlanTag);
+
+        Ip ipMock = Mockito.mock(Ip.class);
+        NetworkVO publicNetworkMock = Mockito.mock(NetworkVO.class);
+        long networkId = 1L;
+        Mockito.when(publicIpMock.getAddress()).thenReturn(ipMock);
+        Mockito.when(ipMock.addr()).thenReturn(expected.getIPv4Address());
+        
Mockito.when(publicIpMock.getGateway()).thenReturn(expected.getIPv4Gateway());
+        
Mockito.when(publicIpMock.getNetmask()).thenReturn(expected.getIPv4Netmask());
+        
Mockito.when(publicIpMock.getMacAddress()).thenReturn(expected.getMacAddress());
+        Mockito.when(publicIpMock.getNetworkId()).thenReturn(networkId);
+        
Mockito.when(networkDao.findById(networkId)).thenReturn(publicNetworkMock);
+        
Mockito.when(publicNetworkMock.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Vlan);
+        Mockito.when(publicIpMock.getVlanTag()).thenReturn(vlanTag);
+
+        networkHelperSpy.configurePublicVrNicBasedOnSourceNatIp(nicProfile, 
publicIpMock);
+
+        Assert.assertTrue(nicProfile.isDefaultNic());
+        Assert.assertEquals(expected.getIPv4Address(), 
nicProfile.getIPv4Address());
+        Assert.assertEquals(expected.getIPv4Gateway(), 
nicProfile.getIPv4Gateway());
+        Assert.assertEquals(expected.getIPv4Netmask(), 
nicProfile.getIPv4Netmask());
+        Assert.assertEquals(expected.getMacAddress(), 
nicProfile.getMacAddress());
+        Assert.assertEquals(expected.getBroadcastType(), 
nicProfile.getBroadcastType());
+        Assert.assertEquals(expected.getBroadCastUri(), 
nicProfile.getBroadCastUri());
+        Assert.assertEquals(expected.getIsolationUri(), 
nicProfile.getIsolationUri());
+    }
+
+    @Test
+    public void 
configurePublicVrNicBasedOnSourceNatIpTestConfigureVlanNicWithNoVlanTag() {
+        String vlanTag = null;
+        NicProfile expected = getExpectedNicProfile(false, vlanTag);
+
+        Ip ipMock = Mockito.mock(Ip.class);
+        NetworkVO publicNetworkMock = Mockito.mock(NetworkVO.class);
+        long networkId = 1L;
+        Mockito.when(publicIpMock.getAddress()).thenReturn(ipMock);
+        Mockito.when(ipMock.addr()).thenReturn(expected.getIPv4Address());
+        
Mockito.when(publicIpMock.getGateway()).thenReturn(expected.getIPv4Gateway());
+        
Mockito.when(publicIpMock.getNetmask()).thenReturn(expected.getIPv4Netmask());
+        
Mockito.when(publicIpMock.getMacAddress()).thenReturn(expected.getMacAddress());
+        Mockito.when(publicIpMock.getNetworkId()).thenReturn(networkId);
+        
Mockito.when(networkDao.findById(networkId)).thenReturn(publicNetworkMock);
+        
Mockito.when(publicNetworkMock.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Vlan);
+        Mockito.when(publicIpMock.getVlanTag()).thenReturn(vlanTag);
+
+        networkHelperSpy.configurePublicVrNicBasedOnSourceNatIp(nicProfile, 
publicIpMock);
+
+        Assert.assertTrue(nicProfile.isDefaultNic());
+        Assert.assertEquals(expected.getIPv4Address(), 
nicProfile.getIPv4Address());
+        Assert.assertEquals(expected.getIPv4Gateway(), 
nicProfile.getIPv4Gateway());
+        Assert.assertEquals(expected.getIPv4Netmask(), 
nicProfile.getIPv4Netmask());
+        Assert.assertEquals(expected.getMacAddress(), 
nicProfile.getMacAddress());
+        Assert.assertEquals(expected.getBroadcastType(), 
nicProfile.getBroadcastType());
+        Assert.assertEquals(expected.getBroadCastUri(), 
nicProfile.getBroadCastUri());
+        Assert.assertEquals(expected.getIsolationUri(), 
nicProfile.getIsolationUri());
+    }
+
+    @Test
+    public void 
setPublicNicMacAddressSameAsPeerNicTestDoNothingWhenThereIsNoPeer() throws 
InsufficientAddressCapacityException {
+        String newMacAddress = "ff-ff-ff-ff-ff-ff";
+        nicProfile.setIPv4Address("10.0.0.1");
+        nicProfile.setMacAddress(newMacAddress);
+        
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), 
Mockito.anyLong())).thenReturn(null);
+
+        networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, 
networkMock, routerDeploymentDefinitionMock);
+
+        Assert.assertEquals(newMacAddress, nicProfile.getMacAddress());
+    }
+
+    @Test
+    public void setPublicNicMacAddressSameAsPeerNicTestKeepMacAddress() throws 
InsufficientAddressCapacityException {
+        String peerMacAddress = "ff-ff-ff-ff-ff-ff";
+        nicProfile.setIPv4Address("10.0.0.1");
+        nicProfile.setMacAddress("ff-ff-ff-ff-ff-f1");
+
+        
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), 
Mockito.anyLong())).thenReturn(nicVoMock);
+        Mockito.when(nicVoMock.getMacAddress()).thenReturn(peerMacAddress);
+        
Mockito.when(routerDeploymentDefinitionMock.getKeepMacAddressOnPublicNic()).thenReturn(true);
+
+        networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, 
networkMock, routerDeploymentDefinitionMock);
+
+        Assert.assertEquals(peerMacAddress, nicProfile.getMacAddress());
+    }
+
+    @Test
+    public void 
setPublicNicMacAddressSameAsPeerNicTestDifferentMacAddressFetchingNewSourceNatIp()
 throws InsufficientAddressCapacityException {
+        String macAddress = "ff-ff-ff-ff-ff-f1";
+        nicProfile.setIPv4Address("10.0.0.1");
+        nicProfile.setMacAddress(macAddress);
+        PublicIp publicIpMock = Mockito.mock(PublicIp.class);
+
+        
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), 
Mockito.anyLong())).thenReturn(nicVoMock);
+        Mockito.when(nicVoMock.getMacAddress()).thenReturn(macAddress);
+        
Mockito.when(routerDeploymentDefinitionMock.getKeepMacAddressOnPublicNic()).thenReturn(false);
+        
Mockito.when(routerDeploymentDefinitionMock.getSourceNatIP()).thenReturn(publicIpMock);
+        
Mockito.doNothing().when(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(nicProfile,
 publicIpMock);
+
+        networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, 
networkMock, routerDeploymentDefinitionMock);
+
+        Mockito.verify(routerDeploymentDefinitionMock).findSourceNatIP();
+        
Mockito.verify(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(nicProfile,
 publicIpMock);
+    }
+
+    @Test
+    public void 
setPublicNicMacAddressSameAsPeerNicTestDifferentMacAddressNotFetchingNewSourceNatIp()
 throws InsufficientAddressCapacityException {
+        String newMacAddress = "ff-ff-ff-ff-ff-ff";
+        nicProfile.setIPv4Address("10.0.0.1");
+        nicProfile.setMacAddress(newMacAddress);
+
+        
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), 
Mockito.anyLong())).thenReturn(nicVoMock);
+        
Mockito.when(nicVoMock.getMacAddress()).thenReturn("ff-ff-ff-ff-ff-f1");
+        
Mockito.when(routerDeploymentDefinitionMock.getKeepMacAddressOnPublicNic()).thenReturn(false);
+
+        networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, 
networkMock, routerDeploymentDefinitionMock);
+
+        Mockito.verify(routerDeploymentDefinitionMock, 
Mockito.never()).findSourceNatIP();
+        Mockito.verify(networkHelperSpy, 
Mockito.never()).configurePublicVrNicBasedOnSourceNatIp(Mockito.any(), 
Mockito.any());
+        Assert.assertEquals(newMacAddress, nicProfile.getMacAddress());
+    }
+
+    @Test
+    public void configurePublicNicTestReturnEmptyMapWhenNetworkIsNotPublic() 
throws InsufficientAddressCapacityException {
+        
Mockito.when(routerDeploymentDefinitionMock.isPublicNetwork()).thenReturn(false);
+
+        Map<Network, List<? extends NicProfile>> nic = 
networkHelperSpy.configurePublicNic(routerDeploymentDefinitionMock, false);
+        Assert.assertTrue(nic.isEmpty());
+    }
+
+    @Test
+    public void configurePublicNicTestConfigureDeviceId() throws 
InsufficientAddressCapacityException {
+        PublicIp publicIpMock = Mockito.mock(PublicIp.class);
+        NetworkOffering networkOfferingMock = 
Mockito.mock(NetworkOffering.class);
+
+        
Mockito.when(routerDeploymentDefinitionMock.isPublicNetwork()).thenReturn(true);
+        
Mockito.when(routerDeploymentDefinitionMock.getSourceNatIP()).thenReturn(publicIpMock);
+        
Mockito.doNothing().when(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(Mockito.any(),
 Mockito.any());
+        
Mockito.doReturn(List.of(networkOfferingMock)).when(networkModel).getSystemAccountNetworkOfferings(Mockito.any());
+        
Mockito.doReturn(List.of(networkMock)).when(networkOrchestrationService).setupNetwork(
+                Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), 
Mockito.any(), Mockito.anyBoolean()
+        );
+        
Mockito.doNothing().when(networkHelperSpy).setPublicNicMacAddressSameAsPeerNic(Mockito.any(),
 Mockito.any(), Mockito.any());
+
+        Map<Network, List<? extends NicProfile>> nic = 
networkHelperSpy.configurePublicNic(routerDeploymentDefinitionMock, true);
+        Integer nicDeviceId = nic.get(networkMock).get(0).getDeviceId();
+        Assert.assertEquals(2, nicDeviceId.intValue());
+    }
+
+    @Test
+    public void configurePublicNicTestUpdateGuestNetworksIpv6Nic() throws 
InsufficientAddressCapacityException {
+        PublicIp publicIpMock = Mockito.mock(PublicIp.class);
+        NetworkOffering networkOfferingMock = 
Mockito.mock(NetworkOffering.class);
+        DeployDestination deployDestinationMock = 
Mockito.mock(DeployDestination.class);
+
+        
Mockito.when(routerDeploymentDefinitionMock.isPublicNetwork()).thenReturn(true);
+        
Mockito.when(routerDeploymentDefinitionMock.getSourceNatIP()).thenReturn(publicIpMock);
+        
Mockito.doNothing().when(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(Mockito.any(),
 Mockito.any());
+        
Mockito.doReturn(List.of(networkOfferingMock)).when(networkModel).getSystemAccountNetworkOfferings(Mockito.any());
+        
Mockito.doReturn(List.of(networkMock)).when(networkOrchestrationService).setupNetwork(
+                Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), 
Mockito.any(), Mockito.anyBoolean()
+        );
+        
Mockito.doNothing().when(networkHelperSpy).setPublicNicMacAddressSameAsPeerNic(Mockito.any(),
 Mockito.any(), Mockito.any());
+        
Mockito.when(routerDeploymentDefinitionMock.getGuestNetwork()).thenReturn(networkMock);
+        
Mockito.when(routerDeploymentDefinitionMock.getDest()).thenReturn(deployDestinationMock);
+
+        Map<Network, List<? extends NicProfile>> nic = 
networkHelperSpy.configurePublicNic(routerDeploymentDefinitionMock, false);
+        
Mockito.verify(ipv6ServiceMock).updateNicIpv6(Mockito.eq(nic.get(networkMock).get(0)),
 Mockito.any(), Mockito.eq(networkMock));
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java 
b/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
index 9569769b016..8b8259421cd 100644
--- a/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
@@ -492,7 +492,7 @@ public class VpcManagerImplTest {
         mockVpcDnsResources(false, false);
         try {
             manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, 
vpcName, ip4Cidr, vpcDomain,
-                    ip4Dns[0], null, null, null, true, 1500, null, null, null, 
false);
+                    ip4Dns[0], null, null, null, true, 1500, null, null, null, 
false, true);
         } catch (ResourceAllocationException e) {
             Assert.fail(String.format("failure with exception: %s", 
e.getMessage()));
         }
@@ -503,7 +503,7 @@ public class VpcManagerImplTest {
         mockVpcDnsResources(true, false);
         try {
             manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, 
vpcName, ip4Cidr, vpcDomain,
-                    ip4Dns[0], ip4Dns[1], ip6Dns[0], null, true, 1500, null, 
null, null, false);
+                    ip4Dns[0], ip4Dns[1], ip6Dns[0], null, true, 1500, null, 
null, null, false, true);
         } catch (ResourceAllocationException e) {
             Assert.fail(String.format("failure with exception: %s", 
e.getMessage()));
         }
@@ -517,7 +517,7 @@ public class VpcManagerImplTest {
         Mockito.when(vpc.getUuid()).thenReturn("uuid");
         try (MockedConstruction<CheckedReservation> mockCheckedReservation = 
Mockito.mockConstruction(CheckedReservation.class)) {
             manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, 
vpcName, ip4Cidr, vpcDomain,
-                    ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, 
null, false);
+                    ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, 
null, false, true);
         } catch (ResourceAllocationException e) {
             Assert.fail(String.format("failure with exception: %s", 
e.getMessage()));
         }
@@ -533,7 +533,7 @@ public class VpcManagerImplTest {
         doNothing().when(routedIpv4Manager).getOrCreateIpv4SubnetForVpc(any(), 
anyString());
         try (MockedConstruction<CheckedReservation> mockCheckedReservation = 
Mockito.mockConstruction(CheckedReservation.class)) {
             manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, 
vpcName, ip4Cidr, vpcDomain,
-                    ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, 
null, false);
+                    ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, 
null, false, true);
         } catch (ResourceAllocationException e) {
             Assert.fail(String.format("failure with exception: %s", 
e.getMessage()));
         }
@@ -556,7 +556,7 @@ public class VpcManagerImplTest {
         try (MockedConstruction<CheckedReservation> mockCheckedReservation = 
Mockito.mockConstruction(CheckedReservation.class)) {
 
             manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, 
vpcName, null, vpcDomain,
-                    ip4Dns[0], ip4Dns[1], null, null, true, 1500, 24, null, 
bgpPeerIds, false);
+                    ip4Dns[0], ip4Dns[1], null, null, true, 1500, 24, null, 
bgpPeerIds, false, true);
         } catch (ResourceAllocationException e) {
             Assert.fail(String.format("failure with exception: %s", 
e.getMessage()));
         }
diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java 
b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
index 3b120b88db4..e4bc2096b9d 100644
--- a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -704,11 +704,19 @@ public class MockNetworkManagerImpl extends ManagerBase 
implements NetworkOrches
     public Network createGuestNetwork(long networkOfferingId, String name, 
String displayText, String gateway, String cidr, String vlanId, boolean 
bypassVlanOverlapCheck, String networkDomain,
                                       Account owner, Long domainId, 
PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean 
subdomainAccess, Long vpcId, String gatewayv6,
                                       String cidrv6, Boolean 
displayNetworkEnabled, String isolatedPvlan, Network.PVlanType 
isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
-                                      String ip4Dns1, String ip4Dns2, String 
ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer 
networkCidrSize) throws ConcurrentOperationException, 
ResourceAllocationException {
+                                      String ip4Dns1, String ip4Dns2, String 
ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer 
networkCidrSize) throws ConcurrentOperationException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
+    public Network createGuestNetwork(long networkOfferingId, String name, 
String displayText, String gateway, String cidr, String vlanId, boolean 
bypassVlanOverlapCheck, String networkDomain,
+                                      Account owner, Long domainId, 
PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean 
subdomainAccess, Long vpcId, String gatewayv6,
+                                      String cidrv6, Boolean 
displayNetworkEnabled, String isolatedPvlan, Network.PVlanType 
isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
+                                      String ip4Dns1, String ip4Dns2, String 
ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer 
networkCidrSize, boolean keepMacAddressOnPublicNic) throws 
ConcurrentOperationException {
+        return null;
+    }
+
     /* (non-Javadoc)
      * @see 
com.cloud.network.NetworkManager#getPasswordResetProvider(com.cloud.network.Network)
      */
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index e2045eba8df..f0a6ad3c79b 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -1433,6 +1433,7 @@
 "label.javadistribution": "Java Runtime Distribution",
 "label.javaversion": "Java Runtime Version",
 "label.keep": "Keep",
+"label.keep.mac.address.on.public.nic": "Use same MAC address for public NIC 
of VRs",
 "label.kernelversion": "Kernel Version",
 "label.key": "Key",
 "label.keyboard": "Keyboard language",
diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json
index c7ca36c1278..d2910a3a2b9 100644
--- a/ui/public/locales/pt_BR.json
+++ b/ui/public/locales/pt_BR.json
@@ -904,6 +904,7 @@
 "label.items.selected": "item(ns) selecionados",
 "label.japanese.keyboard": "Teclado japon\u00eas",
 "label.keep": "Manter",
+"label.keep.mac.address.on.public.nic": "Utilizar o mesmo endere\u00e7o MAC 
para a NIC p\u00fablica dos VRs",
 "label.key": "Chave",
 "label.keyboard": "Linguagem do teclado",
 "label.keyboardtype": "Tipo de teclado",
diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js
index 37cdd0c8b98..50c2ff4250b 100644
--- a/ui/src/config/section/network.js
+++ b/ui/src/config/section/network.js
@@ -49,9 +49,14 @@ export default {
         return fields
       },
       details: () => {
-        var fields = ['name', 'id', 'description', 'type', 'traffictype', 
'vpcid', 'vlan', 'broadcasturi', 'cidr', 'ip6cidr', 'netmask', 'gateway', 
'asnumber', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 
'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 
'account', 'domainpath', 'associatednetwork', 'associatednetworkid', 
'ip4routing', 'ip6firewall', 'ip6routing', 'ip6routes', 'dns1', 'dns2', 
'ip6dns1', 'ip6dns2', 'publicmtu', 'privatemtu']
-        if (!isAdmin()) {
-          fields = fields.filter(function (e) { return e !== 'broadcasturi' })
+        const fields = ['name', 'id', 'description', 'type', 'traffictype', 
'vpcid', 'vlan', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'asnumber', 
'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 
'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 
'account', 'domainpath', 'associatednetwork', 'associatednetworkid', 
'ip4routing', 'ip6firewall', 'ip6routing', 'ip6routes', 'dns1', 'dns2', 
'ip6dns1', 'ip6dns2', 'publicmtu', 'privatemtu']
+        if (isAdmin()) {
+          const vlanIndex = fields.findIndex(detail => detail === 'vlan')
+          fields.splice(vlanIndex + 1, 0, 'broadcasturi')
+          fields.push({
+            field: 'keepmacaddressonpublicnic',
+            customTitle: 'keep.mac.address.on.public.nic'
+          })
         }
         return fields
       },
@@ -233,7 +238,16 @@ export default {
         fields.push(...['domain', 'zonename'])
         return fields
       },
-      details: ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 
'ip4routing', 'ip4routes', 'ip6routes', 'ispersistent', 'redundantvpcrouter', 
'restartrequired', 'zonename', 'account', 'domain', 'dns1', 'dns2', 'ip6dns1', 
'ip6dns2', 'publicmtu'],
+      details: () => {
+        const fields = ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 
'ip4routing', 'ip4routes', 'ip6routes', 'ispersistent', 'redundantvpcrouter', 
'restartrequired', 'zonename', 'account', 'domain', 'dns1', 'dns2', 'ip6dns1', 
'ip6dns2', 'publicmtu']
+        if (isAdmin()) {
+          fields.push({
+            field: 'keepmacaddressonpublicnic',
+            customTitle: 'keep.mac.address.on.public.nic'
+          })
+        }
+        return fields
+      },
       searchFilters: ['name', 'zoneid', 'domainid', 'account', 
'restartrequired', 'tags'],
       related: [{
         name: 'vm',
@@ -268,7 +282,13 @@ export default {
           icon: 'edit-outlined',
           label: 'label.edit',
           dataView: true,
-          args: ['name', 'displaytext', 'publicmtu', 'sourcenatipaddress']
+          args: () => {
+            const fields = ['name', 'displaytext', 'publicmtu', 
'sourcenatipaddress']
+            if (isAdmin()) {
+              fields.push('keepmacaddressonpublicnic')
+            }
+            return fields
+          }
         },
         {
           api: 'restartVPC',
diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue
index f4aa842d8f2..066226980c5 100644
--- a/ui/src/views/AutogenView.vue
+++ b/ui/src/views/AutogenView.vue
@@ -294,6 +294,11 @@
                     :title="$t('label.default.network.' + field.name + 
'.isolated.network')"
                     :tooltip="field.description"
                   />
+                  <tooltip-label
+                    v-else-if="field.name === 'keepmacaddressonpublicnic' && 
currentAction.api === 'updateVPC'"
+                    :title="$t('label.keep.mac.address.on.public.nic')"
+                    :tooltip="field.description"
+                  />
                   <tooltip-label
                     v-else
                     :title="$t('label.' + field.name)"
diff --git a/ui/src/views/network/CreateIsolatedNetworkForm.vue 
b/ui/src/views/network/CreateIsolatedNetworkForm.vue
index 7dc4dbe75e3..8d6fed9cf12 100644
--- a/ui/src/views/network/CreateIsolatedNetworkForm.vue
+++ b/ui/src/views/network/CreateIsolatedNetworkForm.vue
@@ -294,6 +294,15 @@
               v-model:value="form.sourcenatipaddress"
               :placeholder="apiParams.sourcenatipaddress?.description"/>
           </a-form-item>
+          <a-form-item name="keepMacAddressOnPublicNic" 
ref="keepMacAddressOnPublicNic" v-if="isAdmin() && 
!selectedNetworkOffering?.forvpc">
+            <template #label>
+              <tooltip-label
+                :title="$t('label.keep.mac.address.on.public.nic')"
+                :tooltip="apiParams.keepmacaddressonpublicnic?.description"
+              />
+            </template>
+            <a-switch v-model:checked="form.keepMacAddressOnPublicNic" />
+          </a-form-item>
           <div :span="24" class="action-button">
             <a-button
               :loading="actionLoading"
@@ -408,7 +417,9 @@ export default {
   methods: {
     initForm () {
       this.formRef = ref()
-      this.form = reactive({})
+      this.form = reactive({
+        keepMacAddressOnPublicNic: true
+      })
       this.rules = reactive({
         name: [{ required: true, message: this.$t('message.error.name') }],
         zoneid: [{ type: 'number', required: true, message: 
this.$t('message.error.select') }],
@@ -600,14 +611,15 @@ export default {
         const formRaw = toRaw(this.form)
         const values = this.handleRemoveFields(formRaw)
         this.actionLoading = true
-        var params = {
+        const params = {
           zoneId: this.selectedZone.id,
           name: values.name,
           displayText: values.displaytext,
-          networkOfferingId: this.selectedNetworkOffering.id
+          networkOfferingId: this.selectedNetworkOffering.id,
+          keepmacaddressonpublicnic: values.keepMacAddressOnPublicNic
         }
-        var usefulFields = ['gateway', 'netmask', 'cidrsize', 'startip', 
'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 
'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain']
-        for (var field of usefulFields) {
+        const usefulFields = ['gateway', 'netmask', 'cidrsize', 'startip', 
'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 
'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain']
+        for (const field of usefulFields) {
           if (this.isValidTextValueForKey(values, field)) {
             params[field] = values[field]
           }
diff --git a/ui/src/views/network/CreateVpc.vue 
b/ui/src/views/network/CreateVpc.vue
index 2218662076e..2b66f79b387 100644
--- a/ui/src/views/network/CreateVpc.vue
+++ b/ui/src/views/network/CreateVpc.vue
@@ -202,6 +202,15 @@
             v-model:value="form.sourcenatipaddress"
             :placeholder="apiParams.sourcenatipaddress?.description"/>
         </a-form-item>
+        <a-form-item name="keepMacAddressOnPublicNic" 
ref="keepMacAddressOnPublicNic" v-if="isAdmin()">
+          <template #label>
+            <tooltip-label
+              :title="$t('label.keep.mac.address.on.public.nic')"
+              :tooltip="apiParams.keepmacaddressonpublicnic?.description"
+            />
+          </template>
+          <a-switch v-model:checked="form.keepMacAddressOnPublicNic" />
+        </a-form-item>
         <a-form-item name="start" ref="start">
           <template #label>
             <tooltip-label :title="$t('label.start')" 
:tooltip="apiParams.start.description"/>
@@ -287,7 +296,8 @@ export default {
     initForm () {
       this.formRef = ref()
       this.form = reactive({
-        start: true
+        start: true,
+        keepMacAddressOnPublicNic: true
       })
       this.rules = reactive({
         name: [{ required: true, message: 
this.$t('message.error.required.input') }],
@@ -447,7 +457,7 @@ export default {
       if (this.loading) return
       this.formRef.value.validate().then(() => {
         const values = toRaw(this.form)
-        var params = {}
+        const params = {}
         if (this.owner?.account) {
           params.account = this.owner.account
           params.domainid = this.owner.domainid
@@ -460,7 +470,11 @@ export default {
           if (input === '' || input === null || input === undefined) {
             continue
           }
-          params[key] = input
+          if (key === 'keepMacAddressOnPublicNic') {
+            params.keepmacaddressonpublicnic = input
+          } else {
+            params[key] = input
+          }
         }
         if (this.selectedVpcOffering.networkmode === 'ROUTED') {
           if ((values.cidr === undefined || values.cidr === '') && 
(values.cidrsize === undefined || values.cidrsize === '')) {
diff --git a/ui/src/views/network/UpdateNetwork.vue 
b/ui/src/views/network/UpdateNetwork.vue
index 4a434bb15ae..2299d842a71 100644
--- a/ui/src/views/network/UpdateNetwork.vue
+++ b/ui/src/views/network/UpdateNetwork.vue
@@ -208,6 +208,15 @@
           </template>
           <a-switch v-model:checked="form.displaynetwork" />
         </a-form-item>
+        <a-form-item name="keepMacAddressOnPublicNic" 
ref="keepMacAddressOnPublicNic" v-if="isAdmin() && isUpdatingIsolatedNetwork && 
!resource?.vpcid">
+          <template #label>
+            <tooltip-label
+              :title="$t('label.keep.mac.address.on.public.nic')"
+              :tooltip="apiParams.keepmacaddressonpublicnic?.description"
+            />
+          </template>
+          <a-switch v-model:checked="form.keepMacAddressOnPublicNic" />
+        </a-form-item>
         <a-form-item name="forced" ref="forced" v-if="isAdmin()">
           <template #label>
             <tooltip-label :title="$t('label.forced')" 
:tooltip="apiParams.forced.description"/>
@@ -310,7 +319,8 @@ export default {
       this.form = reactive({
         displaynetwork: this.resource.displaynetwork,
         privatemtu: this.resource.privatemtu,
-        publicmtu: this.resource.publicmtu
+        publicmtu: this.resource.publicmtu,
+        keepMacAddressOnPublicNic: this.resource.keepmacaddressonpublicnic
       })
       this.rules = reactive({
         name: [{ required: true, message: 
this.$t('message.error.required.input') }],
@@ -393,18 +403,20 @@ export default {
         const formRaw = toRaw(this.form)
         const values = this.handleRemoveFields(formRaw)
         this.loading = true
-        var manualFields = ['name', 'networkofferingid']
+        const manualFields = ['name', 'networkofferingid']
         const params = {
           id: this.resource.id,
           name: values.name
         }
-        for (var field in values) {
+        for (const field in values) {
           if (manualFields.includes(field)) continue
-          var fieldValue = values[field]
-          if (fieldValue !== undefined &&
-            fieldValue !== null &&
-            (!(field in this.resourceValues) || this.resourceValues[field] !== 
fieldValue)) {
-            params[field] = fieldValue
+          const fieldValue = values[field]
+          if (fieldValue !== undefined && fieldValue !== null && (!(field in 
this.resourceValues) || this.resourceValues[field] !== fieldValue)) {
+            if (field === 'keepMacAddressOnPublicNic') {
+              params.keepmacaddressonpublicnic = fieldValue
+            } else {
+              params[field] = fieldValue
+            }
           }
         }
         if (values.networkofferingid !== undefined &&


Reply via email to