You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by nv...@apache.org on 2021/10/04 23:01:08 UTC

[cloudstack] branch main updated: vmware, network: add maclearning option (#5471)

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

nvazquez 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 6e216dd  vmware, network: add maclearning option (#5471)
6e216dd is described below

commit 6e216dd0d1282e2916676fbaea92871a7b3cc7de
Author: Abhishek Kumar <ab...@gmail.com>
AuthorDate: Tue Oct 5 04:30:45 2021 +0530

    vmware, network: add maclearning option (#5471)
    
    * vmware, network: add maclearning option
    
    Adds option for specifying MAC Learning property for network offering (useful for VMware Distributed Virtual Portgroup). Added global config - network.mac.learning for the default value.
    MAC Learning is supported for DV portgroups for VMware Distributed vSwitches v6.6.0+ and vSphere 6.7+
    
    Signed-off-by: Abhishek Kumar <ab...@gmail.com>
    
    * fix warning msg
    
    Signed-off-by: Abhishek Kumar <ab...@gmail.com>
---
 .../java/com/cloud/offering/NetworkOffering.java   |   2 +-
 .../service/NetworkOrchestrationService.java       |   3 +
 .../engine/orchestration/NetworkOrchestrator.java  |  18 +-
 .../com/cloud/hypervisor/HypervisorGuruBase.java   |   1 +
 ui/public/locales/en.json                          |   3 +
 ui/src/views/offering/AddNetworkOffering.vue       | 142 +++++++------
 vmware-base/pom.xml                                |   5 +
 .../vmware/mo/DistributedVirtualSwitchMO.java      |   9 +
 .../hypervisor/vmware/mo/HypervisorHostHelper.java | 220 +++++++++++++--------
 .../vmware/mo/HypervisorHostHelperTest.java        |  61 ++++--
 10 files changed, 293 insertions(+), 171 deletions(-)

diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java
index f01c585..5949387 100644
--- a/api/src/main/java/com/cloud/offering/NetworkOffering.java
+++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java
@@ -40,7 +40,7 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity,
     }
 
     public enum Detail {
-        InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering, domainid, zoneid, pvlanType
+        InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RelatedNetworkOffering, domainid, zoneid, pvlanType
     }
 
     public final static String SystemPublicNetwork = "System-Public-Network";
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 15e44d9..1673575 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
@@ -94,6 +94,9 @@ public interface NetworkOrchestrationService {
     ConfigKey<Boolean> ForgedTransmits = new ConfigKey<Boolean>("Advanced", Boolean.class, "network.forged.transmits", "true",
             "Whether to allow or deny forged transmits on nics for applicable network elements such as for vswitch/dvswitch portgroups.", true);
 
+    ConfigKey<Boolean> MacLearning = new ConfigKey<Boolean>("Advanced", Boolean.class, "network.mac.learning", "false",
+            "Whether to allow or deny MAC learning on nics for applicable network elements such as for dvswitch portgroups.", true);
+
     ConfigKey<Boolean> RollingRestartEnabled = new ConfigKey<Boolean>("Advanced", Boolean.class, "network.rolling.restart", "true",
             "Whether to allow or deny rolling restart of network routers.", true);
 
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 8fdf30b..f6e80f3 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
@@ -40,18 +40,10 @@ import java.util.stream.Collectors;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import com.cloud.agent.api.CleanupPersistentNetworkResourceAnswer;
-import com.cloud.agent.api.CleanupPersistentNetworkResourceCommand;
-import com.cloud.agent.api.SetupPersistentNetworkAnswer;
-import com.cloud.agent.api.SetupPersistentNetworkCommand;
-import com.cloud.dc.ClusterVO;
-import com.cloud.dc.dao.ClusterDao;
-import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
 import org.apache.cloudstack.api.ApiConstants;
-import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO;
 import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao;
@@ -73,14 +65,20 @@ import com.cloud.agent.api.AgentControlCommand;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckNetworkAnswer;
 import com.cloud.agent.api.CheckNetworkCommand;
+import com.cloud.agent.api.CleanupPersistentNetworkResourceAnswer;
+import com.cloud.agent.api.CleanupPersistentNetworkResourceCommand;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.SetupPersistentNetworkAnswer;
+import com.cloud.agent.api.SetupPersistentNetworkCommand;
 import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StartupRoutingCommand;
 import com.cloud.agent.api.routing.NetworkElementCommand;
 import com.cloud.agent.api.to.NicTO;
+import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
 import com.cloud.alert.AlertManager;
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.Resource.ResourceType;
+import com.cloud.dc.ClusterVO;
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.dc.DataCenterVO;
@@ -88,6 +86,7 @@ import com.cloud.dc.DataCenterVnetVO;
 import com.cloud.dc.PodVlanMapVO;
 import com.cloud.dc.Vlan;
 import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.DataCenterVnetDao;
 import com.cloud.dc.dao.PodVlanMapDao;
@@ -95,6 +94,7 @@ import com.cloud.dc.dao.VlanDao;
 import com.cloud.deploy.DataCenterDeployment;
 import com.cloud.deploy.DeployDestination;
 import com.cloud.deploy.DeploymentPlan;
+import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
 import com.cloud.domain.Domain;
 import com.cloud.event.EventTypes;
 import com.cloud.event.UsageEventUtils;
@@ -4401,6 +4401,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {NetworkGcWait, NetworkGcInterval, NetworkLockTimeout,
                 GuestDomainSuffix, NetworkThrottlingRate, MinVRVersion,
-                PromiscuousMode, MacAddressChanges, ForgedTransmits, RollingRestartEnabled};
+                PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RollingRestartEnabled};
     }
 }
\ No newline at end of file
diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
index c3a087a..6a0b575 100644
--- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -108,6 +108,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
             details.putIfAbsent(NetworkOffering.Detail.PromiscuousMode, NetworkOrchestrationService.PromiscuousMode.value().toString());
             details.putIfAbsent(NetworkOffering.Detail.MacAddressChanges, NetworkOrchestrationService.MacAddressChanges.value().toString());
             details.putIfAbsent(NetworkOffering.Detail.ForgedTransmits, NetworkOrchestrationService.ForgedTransmits.value().toString());
+            details.putIfAbsent(NetworkOffering.Detail.MacLearning, NetworkOrchestrationService.MacLearning.value().toString());
         }
         NetworkDetailVO pvlantypeDetail = networkDetailsDao.findDetail(network.getId(), ApiConstants.ISOLATED_PVLAN_TYPE);
         if (pvlantypeDetail != null) {
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 58aef78..302d4f0 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -1321,6 +1321,7 @@
 "label.macaddress": "MAC Address",
 "label.macaddress.example": "The MAC Address. Example: 01:23:45:67:89:ab",
 "label.macaddresschanges": "MAC Address Changes",
+"label.maclearning": "MAC Learning",
 "label.macos": "MacOS",
 "label.make": "Make",
 "label.make.project.owner": "Make account project owner",
@@ -3085,6 +3086,8 @@
 "message.network.offering.change.warning": "WARNING: Changing the offering will cause connectivity downtime for the VMs with NICs in the network.",
 "message.network.offering.forged.transmits": "Applicable for guest networks on VMware hypervisor only.\nReject - The switch drops any outbound frame from a virtual machine adapter with a source MAC address that is different from the one in the .vmx configuration file.\nAccept - The switch does not perform filtering, and permits all outbound frames.\nNone - Default to value from global setting.",
 "message.network.offering.mac.address.changes": "Applicable for guest networks on VMware hypervisor only.\nReject - If the guest OS changes the effective MAC address of the virtual machine to a value that is different from the MAC address of the VM network adapter (set in the .vmx configuration file), the switch drops all inbound frames to the adapter.\nIf the guest OS changes the effective MAC address of the virtual machine back to the MAC address of the VM network adapter, the virtual  [...]
+"message.network.offering.mac.learning": "Applicable for guest networks on VMware hypervisor only with VMware Distributed Virtual Switches version 6.6.0 & above and vSphere version 6.7 & above.\nMAC learning enables network connectivity for multiple MAC addresses behind a single vNIC.\nNone - Default to value from global setting.",
+"message.network.offering.mac.learning.warning": "WARNING: In order to use MAC Learning you must ensure your hypervisor hosts are running ESXi 6.7+ and the network uses distributed vSwitch 6.6.0+.",
 "message.network.offering.promiscuous.mode": "Applicable for guest networks on VMware hypervisor only.\nReject - The switch drops any outbound frame from a virtual machine adapter with a source MAC address that is different from the one in the .vmx configuration file.\nAccept - The switch does not perform filtering, and permits all outbound frames.\nNone - Default to value from global setting.",
 "message.network.remote.access.vpn.configuration": "Remote Access VPN configuration has been generated, but it failed to apply. Please check connectivity of the network element, then re-try.",
 "message.network.removenic": "Please confirm that want to remove this NIC, which will also remove the associated network from the VM.",
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue
index c0f2bdb..aa2bbb3 100644
--- a/ui/src/views/offering/AddNetworkOffering.vue
+++ b/ui/src/views/offering/AddNetworkOffering.vue
@@ -108,60 +108,91 @@
             </a-radio-button>
           </a-radio-group>
         </a-form-item>
-        <a-form-item>
-          <tooltip-label slot="label" :title="$t('label.promiscuousmode')" :tooltip="$t('message.network.offering.promiscuous.mode')"/>
-          <a-radio-group
-            v-decorator="['promiscuousmode', {
-              initialValue: ''
-            }]"
-            buttonStyle="solid">
-            <a-radio-button value="">
-              {{ $t('label.none') }}
-            </a-radio-button>
-            <a-radio-button value="true">
-              {{ $t('label.accept') }}
-            </a-radio-button>
-            <a-radio-button value="false">
-              {{ $t('label.reject') }}
-            </a-radio-button>
-          </a-radio-group>
-        </a-form-item>
-        <a-form-item>
-          <tooltip-label slot="label" :title="$t('label.macaddresschanges')" :tooltip="$t('message.network.offering.mac.address.changes')"/>
-          <a-radio-group
-            v-decorator="['macaddresschanges', {
-              initialValue: ''
-            }]"
-            buttonStyle="solid">
-            <a-radio-button value="">
-              {{ $t('label.none') }}
-            </a-radio-button>
-            <a-radio-button value="true">
-              {{ $t('label.accept') }}
-            </a-radio-button>
-            <a-radio-button value="false">
-              {{ $t('label.reject') }}
-            </a-radio-button>
-          </a-radio-group>
-        </a-form-item>
-        <a-form-item>
-          <tooltip-label slot="label" :title="$t('label.forgedtransmits')" :tooltip="$t('message.network.offering.forged.transmits')"/>
-          <a-radio-group
-            v-decorator="['forgedtransmits', {
-              initialValue: ''
-            }]"
-            buttonStyle="solid">
-            <a-radio-button value="">
-              {{ $t('label.none') }}
-            </a-radio-button>
-            <a-radio-button value="true">
-              {{ $t('label.accept') }}
-            </a-radio-button>
-            <a-radio-button value="false">
-              {{ $t('label.reject') }}
-            </a-radio-button>
-          </a-radio-group>
-        </a-form-item>
+        <a-row :gutter="12">
+          <a-col :md="12" :lg="12">
+            <a-form-item>
+              <tooltip-label slot="label" :title="$t('label.promiscuousmode')" :tooltip="$t('message.network.offering.promiscuous.mode')"/>
+              <a-radio-group
+                v-decorator="['promiscuousmode', {
+                  initialValue: ''
+                }]"
+                buttonStyle="solid">
+                <a-radio-button value="">
+                  {{ $t('label.none') }}
+                </a-radio-button>
+                <a-radio-button value="true">
+                  {{ $t('label.accept') }}
+                </a-radio-button>
+                <a-radio-button value="false">
+                  {{ $t('label.reject') }}
+                </a-radio-button>
+              </a-radio-group>
+            </a-form-item>
+            <a-form-item>
+              <tooltip-label slot="label" :title="$t('label.macaddresschanges')" :tooltip="$t('message.network.offering.mac.address.changes')"/>
+              <a-radio-group
+                v-decorator="['macaddresschanges', {
+                  initialValue: ''
+                }]"
+                buttonStyle="solid">
+                <a-radio-button value="">
+                  {{ $t('label.none') }}
+                </a-radio-button>
+                <a-radio-button value="true">
+                  {{ $t('label.accept') }}
+                </a-radio-button>
+                <a-radio-button value="false">
+                  {{ $t('label.reject') }}
+                </a-radio-button>
+              </a-radio-group>
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :lg="12">
+            <a-form-item>
+              <tooltip-label slot="label" :title="$t('label.forgedtransmits')" :tooltip="$t('message.network.offering.forged.transmits')"/>
+              <a-radio-group
+                v-decorator="['forgedtransmits', {
+                  initialValue: ''
+                }]"
+                buttonStyle="solid">
+                <a-radio-button value="">
+                  {{ $t('label.none') }}
+                </a-radio-button>
+                <a-radio-button value="true">
+                  {{ $t('label.accept') }}
+                </a-radio-button>
+                <a-radio-button value="false">
+                  {{ $t('label.reject') }}
+                </a-radio-button>
+              </a-radio-group>
+            </a-form-item>
+            <a-form-item>
+              <tooltip-label slot="label" :title="$t('label.maclearning')" :tooltip="$t('message.network.offering.mac.learning')"/>
+              <span v-if="macLearningValue !== ''">
+                <a-alert type="warning">
+                  <span slot="message" v-html="$t('message.network.offering.mac.learning.warning')" />
+                </a-alert>
+                <br/>
+              </span>
+              <a-radio-group
+                v-decorator="['maclearning', {
+                  initialValue: macLearningValue
+                }]"
+                buttonStyle="solid"
+                @change="e => { macLearningValue = e.target.value }">
+                <a-radio-button value="">
+                  {{ $t('label.none') }}
+                </a-radio-button>
+                <a-radio-button value="true">
+                  {{ $t('label.accept') }}
+                </a-radio-button>
+                <a-radio-button value="false">
+                  {{ $t('label.reject') }}
+                </a-radio-button>
+              </a-radio-group>
+            </a-form-item>
+          </a-col>
+        </a-row>
         <a-form-item v-if="guestType !== 'l2'">
           <tooltip-label slot="label" :title="$t('label.supportedservices')" :tooltip="apiParams.supportedservices.description"/>
           <div class="supported-services-container" scroll-to="last-child">
@@ -421,6 +452,7 @@ export default {
       selectedDomains: [],
       selectedZones: [],
       forVpc: false,
+      macLearningValue: '',
       supportedServices: [],
       supportedServiceLoading: false,
       isVirtualRouterForAtLeastOneService: false,
@@ -685,7 +717,7 @@ export default {
         var self = this
         var selectedServices = null
         var keys = Object.keys(values)
-        const detailsKey = ['promiscuousmode', 'macaddresschanges', 'forgedtransmits']
+        const detailsKey = ['promiscuousmode', 'macaddresschanges', 'forgedtransmits', 'maclearning']
         const ignoredKeys = [...detailsKey, 'state', 'status', 'allocationstate', 'forvpc', 'specifyvlan', 'ispublic', 'domainid', 'zoneid', 'egressdefaultpolicy', 'isolation', 'supportspublicaccess']
         keys.forEach(function (key, keyIndex) {
           if (self.isSupportedServiceObject(values[key])) {
diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml
index 38bb62b..ab818ed 100644
--- a/vmware-base/pom.xml
+++ b/vmware-base/pom.xml
@@ -81,5 +81,10 @@
             <version>${cs.vmware.api.version}</version>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-artifact</artifactId>
+            <version>3.6.3</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java
index 40a0a64..4404a22 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java
@@ -117,6 +117,15 @@ public class DistributedVirtualSwitchMO extends BaseMO {
         return dvsConfigInfo.getConfigVersion();
     }
 
+    public String getDVSProductVersion(ManagedObjectReference dvSwitchMor) throws Exception {
+        assert (dvSwitchMor != null);
+        DVSConfigInfo dvsConfigInfo = (DVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config");
+        if (dvsConfigInfo != null && dvsConfigInfo.getProductInfo() != null) {
+            return dvsConfigInfo.getProductInfo().getVersion();
+        }
+        return null;
+    }
+
     public Map<Integer, HypervisorHostHelper.PvlanType> retrieveVlanPvlan(int vlanid, int secondaryvlanid, ManagedObjectReference dvSwitchMor) throws Exception {
         assert (dvSwitchMor != null);
 
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
index 7ffd8b5..c8a0997 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
@@ -43,6 +43,7 @@ import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationSe
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
+import org.apache.maven.artifact.versioning.ComparableVersion;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -79,6 +80,8 @@ import com.vmware.vim25.CustomFieldStringValue;
 import com.vmware.vim25.DVPortSetting;
 import com.vmware.vim25.DVPortgroupConfigInfo;
 import com.vmware.vim25.DVPortgroupConfigSpec;
+import com.vmware.vim25.DVSMacLearningPolicy;
+import com.vmware.vim25.DVSMacManagementPolicy;
 import com.vmware.vim25.DVSSecurityPolicy;
 import com.vmware.vim25.DVSTrafficShapingPolicy;
 import com.vmware.vim25.DatacenterConfigInfo;
@@ -194,6 +197,17 @@ public class HypervisorHostHelper {
         apiVersionHardwareVersionMap.put("6.9", 14);
         apiVersionHardwareVersionMap.put("7.0", 17);
     }
+    private static final String MINIMUM_VCENTER_API_VERSION_WITH_DVS_NEW_POLICIES_SUPPORT = "6.7";
+    private static final String MINIMUM_DVS_VERSION_WITH_NEW_POLICIES_SUPPORT = "6.6.0";
+
+    private static boolean isVersionEqualOrHigher(String check, String base) {
+        if (check == null || base == null) {
+            return false;
+        }
+        ComparableVersion baseVersion = new ComparableVersion(base);
+        ComparableVersion checkVersion = new ComparableVersion(check);
+        return checkVersion.compareTo(baseVersion) >= 0;
+    }
 
     public static VirtualMachineMO findVmFromObjectContent(VmwareContext context, ObjectContent[] ocs, String name, String instanceNameCustomField) {
 
@@ -594,8 +608,6 @@ public class HypervisorHostHelper {
         }
 
         if (vSwitchType == VirtualSwitchType.VMwareDistributedVirtualSwitch) {
-            DVSTrafficShapingPolicy shapingPolicy;
-            DVSSecurityPolicy secPolicy;
             vcApiVersion = getVcenterApiVersion(context);
             minVcApiVersionSupportingAutoExpand = "5.0";
             autoExpandSupported = isFeatureSupportedInVcenterApiVersion(vcApiVersion, minVcApiVersionSupportingAutoExpand);
@@ -612,9 +624,10 @@ public class HypervisorHostHelper {
                 String msg = "Unable to find distributed vSwitch " + dvSwitchName;
                 s_logger.error(msg);
                 throw new Exception(msg);
-            } else {
-                s_logger.debug("Found distributed vSwitch " + dvSwitchName);
             }
+            dvSwitchMo = new DistributedVirtualSwitchMO(context, morDvSwitch);
+            String dvSwitchVersion = dvSwitchMo.getDVSProductVersion(morDvSwitch);
+            s_logger.debug(String.format("Found distributed vSwitch: %s with product version: %s", dvSwitchName, dvSwitchVersion));
 
             if (broadcastDomainType == BroadcastDomainType.Lswitch) {
                 if (!dataCenterMo.hasDvPortGroup(networkName)) {
@@ -622,10 +635,11 @@ public class HypervisorHostHelper {
                 }
                 bWaitPortGroupReady = false;
             } else {
-                dvSwitchMo = new DistributedVirtualSwitchMO(context, morDvSwitch);
-
-                shapingPolicy = getDVSShapingPolicy(networkRateMbps);
-                secPolicy = createDVSSecurityPolicy(details);
+                boolean dvSwitchSupportNewPolicies = (isFeatureSupportedInVcenterApiVersion(vcApiVersion, MINIMUM_VCENTER_API_VERSION_WITH_DVS_NEW_POLICIES_SUPPORT)
+                        && isVersionEqualOrHigher(dvSwitchVersion, MINIMUM_DVS_VERSION_WITH_NEW_POLICIES_SUPPORT));
+                DVSTrafficShapingPolicy shapingPolicy = getDVSShapingPolicy(networkRateMbps);
+                DVSSecurityPolicy secPolicy = createDVSSecurityPolicy(details);
+                DVSMacManagementPolicy macManagementPolicy = createDVSMacManagementPolicy(details);
 
                 // First, if both vlan id and pvlan id are provided, we need to
                 // reconfigure the DVSwitch to have a tuple <vlan id, pvlan id> of
@@ -637,7 +651,9 @@ public class HypervisorHostHelper {
 
                 VMwareDVSPortgroupPolicy portGroupPolicy = null;
                 // Next, create the port group. For this, we need to create a VLAN spec.
-                createPortGroup(physicalNetwork, networkName, vlanId, vid, spvlanid, dataCenterMo, shapingPolicy, secPolicy, portGroupPolicy, dvSwitchMo, numPorts, autoExpandSupported);
+                createPortGroup(physicalNetwork, networkName, vlanId, vid, spvlanid, dataCenterMo, shapingPolicy,
+                        secPolicy, macManagementPolicy, portGroupPolicy, dvSwitchMo, numPorts, autoExpandSupported,
+                        dvSwitchSupportNewPolicies);
                 bWaitPortGroupReady = true;
             }
         } else if (vSwitchType == VirtualSwitchType.NexusDistributedVirtualSwitch) {
@@ -709,7 +725,7 @@ public class HypervisorHostHelper {
     }
 
     public static boolean isFeatureSupportedInVcenterApiVersion(String vCenterApiVersion, String minVcenterApiVersionForFeature) {
-        return vCenterApiVersion.compareTo(minVcenterApiVersionForFeature) >= 0 ? true : false;
+        return isVersionEqualOrHigher(vCenterApiVersion, minVcenterApiVersionForFeature);
     }
 
     private static void setupPVlanPair(DistributedVirtualSwitchMO dvSwitchMo, ManagedObjectReference morDvSwitch, Integer vid, Integer spvlanid, String pvlanType) throws Exception {
@@ -771,7 +787,9 @@ public class HypervisorHostHelper {
     }
 
     private static void createPortGroup(String physicalNetwork, String networkName, String vlanRange, Integer vid, Integer spvlanid, DatacenterMO dataCenterMo,
-                                        DVSTrafficShapingPolicy shapingPolicy, DVSSecurityPolicy secPolicy, VMwareDVSPortgroupPolicy portGroupPolicy, DistributedVirtualSwitchMO dvSwitchMo, int numPorts, boolean autoExpandSupported)
+                                        DVSTrafficShapingPolicy shapingPolicy, DVSSecurityPolicy secPolicy, DVSMacManagementPolicy macManagementPolicy,
+                                        VMwareDVSPortgroupPolicy portGroupPolicy, DistributedVirtualSwitchMO dvSwitchMo, int numPorts, boolean autoExpandSupported,
+                                        boolean dvSwitchSupportNewPolicies)
                     throws Exception {
         VmwareDistributedVirtualSwitchVlanSpec vlanSpec = null;
         VmwareDistributedVirtualSwitchPvlanSpec pvlanSpec = null;
@@ -782,7 +800,7 @@ public class HypervisorHostHelper {
         // NOTE - VmwareDistributedVirtualSwitchPvlanSpec extends VmwareDistributedVirtualSwitchVlanSpec.
         if (vid == null || spvlanid == null) {
             vlanSpec = createDVPortVlanSpec(vid, vlanRange);
-            dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, vlanSpec);
+            dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, macManagementPolicy, vlanSpec, dvSwitchSupportNewPolicies);
         } else if (spvlanid != null) {
             // Create a pvlan spec. The pvlan spec is different from the pvlan config spec
             // that we created earlier. The pvlan config spec is used to configure the switch
@@ -793,7 +811,7 @@ public class HypervisorHostHelper {
             // and it will find out the associated primary vlan id and do the rest of the
             // port group configuration.
             pvlanSpec = createDVPortPvlanIdSpec(spvlanid);
-            dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, pvlanSpec);
+            dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, macManagementPolicy, pvlanSpec, dvSwitchSupportNewPolicies);
         }
 
         newDvPortGroupSpec = createDvPortGroupSpec(networkName, dvsPortSetting, autoExpandSupported);
@@ -815,7 +833,7 @@ public class HypervisorHostHelper {
         } else {
             s_logger.info("Found Distributed Virtual Port group " + networkName);
             DVPortgroupConfigInfo currentDvPortgroupInfo = dataCenterMo.getDvPortGroupSpec(networkName);
-            if (!isSpecMatch(currentDvPortgroupInfo, newDvPortGroupSpec)) {
+            if (!isSpecMatch(currentDvPortgroupInfo, newDvPortGroupSpec, dvSwitchSupportNewPolicies)) {
                 s_logger.info("Updating Distributed Virtual Port group " + networkName);
                 newDvPortGroupSpec.setDefaultPortConfig(dvsPortSetting);
                 newDvPortGroupSpec.setConfigVersion(currentDvPortgroupInfo.getConfigVersion());
@@ -831,10 +849,79 @@ public class HypervisorHostHelper {
         }
     }
 
-    public static boolean isSpecMatch(DVPortgroupConfigInfo currentDvPortgroupInfo, DVPortgroupConfigSpec newDvPortGroupSpec) {
+    private static boolean eitherObjectNull(Object obj1, Object obj2) {
+        return (obj1 == null && obj2 != null) || (obj1 != null && obj2 == null);
+    }
+
+    private static boolean areBoolPoliciesDifferent(BoolPolicy currentPolicy, BoolPolicy newPolicy) {
+        return eitherObjectNull(currentPolicy, newPolicy) ||
+                (newPolicy != null && newPolicy.isValue() != currentPolicy.isValue());
+    }
+
+    private static boolean areDVSSecurityPoliciesDifferent(DVSSecurityPolicy currentSecurityPolicy, DVSSecurityPolicy newSecurityPolicy) {
+        return eitherObjectNull(currentSecurityPolicy, newSecurityPolicy) ||
+                (newSecurityPolicy != null &&
+                        (areBoolPoliciesDifferent(currentSecurityPolicy.getAllowPromiscuous(), newSecurityPolicy.getAllowPromiscuous()) ||
+                                areBoolPoliciesDifferent(currentSecurityPolicy.getForgedTransmits(), newSecurityPolicy.getForgedTransmits()) ||
+                                areBoolPoliciesDifferent(currentSecurityPolicy.getMacChanges(), newSecurityPolicy.getMacChanges())));
+    }
+
+    private static boolean areDVSMacLearningPoliciesDifferent(DVSMacLearningPolicy currentMacLearningPolicy, DVSMacLearningPolicy newMacLearningPolicy) {
+        return eitherObjectNull(currentMacLearningPolicy, newMacLearningPolicy) ||
+                (newMacLearningPolicy != null && currentMacLearningPolicy.isEnabled() != newMacLearningPolicy.isEnabled());
+    }
+
+    private static boolean areDVSMacManagementPoliciesDifferent(DVSMacManagementPolicy currentMacManagementPolicy, DVSMacManagementPolicy newMacManagementPolicy) {
+        return eitherObjectNull(currentMacManagementPolicy, newMacManagementPolicy) ||
+                (newMacManagementPolicy != null &&
+                        (currentMacManagementPolicy.isAllowPromiscuous() != newMacManagementPolicy.isAllowPromiscuous() ||
+                                currentMacManagementPolicy.isForgedTransmits() != newMacManagementPolicy.isForgedTransmits() ||
+                                currentMacManagementPolicy.isMacChanges() != newMacManagementPolicy.isMacChanges() ||
+                                areDVSMacLearningPoliciesDifferent(currentMacManagementPolicy.getMacLearningPolicy(), newMacManagementPolicy.getMacLearningPolicy())));
+    }
+
+    private static boolean isDVSPortConfigSame(String dvPortGroupName, VMwareDVSPortSetting currentPortSetting, VMwareDVSPortSetting newPortSetting, boolean dvSwitchSupportNewPolicies) {
+        if (areDVSSecurityPoliciesDifferent(currentPortSetting.getSecurityPolicy(), newPortSetting.getSecurityPolicy())) {
+            return false;
+        }
+        if (dvSwitchSupportNewPolicies && areDVSMacManagementPoliciesDifferent(currentPortSetting.getMacManagementPolicy(), newPortSetting.getMacManagementPolicy())) {
+            return false;
+        }
+
+        VmwareDistributedVirtualSwitchVlanSpec oldVlanSpec = currentPortSetting.getVlan();
+        VmwareDistributedVirtualSwitchVlanSpec newVlanSpec = newPortSetting.getVlan();
+
+        int oldVlanId, newVlanId;
+        if (oldVlanSpec instanceof VmwareDistributedVirtualSwitchPvlanSpec && newVlanSpec instanceof VmwareDistributedVirtualSwitchPvlanSpec) {
+            VmwareDistributedVirtualSwitchPvlanSpec oldpVlanSpec = (VmwareDistributedVirtualSwitchPvlanSpec) oldVlanSpec;
+            VmwareDistributedVirtualSwitchPvlanSpec newpVlanSpec = (VmwareDistributedVirtualSwitchPvlanSpec) newVlanSpec;
+            oldVlanId = oldpVlanSpec.getPvlanId();
+            newVlanId = newpVlanSpec.getPvlanId();
+        } else if (oldVlanSpec instanceof VmwareDistributedVirtualSwitchTrunkVlanSpec && newVlanSpec instanceof VmwareDistributedVirtualSwitchTrunkVlanSpec) {
+            VmwareDistributedVirtualSwitchTrunkVlanSpec oldpVlanSpec = (VmwareDistributedVirtualSwitchTrunkVlanSpec) oldVlanSpec;
+            VmwareDistributedVirtualSwitchTrunkVlanSpec newpVlanSpec = (VmwareDistributedVirtualSwitchTrunkVlanSpec) newVlanSpec;
+            oldVlanId = oldpVlanSpec.getVlanId().get(0).getStart();
+            newVlanId = newpVlanSpec.getVlanId().get(0).getStart();
+        } else if (oldVlanSpec instanceof VmwareDistributedVirtualSwitchVlanIdSpec && newVlanSpec instanceof VmwareDistributedVirtualSwitchVlanIdSpec) {
+            VmwareDistributedVirtualSwitchVlanIdSpec oldVlanIdSpec = (VmwareDistributedVirtualSwitchVlanIdSpec) oldVlanSpec;
+            VmwareDistributedVirtualSwitchVlanIdSpec newVlanIdSpec = (VmwareDistributedVirtualSwitchVlanIdSpec) newVlanSpec;
+            oldVlanId = oldVlanIdSpec.getVlanId();
+            newVlanId = newVlanIdSpec.getVlanId();
+        } else {
+            s_logger.debug(String.format("Old and new vlan spec type mismatch found for dvPortGroup: %s. Old spec type is: %s, and new spec type is: %s", dvPortGroupName, oldVlanSpec.getClass(), newVlanSpec.getClass()));
+            return false;
+        }
+
+        if (oldVlanId != newVlanId) {
+            s_logger.info(String.format("Detected that new VLAN [%d] is different from current VLAN [%d] of dvPortGroup: %s", newVlanId, oldVlanId, dvPortGroupName));
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean isSpecMatch(DVPortgroupConfigInfo currentDvPortgroupInfo, DVPortgroupConfigSpec newDvPortGroupSpec, boolean dvSwitchSupportNewPolicies) {
         String dvPortGroupName = newDvPortGroupSpec.getName();
         s_logger.debug("Checking if configuration of dvPortGroup [" + dvPortGroupName + "] has changed.");
-        boolean specMatches = true;
         DVSTrafficShapingPolicy currentTrafficShapingPolicy;
         currentTrafficShapingPolicy = currentDvPortgroupInfo.getDefaultPortConfig().getInShapingPolicy();
 
@@ -886,26 +973,26 @@ public class HypervisorHostHelper {
 
         if (!oldIsEnabled.equals(newIsEnabled)) {
             s_logger.info("Detected change in state of shaping policy (enabled/disabled) [" + newIsEnabled + "]");
-            specMatches = false;
+            return false;
         }
 
         if (oldIsEnabled || newIsEnabled) {
             if (oldAverageBandwidth != null && !oldAverageBandwidth.equals(newAverageBandwidth)) {
                 s_logger.info("Average bandwidth setting in new shaping policy doesn't match the existing setting.");
-                specMatches = false;
+                return false;
             } else if (oldBurstSize != null && !oldBurstSize.equals(newBurstSize)) {
                 s_logger.info("Burst size setting in new shaping policy doesn't match the existing setting.");
-                specMatches = false;
+                return false;
             } else if (oldPeakBandwidth != null && !oldPeakBandwidth.equals(newPeakBandwidth)) {
                 s_logger.info("Peak bandwidth setting in new shaping policy doesn't match the existing setting.");
-                specMatches = false;
+                return false;
             }
         }
 
         boolean oldAutoExpandSetting = currentDvPortgroupInfo.isAutoExpand();
         boolean autoExpandEnabled = newDvPortGroupSpec.isAutoExpand();
         if (oldAutoExpandSetting != autoExpandEnabled) {
-            specMatches = false;
+            return false;
         }
         if (!autoExpandEnabled) {
             // Allow update of number of dvports per dvPortGroup is auto expand is not enabled.
@@ -914,72 +1001,17 @@ public class HypervisorHostHelper {
             if (oldNumPorts < newNumPorts) {
                 s_logger.info("Need to update the number of dvports for dvPortGroup :[" + dvPortGroupName +
                             "] from existing number of dvports " + oldNumPorts + " to " + newNumPorts);
-                specMatches = false;
+                return false;
             } else if (oldNumPorts > newNumPorts) {
                 s_logger.warn("Detected that new number of dvports [" + newNumPorts + "] in dvPortGroup [" + dvPortGroupName +
                         "] is less than existing number of dvports [" + oldNumPorts + "]. Attempt to update this dvPortGroup may fail!");
-                specMatches = false;
+                return false;
             }
         }
 
         VMwareDVSPortSetting currentPortSetting = ((VMwareDVSPortSetting)currentDvPortgroupInfo.getDefaultPortConfig());
         VMwareDVSPortSetting newPortSetting = ((VMwareDVSPortSetting)newDvPortGroupSpec.getDefaultPortConfig());
-        if ((currentPortSetting.getSecurityPolicy() == null && newPortSetting.getSecurityPolicy() != null) ||
-                (currentPortSetting.getSecurityPolicy() != null && newPortSetting.getSecurityPolicy() == null)) {
-            specMatches = false;
-        }
-        if (currentPortSetting.getSecurityPolicy() != null && newPortSetting.getSecurityPolicy() != null) {
-            if (currentPortSetting.getSecurityPolicy().getAllowPromiscuous() != null &&
-                    newPortSetting.getSecurityPolicy().getAllowPromiscuous() != null &&
-                    newPortSetting.getSecurityPolicy().getAllowPromiscuous().isValue() != null &&
-                    !newPortSetting.getSecurityPolicy().getAllowPromiscuous().isValue().equals(currentPortSetting.getSecurityPolicy().getAllowPromiscuous().isValue())) {
-                specMatches = false;
-            }
-            if (currentPortSetting.getSecurityPolicy().getForgedTransmits() != null &&
-                    newPortSetting.getSecurityPolicy().getForgedTransmits() != null &&
-                    newPortSetting.getSecurityPolicy().getForgedTransmits().isValue() != null &&
-                    !newPortSetting.getSecurityPolicy().getForgedTransmits().isValue().equals(currentPortSetting.getSecurityPolicy().getForgedTransmits().isValue())) {
-                specMatches = false;
-            }
-            if (currentPortSetting.getSecurityPolicy().getMacChanges() != null &&
-                    newPortSetting.getSecurityPolicy().getMacChanges() != null &&
-                    newPortSetting.getSecurityPolicy().getMacChanges().isValue() != null &&
-                    !newPortSetting.getSecurityPolicy().getMacChanges().isValue().equals(currentPortSetting.getSecurityPolicy().getMacChanges().isValue())) {
-                specMatches = false;
-            }
-        }
-
-        VmwareDistributedVirtualSwitchVlanSpec oldVlanSpec = currentPortSetting.getVlan();
-        VmwareDistributedVirtualSwitchVlanSpec newVlanSpec = newPortSetting.getVlan();
-
-        int oldVlanId, newVlanId;
-        if (oldVlanSpec instanceof VmwareDistributedVirtualSwitchPvlanSpec && newVlanSpec instanceof VmwareDistributedVirtualSwitchPvlanSpec) {
-            VmwareDistributedVirtualSwitchPvlanSpec oldpVlanSpec = (VmwareDistributedVirtualSwitchPvlanSpec) oldVlanSpec;
-            VmwareDistributedVirtualSwitchPvlanSpec newpVlanSpec = (VmwareDistributedVirtualSwitchPvlanSpec) newVlanSpec;
-            oldVlanId = oldpVlanSpec.getPvlanId();
-            newVlanId = newpVlanSpec.getPvlanId();
-        } else if (oldVlanSpec instanceof VmwareDistributedVirtualSwitchTrunkVlanSpec && newVlanSpec instanceof VmwareDistributedVirtualSwitchTrunkVlanSpec) {
-            VmwareDistributedVirtualSwitchTrunkVlanSpec oldpVlanSpec = (VmwareDistributedVirtualSwitchTrunkVlanSpec) oldVlanSpec;
-            VmwareDistributedVirtualSwitchTrunkVlanSpec newpVlanSpec = (VmwareDistributedVirtualSwitchTrunkVlanSpec) newVlanSpec;
-            oldVlanId = oldpVlanSpec.getVlanId().get(0).getStart();
-            newVlanId = newpVlanSpec.getVlanId().get(0).getStart();
-        } else if (oldVlanSpec instanceof VmwareDistributedVirtualSwitchVlanIdSpec && newVlanSpec instanceof VmwareDistributedVirtualSwitchVlanIdSpec) {
-            VmwareDistributedVirtualSwitchVlanIdSpec oldVlanIdSpec = (VmwareDistributedVirtualSwitchVlanIdSpec) oldVlanSpec;
-            VmwareDistributedVirtualSwitchVlanIdSpec newVlanIdSpec = (VmwareDistributedVirtualSwitchVlanIdSpec) newVlanSpec;
-            oldVlanId = oldVlanIdSpec.getVlanId();
-            newVlanId = newVlanIdSpec.getVlanId();
-        } else {
-            s_logger.debug("Old and new vlan spec type mismatch found for [" + dvPortGroupName + "] has changed. Old spec type is: " + oldVlanSpec.getClass() + ", and new spec type is:" + newVlanSpec.getClass());
-            return false;
-        }
-
-        if (oldVlanId != newVlanId) {
-            s_logger.info("Detected that new VLAN [" + newVlanId + "] of dvPortGroup [" + dvPortGroupName +
-                        "] is different from current VLAN [" + oldVlanId + "]");
-            specMatches = false;
-        }
-
-        return specMatches;
+        return isDVSPortConfigSame(dvPortGroupName, currentPortSetting, newPortSetting, dvSwitchSupportNewPolicies);
     }
 
     public static ManagedObjectReference waitForDvPortGroupReady(DatacenterMO dataCenterMo, String dvPortGroupName, long timeOutMs) throws Exception {
@@ -1046,10 +1078,13 @@ public class HypervisorHostHelper {
     }
 
     public static VMwareDVSPortSetting createVmwareDVPortSettingSpec(DVSTrafficShapingPolicy shapingPolicy, DVSSecurityPolicy secPolicy,
-            VmwareDistributedVirtualSwitchVlanSpec vlanSpec) {
+            DVSMacManagementPolicy macManagementPolicy, VmwareDistributedVirtualSwitchVlanSpec vlanSpec, boolean dvSwitchSupportNewPolicies) {
         VMwareDVSPortSetting dvsPortSetting = new VMwareDVSPortSetting();
         dvsPortSetting.setVlan(vlanSpec);
         dvsPortSetting.setSecurityPolicy(secPolicy);
+        if (dvSwitchSupportNewPolicies) {
+            dvsPortSetting.setMacManagementPolicy(macManagementPolicy);
+        }
         dvsPortSetting.setInShapingPolicy(shapingPolicy);
         dvsPortSetting.setOutShapingPolicy(shapingPolicy);
         return dvsPortSetting;
@@ -1164,6 +1199,7 @@ public class HypervisorHostHelper {
         details.put(NetworkOffering.Detail.PromiscuousMode, NetworkOrchestrationService.PromiscuousMode.value().toString());
         details.put(NetworkOffering.Detail.MacAddressChanges, NetworkOrchestrationService.MacAddressChanges.value().toString());
         details.put(NetworkOffering.Detail.ForgedTransmits, NetworkOrchestrationService.ForgedTransmits.value().toString());
+        details.put(NetworkOffering.Detail.MacLearning, NetworkOrchestrationService.MacLearning.value().toString());
         return details;
     }
 
@@ -1173,40 +1209,50 @@ public class HypervisorHostHelper {
         allow.setValue(true);
         BoolPolicy deny = new BoolPolicy();
         deny.setValue(false);
-
         secPolicy.setAllowPromiscuous(deny);
         secPolicy.setForgedTransmits(allow);
         secPolicy.setMacChanges(allow);
-
         if (nicDetails == null) {
             nicDetails = getDefaultSecurityDetails();
         }
-
         if (nicDetails.containsKey(NetworkOffering.Detail.PromiscuousMode)) {
-            if (Boolean.valueOf(nicDetails.get(NetworkOffering.Detail.PromiscuousMode))) {
+            if (Boolean.parseBoolean(nicDetails.get(NetworkOffering.Detail.PromiscuousMode))) {
                 secPolicy.setAllowPromiscuous(allow);
             } else {
                 secPolicy.setAllowPromiscuous(deny);
             }
         }
         if (nicDetails.containsKey(NetworkOffering.Detail.ForgedTransmits)) {
-            if (Boolean.valueOf(nicDetails.get(NetworkOffering.Detail.ForgedTransmits))) {
+            if (Boolean.parseBoolean(nicDetails.get(NetworkOffering.Detail.ForgedTransmits))) {
                 secPolicy.setForgedTransmits(allow);
             } else {
                 secPolicy.setForgedTransmits(deny);
             }
         }
         if (nicDetails.containsKey(NetworkOffering.Detail.MacAddressChanges)) {
-            if (Boolean.valueOf(nicDetails.get(NetworkOffering.Detail.MacAddressChanges))) {
+            if (Boolean.parseBoolean(nicDetails.get(NetworkOffering.Detail.MacAddressChanges))) {
                 secPolicy.setMacChanges(allow);
             } else {
                 secPolicy.setMacChanges(deny);
             }
         }
-
         return secPolicy;
     }
 
+    public static DVSMacManagementPolicy createDVSMacManagementPolicy(Map<NetworkOffering.Detail, String> nicDetails) {
+        if (nicDetails == null) {
+            nicDetails = getDefaultSecurityDetails();
+        }
+        DVSMacManagementPolicy macManagementPolicy = new DVSMacManagementPolicy();
+        macManagementPolicy.setAllowPromiscuous(Boolean.valueOf(nicDetails.getOrDefault(NetworkOffering.Detail.PromiscuousMode, "false")));
+        macManagementPolicy.setForgedTransmits(Boolean.valueOf(nicDetails.getOrDefault(NetworkOffering.Detail.ForgedTransmits, "false")));
+        macManagementPolicy.setMacChanges(Boolean.valueOf(nicDetails.getOrDefault(NetworkOffering.Detail.MacAddressChanges, "false")));
+        DVSMacLearningPolicy macLearningPolicy = new DVSMacLearningPolicy();
+        macLearningPolicy.setEnabled(Boolean.parseBoolean(nicDetails.getOrDefault(NetworkOffering.Detail.MacLearning, "false")));
+        macManagementPolicy.setMacLearningPolicy(macLearningPolicy);
+        return macManagementPolicy;
+    }
+
     public static HostNetworkSecurityPolicy createVSSecurityPolicy(Map<NetworkOffering.Detail, String> nicDetails) {
         HostNetworkSecurityPolicy secPolicy = new HostNetworkSecurityPolicy();
         secPolicy.setAllowPromiscuous(Boolean.FALSE);
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
index 9fd31ec..ff4169d 100644
--- a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
@@ -20,11 +20,11 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.never;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -42,16 +42,17 @@ import com.cloud.offering.NetworkOffering;
 import com.vmware.vim25.AboutInfo;
 import com.vmware.vim25.BoolPolicy;
 import com.vmware.vim25.ClusterConfigInfoEx;
-import com.vmware.vim25.DatacenterConfigInfo;
-import com.vmware.vim25.VirtualMachineConfigSpec;
 import com.vmware.vim25.DVPortgroupConfigInfo;
 import com.vmware.vim25.DVPortgroupConfigSpec;
+import com.vmware.vim25.DVSMacManagementPolicy;
 import com.vmware.vim25.DVSSecurityPolicy;
 import com.vmware.vim25.DVSTrafficShapingPolicy;
+import com.vmware.vim25.DatacenterConfigInfo;
 import com.vmware.vim25.HostNetworkSecurityPolicy;
 import com.vmware.vim25.LongPolicy;
 import com.vmware.vim25.ServiceContent;
 import com.vmware.vim25.VMwareDVSPortSetting;
+import com.vmware.vim25.VirtualMachineConfigSpec;
 import com.vmware.vim25.VmwareDistributedVirtualSwitchTrunkVlanSpec;
 import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
 import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanSpec;
@@ -213,7 +214,7 @@ public class HypervisorHostHelperTest {
         when(dvPortgroupConfigSpec.isAutoExpand()).thenReturn(newAutoExpand);
         when(dvPortgroupConfigSpec.getDefaultPortConfig()).thenReturn(newVmwareDvsPortSetting);
 
-        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec);
+        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec, false);
         assertTrue(specCompareResult);
     }
 
@@ -273,7 +274,7 @@ public class HypervisorHostHelperTest {
         when(dvPortgroupConfigSpec.isAutoExpand()).thenReturn(newAutoExpand);
         when(dvPortgroupConfigSpec.getDefaultPortConfig()).thenReturn(newVmwareDvsPortSetting);
 
-        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec);
+        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec, false);
         assertFalse(specCompareResult);
     }
 
@@ -332,7 +333,7 @@ public class HypervisorHostHelperTest {
         when(dvPortgroupConfigSpec.isAutoExpand()).thenReturn(newAutoExpand);
         when(dvPortgroupConfigSpec.getDefaultPortConfig()).thenReturn(newVmwareDvsPortSetting);
 
-        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec);
+        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec, false);
         assertTrue(specCompareResult);
     }
 
@@ -391,7 +392,7 @@ public class HypervisorHostHelperTest {
         when(dvPortgroupConfigSpec.isAutoExpand()).thenReturn(newAutoExpand);
         when(dvPortgroupConfigSpec.getDefaultPortConfig()).thenReturn(newVmwareDvsPortSetting);
 
-        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec);
+        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec, false);
         assertFalse(specCompareResult);
     }
 
@@ -450,7 +451,7 @@ public class HypervisorHostHelperTest {
         when(dvPortgroupConfigSpec.isAutoExpand()).thenReturn(newAutoExpand);
         when(dvPortgroupConfigSpec.getDefaultPortConfig()).thenReturn(newVmwareDvsPortSetting);
 
-        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec);
+        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec, false);
         assertFalse(specCompareResult);
     }
 
@@ -500,7 +501,7 @@ public class HypervisorHostHelperTest {
         when(dvPortgroupConfigSpec.isAutoExpand()).thenReturn(newAutoExpand);
         when(dvPortgroupConfigSpec.getDefaultPortConfig()).thenReturn(newVmwareDvsPortSetting);
 
-        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec);
+        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec, false);
         assertFalse(specCompareResult);
     }
 
@@ -540,7 +541,7 @@ public class HypervisorHostHelperTest {
         when(dvPortgroupConfigSpec.isAutoExpand()).thenReturn(newAutoExpand);
         when(dvPortgroupConfigSpec.getDefaultPortConfig()).thenReturn(newVmwareDvsPortSetting);
 
-        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec);
+        boolean specCompareResult = HypervisorHostHelper.isSpecMatch(currentDvPortgroupInfo, dvPortgroupConfigSpec, false);
         assertTrue(specCompareResult);
     }
 
@@ -801,11 +802,12 @@ public class HypervisorHostHelperTest {
         assertEquals(expected, HypervisorHostHelper.removeOVFNetwork(ovfString));
     }
 
-    private Map<NetworkOffering.Detail, String> getSecurityDetails() {
+    private Map<NetworkOffering.Detail, String> getNicDetails() {
         final Map<NetworkOffering.Detail, String> details = new HashMap<>();
         details.put(NetworkOffering.Detail.PromiscuousMode, "false");
         details.put(NetworkOffering.Detail.ForgedTransmits, "false");
         details.put(NetworkOffering.Detail.MacAddressChanges, "false");
+        details.put(NetworkOffering.Detail.MacLearning, "false");
         return details;
     }
 
@@ -819,7 +821,7 @@ public class HypervisorHostHelperTest {
 
     @Test
     public void testVSSecurityPolicyDefaultWithDetail() {
-        HostNetworkSecurityPolicy secPolicy = HypervisorHostHelper.createVSSecurityPolicy(getSecurityDetails());
+        HostNetworkSecurityPolicy secPolicy = HypervisorHostHelper.createVSSecurityPolicy(getNicDetails());
         assertFalse(secPolicy.isAllowPromiscuous());
         assertFalse(secPolicy.isForgedTransmits());
         assertFalse(secPolicy.isMacChanges());
@@ -827,7 +829,7 @@ public class HypervisorHostHelperTest {
 
     @Test
     public void testVSSecurityPolicyWithDetail() {
-        Map<NetworkOffering.Detail, String> details = getSecurityDetails();
+        Map<NetworkOffering.Detail, String> details = getNicDetails();
         details.put(NetworkOffering.Detail.MacAddressChanges, "true");
         HostNetworkSecurityPolicy secPolicy = HypervisorHostHelper.createVSSecurityPolicy(details);
         assertFalse(secPolicy.isAllowPromiscuous());
@@ -836,7 +838,7 @@ public class HypervisorHostHelperTest {
     }
 
     @Test
-    public void testDVSSecurityPolicyDefault() {
+    public void testDVSSecurityPolicyLegacyDefault() {
         DVSSecurityPolicy secPolicy = HypervisorHostHelper.createDVSSecurityPolicy(null);
         assertFalse(secPolicy.getAllowPromiscuous().isValue());
         assertTrue(secPolicy.getForgedTransmits().isValue());
@@ -844,8 +846,8 @@ public class HypervisorHostHelperTest {
     }
 
     @Test
-    public void testDVSSecurityPolicyDefaultWithDetail() {
-        Map<NetworkOffering.Detail, String> details = getSecurityDetails();
+    public void testDVSSecurityPolicyLegacyDefaultWithDetail() {
+        Map<NetworkOffering.Detail, String> details = getNicDetails();
         details.remove(NetworkOffering.Detail.ForgedTransmits);
         details.remove(NetworkOffering.Detail.PromiscuousMode);
         DVSSecurityPolicy secPolicy = HypervisorHostHelper.createDVSSecurityPolicy(details);
@@ -855,8 +857,8 @@ public class HypervisorHostHelperTest {
     }
 
     @Test
-    public void testDVSSecurityPolicyWithDetail() {
-        Map<NetworkOffering.Detail, String> details = getSecurityDetails();
+    public void testDVSSecurityPolicyLegacyWithDetail() {
+        Map<NetworkOffering.Detail, String> details = getNicDetails();
         details.put(NetworkOffering.Detail.ForgedTransmits, "true");
         DVSSecurityPolicy secPolicy = HypervisorHostHelper.createDVSSecurityPolicy(details);
         assertFalse(secPolicy.getAllowPromiscuous().isValue());
@@ -865,6 +867,27 @@ public class HypervisorHostHelperTest {
     }
 
     @Test
+    public void testDVSMacManagementPolicyDefault() {
+        DVSMacManagementPolicy macManagementPolicy = HypervisorHostHelper.createDVSMacManagementPolicy(null);
+        assertFalse(macManagementPolicy.isAllowPromiscuous());
+        assertTrue(macManagementPolicy.isForgedTransmits());
+        assertTrue(macManagementPolicy.isMacChanges());
+        assertFalse(macManagementPolicy.getMacLearningPolicy().isEnabled());
+    }
+
+    @Test
+    public void testDVSMacManagementPolicyWithDetail() {
+        Map<NetworkOffering.Detail, String> details = getNicDetails();
+        details.put(NetworkOffering.Detail.ForgedTransmits, "true");
+        details.put(NetworkOffering.Detail.MacLearning, "true");
+        DVSMacManagementPolicy macManagementPolicy = HypervisorHostHelper.createDVSMacManagementPolicy(details);
+        assertFalse(macManagementPolicy.isAllowPromiscuous());
+        assertTrue(macManagementPolicy.isForgedTransmits());
+        assertFalse(macManagementPolicy.isMacChanges());
+        assertTrue(macManagementPolicy.getMacLearningPolicy().isEnabled());
+    }
+
+    @Test
     public void testCreateDVPortVlanSpecNullVlanId() {
         VmwareDistributedVirtualSwitchVlanSpec spec = HypervisorHostHelper.createDVPortVlanSpec(null, null);
         assertTrue(spec instanceof VmwareDistributedVirtualSwitchVlanIdSpec);