You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by gi...@apache.org on 2014/01/29 09:53:47 UTC

[12/50] git commit: updated refs/heads/marvin to df58f51

CLOUDSTACK-5561 Support of multiple public vlans on VR running in HyperV


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/807dc091
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/807dc091
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/807dc091

Branch: refs/heads/marvin
Commit: 807dc091382fbf6fbd4b8fc53e7cdb414078ea2e
Parents: ce0dc3b
Author: Rajesh Battala <ra...@citrix.com>
Authored: Tue Jan 28 06:40:47 2014 +0530
Committer: Rajesh Battala <ra...@citrix.com>
Committed: Tue Jan 28 07:03:08 2014 +0530

----------------------------------------------------------------------
 .../com/cloud/agent/api/GetVmConfigAnswer.java  |  68 +++++
 .../com/cloud/agent/api/GetVmConfigCommand.java |  46 ++++
 .../agent/api/ModifyVmNicConfigAnswer.java      |  36 +++
 .../agent/api/ModifyVmNicConfigCommand.java     |  42 +++
 .../DotNet/ServerResource/AgentShell/App.config |   2 +-
 .../HypervResource/CloudStackTypes.cs           |  18 ++
 .../HypervResource/HypervResourceController.cs  | 100 +++++++
 .../HypervResource/IWmiCallsV2.cs               |   1 +
 .../ServerResource/HypervResource/WmiCallsV2.cs |  62 +++++
 .../hypervisor/hyperv/guru/HypervGuru.java      | 113 ++++++++
 .../hyperv/manager/HypervManager.java           |   1 +
 .../hyperv/manager/HypervManagerImpl.java       |  20 +-
 .../resource/HypervDirectConnectResource.java   | 258 ++++++++++++++-----
 .../VirtualNetworkApplianceManagerImpl.java     |   2 +-
 .../debian/config/opt/cloud/bin/ipassoc.sh      |   3 +-
 15 files changed, 697 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/core/src/com/cloud/agent/api/GetVmConfigAnswer.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/GetVmConfigAnswer.java b/core/src/com/cloud/agent/api/GetVmConfigAnswer.java
new file mode 100644
index 0000000..46e003e
--- /dev/null
+++ b/core/src/com/cloud/agent/api/GetVmConfigAnswer.java
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.agent.api;
+
+import java.util.List;
+
+public class GetVmConfigAnswer extends Answer {
+
+    String vmName;
+    List<NicDetails> nics;
+
+    protected GetVmConfigAnswer() {
+    }
+
+    public GetVmConfigAnswer(String vmName, List<NicDetails> nics) {
+        this.vmName = vmName;
+        this.nics = nics;
+    }
+
+    public String getVmName() {
+        return vmName;
+    }
+
+    public List<NicDetails> getNics() {
+        return nics;
+    }
+
+    public class NicDetails {
+        String macAddress;
+        int vlanid;
+
+        public NicDetails() {
+        }
+
+        public NicDetails(String macAddress, int vlanid) {
+            this.macAddress = macAddress;
+            this.vlanid = vlanid;
+        }
+
+        public String getMacAddress() {
+            return macAddress;
+        }
+
+        public int getVlanid() {
+            return vlanid;
+        }
+
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/core/src/com/cloud/agent/api/GetVmConfigCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/GetVmConfigCommand.java b/core/src/com/cloud/agent/api/GetVmConfigCommand.java
new file mode 100644
index 0000000..9133bd6
--- /dev/null
+++ b/core/src/com/cloud/agent/api/GetVmConfigCommand.java
@@ -0,0 +1,46 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.agent.api;
+
+
+import java.util.List;
+
+import com.cloud.agent.api.to.NicTO;
+
+public class GetVmConfigCommand extends Command {
+    String vmName;
+    List<NicTO> nics;
+    protected GetVmConfigCommand() {
+    }
+
+    public GetVmConfigCommand(String vmName) {
+        this.vmName = vmName;
+    }
+
+    public String getVmName() {
+        return vmName;
+    }
+
+    public void setNics(List<NicTO> nics){
+        this.nics = nics;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/core/src/com/cloud/agent/api/ModifyVmNicConfigAnswer.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/ModifyVmNicConfigAnswer.java b/core/src/com/cloud/agent/api/ModifyVmNicConfigAnswer.java
new file mode 100644
index 0000000..1140485
--- /dev/null
+++ b/core/src/com/cloud/agent/api/ModifyVmNicConfigAnswer.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.agent.api;
+
+public class ModifyVmNicConfigAnswer extends Answer {
+    String vmName;
+    protected ModifyVmNicConfigAnswer() {
+    }
+
+    public ModifyVmNicConfigAnswer(String vmName) {
+        this.vmName = vmName;
+    }
+
+    public String getVmName() {
+        return vmName;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java b/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
new file mode 100644
index 0000000..0230bec
--- /dev/null
+++ b/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.agent.api;
+
+
+public class ModifyVmNicConfigCommand extends Command {
+    String vmName;
+    int vlan;
+    String macAddress;
+    protected ModifyVmNicConfigCommand() {
+    }
+
+    public ModifyVmNicConfigCommand(String vmName, int vlan, String macAddress) {
+        this.vmName = vmName;
+        this.vlan = vlan;
+        this.macAddress = macAddress;
+    }
+
+    public String getVmName() {
+        return vmName;
+    }
+
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config
index b783dfe..3ec08bd 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config
@@ -96,7 +96,7 @@
         <value>2048</value>
       </setting>
       <setting name="private_ip_address" serializeAs="String">
-        <value>10.102.192.150</value>
+        <value>0.0.0.0</value>
       </setting>
     </CloudStack.Plugin.AgentShell.AgentSettings>
    </applicationSettings>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
index d54295c..c336a38 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
@@ -690,6 +690,20 @@ namespace HypervResource
         public String entityType;
     }
 
+    public class NicDetails
+    {
+        [JsonProperty("macAddress")]
+        public string macaddress;
+        [JsonProperty("vlanid")]
+        public int vlanid;
+        public NicDetails() { }
+        public NicDetails(String macaddress, int vlanid)
+        {
+            this.macaddress = macaddress;
+            this.vlanid = vlanid;
+        }
+    }
+
     /// <summary>
     /// Fully qualified named for a number of types used in CloudStack.  Used to specify the intended type for JSON serialised objects. 
     /// </summary>
@@ -738,6 +752,10 @@ namespace HypervResource
         public const string GetVmDiskStatsCommand = "com.cloud.agent.api.GetVmDiskStatsCommand";
         public const string GetVmStatsAnswer = "com.cloud.agent.api.GetVmStatsAnswer";
         public const string GetVmStatsCommand = "com.cloud.agent.api.GetVmStatsCommand";
+        public const string GetVmConfigCommand = "com.cloud.agent.api.GetVmConfigCommand";
+        public const string GetVmConfigAnswer = "com.cloud.agent.api.GetVmConfigAnswer";
+        public const string ModifyVmNicConfigCommand = "com.cloud.agent.api.ModifyVmNicConfigCommand";
+        public const string ModifyVmNicConfigAnswer = "com.cloud.agent.api.ModifyVmNicConfigAnswer";
         public const string GetVncPortAnswer = "com.cloud.agent.api.GetVncPortAnswer";
         public const string GetVncPortCommand = "com.cloud.agent.api.GetVncPortCommand";
         public const string HostStatsEntry = "com.cloud.agent.api.HostStatsEntry";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
index f7787c3..ebb3bce 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
@@ -982,6 +982,24 @@ namespace HypervResource
             return true;
         }
 
+        // POST api/HypervResource/PlugNicCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.PlugNicCommand)]
+        public JContainer PlugNicCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.PlugNicCommand + cmd.ToString());
+                object ansContent = new
+                {
+                    result = true,
+                    details = "instead of plug, change he network settings",
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PlugNicAnswer);
+            }
+        }
+
 
         // POST api/HypervResource/CleanupNetworkRulesCmd
         [HttpPost]
@@ -1264,6 +1282,88 @@ namespace HypervResource
             }
         }
 
+        // POST api/HypervResource/ModifyVmVnicVlanCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.ModifyVmNicConfigCommand)]
+        public JContainer ModifyVmNicConfigCommand([FromBody]dynamic cmd)
+        {
+
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.ModifyVmNicConfigCommand + cmd.ToString());
+                bool result = false;
+                String vmName = cmd.vmName;
+                uint vlan = (uint)cmd.vlan;
+                string macAddress = cmd.macAddress;
+                wmiCallsV2.ModifyVmVLan(vmName, vlan, macAddress);
+
+                result = true;
+
+                object ansContent = new
+                {
+                    vmName = vmName,
+                    result = result,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyVmNicConfigAnswer);
+            }
+
+        }
+
+        // POST api/HypervResource/GetVmConfigCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.GetVmConfigCommand)]
+        public JContainer GetVmConfigCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.GetVmConfigCommand + cmd.ToString());
+                bool result = false;
+                String vmName = cmd.vmName;
+                ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName);
+                List<NicDetails> nicDetails = new List<NicDetails>();
+                var nicSettingsViaVm = wmiCallsV2.GetEthernetPortSettings(vm);
+                NicDetails nic = null;
+                String[] macAddress = new String[nicSettingsViaVm.Length];
+                int index = 0;
+                foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
+                {
+                    macAddress[index++] = item.Address;
+                }
+
+                index = 0;
+                var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm);
+                int vlanid = 1;
+                foreach (EthernetPortAllocationSettingData item in ethernetConnections)
+                {
+                    EthernetSwitchPortVlanSettingData vlanSettings = wmiCallsV2.GetVlanSettings(item);
+                    if (vlanSettings == null)
+                    {
+                        vlanid = -1;
+                    }
+                    else
+                    {
+                        vlanid = vlanSettings.AccessVlanId;
+                    }
+                    nic = new NicDetails(macAddress[index++], vlanid);
+                    nicDetails.Add(nic);
+                }
+
+                result = true;
+
+                object ansContent = new
+                {
+                    vmName = vmName,
+                    nics = nicDetails,
+                    result = result,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmConfigAnswer);
+            }
+        }
+
+
+
         // POST api/HypervResource/GetVmStatsCommand
         [HttpPost]
         [ActionName(CloudStackTypes.GetVmStatsCommand)]

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs
index 5f814c5..9042d7c 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs
@@ -66,5 +66,6 @@ namespace HypervResource
         void patchSystemVmIso(string vmName, string systemVmIso);
         void SetState(ComputerSystem vm, ushort requiredState);
         Dictionary<String, VmState> GetVmSync(String privateIpAddress);
+        void ModifyVmVLan(string vmName, uint vlanid, string mac);
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
index 2e3aca5..b9694f0 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
@@ -443,6 +443,7 @@ namespace HypervResource
                 nicCount++;
             }
 
+
             // pass the boot args for the VM using KVP component.
             // We need to pass the boot args to system vm's to get them configured with cloudstack configuration.
             // Add new user data
@@ -909,6 +910,37 @@ namespace HypervResource
             return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());
         }
 
+
+        // Modify the systemvm nic's VLAN id
+        public void ModifyVmVLan(string vmName, uint vlanid, String mac)
+        {
+            ComputerSystem vm = GetComputerSystem(vmName);
+            SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm);
+            // Obtain controller for Hyper-V virtualisation subsystem
+            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
+            string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' })));
+            int index = 0;
+            foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
+            {
+                if (normalisedMAC.ToLower().Equals(item.Address.ToLower()))
+                {
+                    break;
+                }
+                index++;
+            }
+
+            //TODO: make sure the index wont be out of range.
+
+            EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm);
+            EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]);
+
+            //Assign configuration to new NIC
+            vlanSettings.LateBoundObject["AccessVlanId"] = vlanid;
+            vlanSettings.LateBoundObject["OperationMode"] = 1;
+            ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] {
+                vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)});
+        }
+
         public void AttachIso(string displayName, string iso)
         {
             logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName);
@@ -1420,6 +1452,36 @@ namespace HypervResource
             return vSwitch;
         }
 
+
+        private static void ModifyFeatureVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)
+        {
+            // Resource settings are changed through the management service
+            System.Management.ManagementPath jobPath;
+            System.Management.ManagementPath[] results;
+
+            var ret_val = vmMgmtSvc.ModifyFeatureSettings(
+                resourceSettings,
+                out jobPath,
+                out results);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
         private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)
         {
             // Resource settings are changed through the management service

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java
index 5845038..1d9e7f6 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java
@@ -16,15 +16,30 @@
 // under the License.
 package com.cloud.hypervisor.hyperv.guru;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
 import javax.ejb.Local;
 import javax.inject.Inject;
 
+import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.HypervisorGuru;
 import com.cloud.hypervisor.HypervisorGuruBase;
 import com.cloud.storage.GuestOSVO;
 import com.cloud.storage.dao.GuestOSDao;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.hypervisor.hyperv.manager.HypervManager;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
 
 /**
@@ -35,6 +50,9 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru {
 
     @Inject
     private GuestOSDao _guestOsDao;
+    @Inject HypervManager _hypervMgr;
+    @Inject NetworkDao _networkDao;
+    @Inject NetworkModel _networkMgr;
 
     @Override
     public final HypervisorType getHypervisorType() {
@@ -51,6 +69,78 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru {
     @Override
     public final VirtualMachineTO implement(VirtualMachineProfile vm) {
         VirtualMachineTO to = toVirtualMachineTO(vm);
+        List<NicProfile> nicProfiles = vm.getNics();
+
+        if(vm.getVirtualMachine().getType() ==  VirtualMachine.Type.DomainRouter) {
+
+            NicProfile publicNicProfile = null;
+            for(NicProfile nicProfile : nicProfiles) {
+                if(nicProfile.getTrafficType() == TrafficType.Public) {
+                    publicNicProfile = nicProfile;
+                    break;
+                }
+            }
+
+            if(publicNicProfile != null) {
+                NicTO[] nics = to.getNics();
+
+                // reserve extra NICs
+                NicTO[] expandedNics = new NicTO[nics.length +  _hypervMgr.getRouterExtraPublicNics()];
+                int i = 0;
+                int deviceId = -1;
+                for(i = 0; i < nics.length; i++) {
+                    expandedNics[i] = nics[i];
+                    if(nics[i].getDeviceId() > deviceId)
+                        deviceId = nics[i].getDeviceId();
+                }
+                deviceId++;
+
+                long networkId = publicNicProfile.getNetworkId();
+                NetworkVO network = _networkDao.findById(networkId);
+
+                for(; i < nics.length + _hypervMgr.getRouterExtraPublicNics(); i++) {
+                    NicTO nicTo = new NicTO();
+                    nicTo.setDeviceId(deviceId++);
+                    nicTo.setBroadcastType(publicNicProfile.getBroadcastType());
+                    nicTo.setType(publicNicProfile.getTrafficType());
+                    nicTo.setIp("0.0.0.0");
+                    nicTo.setNetmask("255.255.255.255");
+                    nicTo.setName(publicNicProfile.getName());
+
+                    try {
+                        String mac = _networkMgr.getNextAvailableMacAddressInNetwork(networkId);
+                        nicTo.setMac(mac);
+                    } catch (InsufficientAddressCapacityException e) {
+                        throw new CloudRuntimeException("unable to allocate mac address on network: " + networkId);
+                    }
+                    nicTo.setDns1(publicNicProfile.getDns1());
+                    nicTo.setDns2(publicNicProfile.getDns2());
+                    if (publicNicProfile.getGateway() != null) {
+                        nicTo.setGateway(publicNicProfile.getGateway());
+                    } else {
+                        nicTo.setGateway(network.getGateway());
+                    }
+                    nicTo.setDefaultNic(false);
+                    nicTo.setBroadcastUri(publicNicProfile.getBroadCastUri());
+                    nicTo.setIsolationuri(publicNicProfile.getIsolationUri());
+
+                    Integer networkRate = _networkMgr.getNetworkRate(network.getId(), null);
+                    nicTo.setNetworkRateMbps(networkRate);
+
+                    expandedNics[i] = nicTo;
+                }
+                to.setNics(expandedNics);
+            }
+
+            StringBuffer sbMacSequence = new StringBuffer();
+            for(NicTO nicTo : sortNicsByDeviceId(to.getNics())) {
+                sbMacSequence.append(nicTo.getMac()).append("|");
+            }
+            sbMacSequence.deleteCharAt(sbMacSequence.length() - 1);
+            String bootArgs = to.getBootArgs();
+            to.setBootArgs(bootArgs + " nic_macs=" + sbMacSequence.toString());
+
+        }
 
         // Determine the VM's OS description
         GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId());
@@ -59,6 +149,29 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru {
         return to;
     }
 
+    private NicTO[] sortNicsByDeviceId(NicTO[] nics) {
+
+        List<NicTO> listForSort = new ArrayList<NicTO>();
+        for (NicTO nic : nics) {
+            listForSort.add(nic);
+        }
+        Collections.sort(listForSort, new Comparator<NicTO>() {
+
+            @Override
+            public int compare(NicTO arg0, NicTO arg1) {
+                if (arg0.getDeviceId() < arg1.getDeviceId()) {
+                    return -1;
+                } else if (arg0.getDeviceId() == arg1.getDeviceId()) {
+                    return 0;
+                }
+
+                return 1;
+            }
+        });
+
+        return listForSort.toArray(new NicTO[0]);
+    }
+
     @Override
     public final boolean trackVmHostChange() {
         return false;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java
index 9030e29..5821fe4 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java
@@ -21,4 +21,5 @@ import com.cloud.utils.component.Manager;
 
 public interface HypervManager extends Manager {
     public String prepareSecondaryStorageStore(long zoneId);
+    int getRouterExtraPublicNics();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
index a30eb7d..71a619a 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
@@ -45,6 +45,8 @@ import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.script.Script;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.VMInstanceDao;
 
 @Local(value = {HypervManager.class})
 public class HypervManagerImpl implements HypervManager {
@@ -60,10 +62,11 @@ public class HypervManagerImpl implements HypervManager {
     Map<String, String> _storageMounts = new HashMap<String, String>();
     StorageLayer _storage;
 
-    @Inject
-    ConfigurationDao _configDao;
-    @Inject
-    DataStoreManager _dataStoreMgr;
+    @Inject ConfigurationDao _configDao;
+    @Inject DataStoreManager _dataStoreMgr;
+    @Inject VMInstanceDao _vminstanceDao;
+    @Inject NicDao _nicDao;
+    int _routerExtraPublicNics = 2;
 
     @Override
     public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@@ -77,7 +80,7 @@ public class HypervManagerImpl implements HypervManager {
             _storage = new JavaStorageLayer();
             _storage.configure("StorageLayer", params);
         }
-
+        _routerExtraPublicNics = NumbersUtil.parseInt(_configDao.getValue(Config.RouterExtraPublicNics.key()), 2);
         return true;
     }
 
@@ -373,4 +376,9 @@ public class HypervManagerImpl implements HypervManager {
             }
         }
     }
-}
+
+    @Override
+    public int getRouterExtraPublicNics() {
+        return _routerExtraPublicNics;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
index d6ffa1d..e9647ad 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
@@ -71,7 +71,12 @@ import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.GetDomRVersionAnswer;
 import com.cloud.agent.api.GetDomRVersionCmd;
+import com.cloud.agent.api.GetVmConfigAnswer;
+import com.cloud.agent.api.GetVmConfigAnswer.NicDetails;
+import com.cloud.agent.api.GetVmConfigCommand;
 import com.cloud.agent.api.HostVmStateReportEntry;
+import com.cloud.agent.api.ModifyVmNicConfigAnswer;
+import com.cloud.agent.api.ModifyVmNicConfigCommand;
 import com.cloud.agent.api.NetworkUsageAnswer;
 import com.cloud.agent.api.NetworkUsageCommand;
 import com.cloud.agent.api.PingCommand;
@@ -117,11 +122,13 @@ import com.cloud.agent.api.to.PortForwardingRuleTO;
 import com.cloud.agent.api.to.StaticNatRuleTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.exception.InternalErrorException;
 import com.cloud.host.Host.Type;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.hypervisor.hyperv.manager.HypervManager;
 import com.cloud.network.HAProxyConfigurator;
 import com.cloud.network.LoadBalancerConfigurator;
+import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.RouterPrivateIpStrategy;
 import com.cloud.network.rules.FirewallRule;
 import com.cloud.resource.ServerResource;
@@ -133,6 +140,8 @@ import com.cloud.utils.net.NetUtils;
 import com.cloud.utils.ssh.SshHelper;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineName;
+
+
 /**
  * Implementation of dummy resource to be returned from discoverer.
  **/
@@ -706,65 +715,6 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
         }
     }
 
-    //
-    // find mac address of a specified ethx device
-    //    ip address show ethx | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2
-    // returns
-    //      eth0:xx.xx.xx.xx
-
-    //
-    // list IP with eth devices
-    //  ifconfig ethx |grep -B1 "inet addr" | awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }'
-    //     | awk -F: '{ print $1 ": " $3 }'
-    //
-    // returns
-    //      eth0:xx.xx.xx.xx
-    //
-    //
-
-    private int findRouterEthDeviceIndex(String domrName, String routerIp, String mac) throws Exception {
-
-        s_logger.info("findRouterEthDeviceIndex. mac: " + mac);
-
-        // TODO : this is a temporary very inefficient solution, will refactor it later
-        Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "ls /proc/sys/net/ipv4/conf");
-
-        // when we dynamically plug in a new NIC into virtual router, it may take time to show up in guest OS
-        // we use a waiting loop here as a workaround to synchronize activities in systems
-        long startTick = System.currentTimeMillis();
-        while (System.currentTimeMillis() - startTick < 15000) {
-            if (result.first()) {
-                String[] tokens = result.second().split("\\s+");
-                for (String token : tokens) {
-                    if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) {
-                        String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
-
-                        if (s_logger.isDebugEnabled())
-                            s_logger.debug("Run domr script " + cmd);
-                        Pair<Boolean, String> result2 = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
-                            // TODO need to find the dev index inside router based on IP address
-                            cmd);
-                        if (s_logger.isDebugEnabled())
-                            s_logger.debug("result: " + result2.first() + ", output: " + result2.second());
-
-                        if (result2.first() && result2.second().trim().equalsIgnoreCase(mac.trim()))
-                            return Integer.parseInt(token.substring(3));
-                    }
-                }
-            }
-
-            s_logger.warn("can not find intereface associated with mac: " + mac + ", guest OS may still at loading state, retry...");
-
-            try {
-                Thread.currentThread();
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-            }
-        }
-
-        return -1;
-    }
-
     protected Answer execute(SetPortForwardingRulesCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource SetPortForwardingRulesCommand: " + s_gson.toJson(cmd));
@@ -1170,7 +1120,6 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource VmDataCommand: " + s_gson.toJson(cmd));
         }
-
         String routerPrivateIpAddress = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
         String controlIp = getRouterSshControlIp(cmd);
 
@@ -1386,6 +1335,102 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
         return new Answer(cmd);
     }
 
+    //
+    // find mac address of a specified ethx device
+    //    ip address show ethx | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2
+    // returns
+    //      eth0:xx.xx.xx.xx
+
+    //
+    // list IP with eth devices
+    //  ifconfig ethx |grep -B1 "inet addr" | awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }'
+    //     | awk -F: '{ print $1 ": " $3 }'
+    //
+    // returns
+    //      eth0:xx.xx.xx.xx
+    //
+    //
+
+    private int findRouterEthDeviceIndex(String domrName, String routerIp, String mac) throws Exception {
+
+        s_logger.info("findRouterEthDeviceIndex. mac: " + mac);
+
+        // TODO : this is a temporary very inefficient solution, will refactor it later
+        Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+                "ls /proc/sys/net/ipv4/conf");
+
+        // when we dynamically plug in a new NIC into virtual router, it may take time to show up in guest OS
+        // we use a waiting loop here as a workaround to synchronize activities in systems
+        long startTick = System.currentTimeMillis();
+        while (System.currentTimeMillis() - startTick < 15000) {
+            if (result.first()) {
+                String[] tokens = result.second().split("\\s+");
+                for (String token : tokens) {
+                    if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) {
+                        String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
+
+                        if (s_logger.isDebugEnabled())
+                            s_logger.debug("Run domr script " + cmd);
+                        Pair<Boolean, String> result2 = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+                                // TODO need to find the dev index inside router based on IP address
+                                cmd);
+                        if (s_logger.isDebugEnabled())
+                            s_logger.debug("result: " + result2.first() + ", output: " + result2.second());
+
+                        if (result2.first() && result2.second().trim().equalsIgnoreCase(mac.trim()))
+                            return Integer.parseInt(token.substring(3));
+                    }
+                }
+            }
+
+            s_logger.warn("can not find intereface associated with mac: " + mac + ", guest OS may still at loading state, retry...");
+
+        }
+
+        return -1;
+    }
+
+    private Pair<Integer, String> findRouterFreeEthDeviceIndex(String routerIp) throws Exception {
+
+        s_logger.info("findRouterFreeEthDeviceIndex. mac: ");
+
+        // TODO : this is a temporary very inefficient solution, will refactor it later
+        Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+                "ip address | grep DOWN| cut -f2 -d :");
+
+        // when we dynamically plug in a new NIC into virtual router, it may take time to show up in guest OS
+        // we use a waiting loop here as a workaround to synchronize activities in systems
+        long startTick = System.currentTimeMillis();
+        while (System.currentTimeMillis() - startTick < 15000) {
+            if (result.first() && !result.second().isEmpty()) {
+                String[] tokens = result.second().split("\\n");
+                for (String token : tokens) {
+                    if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) {
+                        //String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
+                        //TODO: don't check for eth0,1,2, as they will be empty by default.
+                        //String cmd = String.format("ip address show %s ", token);
+                        String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
+                        if (s_logger.isDebugEnabled())
+                            s_logger.debug("Run domr script " + cmd);
+                        Pair<Boolean, String> result2 = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+                                // TODO need to find the dev index inside router based on IP address
+                                cmd);
+                        if (s_logger.isDebugEnabled())
+                            s_logger.debug("result: " + result2.first() + ", output: " + result2.second());
+
+                        if (result2.first() && result2.second().trim().length() > 0)
+                            return new Pair<Integer, String>(Integer.parseInt(token.trim().substring(3)), result2.second().trim()) ;
+                    }
+                }
+            }
+
+            //s_logger.warn("can not find intereface associated with mac: , guest OS may still at loading state, retry...");
+
+        }
+
+        return new Pair<Integer, String>(-1, "");
+    }
+
     protected Answer execute(IpAssocCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource IPAssocCommand: " + s_gson.toJson(cmd));
@@ -1401,7 +1446,7 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
             String controlIp = getRouterSshControlIp(cmd);
             for (IpAddressTO ip : ips) {
                 assignPublicIpAddress(routerName, controlIp, ip.getPublicIp(), ip.isAdd(), ip.isFirstIP(), ip.isSourceNat(), ip.getBroadcastUri(), ip.getVlanGateway(),
-                    ip.getVlanNetmask(), ip.getVifMacAddress());
+                        ip.getVlanNetmask(), ip.getVifMacAddress());
                 results[i++] = ip.getPublicIp() + " - success";
             }
 
@@ -1419,16 +1464,97 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
         return new IpAssocAnswer(cmd, results);
     }
 
+    protected int getVmNics(String vmName, int vlanid) {
+        GetVmConfigCommand vmConfig = new GetVmConfigCommand(vmName);
+        URI agentUri = null;
+        int nicposition = -1;
+        try {
+            String cmdName = GetVmConfigCommand.class.getName();
+            agentUri =
+                    new URI("https", null, _agentIp, _port,
+                            "/api/HypervResource/" + cmdName, null, null);
+        } catch (URISyntaxException e) {
+            String errMsg = "Could not generate URI for Hyper-V agent";
+            s_logger.error(errMsg, e);
+        }
+        String ansStr = postHttpRequest(s_gson.toJson(vmConfig), agentUri);
+        Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
+        s_logger.debug("executeRequest received response "
+                + s_gson.toJson(result));
+        if (result.length > 0) {
+            GetVmConfigAnswer ans = ((GetVmConfigAnswer)result[0]);
+            List<NicDetails> nics = ans.getNics();
+            for (NicDetails nic : nics) {
+                if (nic.getVlanid() == vlanid) {
+                    nicposition = nics.indexOf(nic);
+                    break;
+                }
+            }
+        }
+        return nicposition;
+    }
+
+    protected void modifyNicVlan(String vmName, int vlanId, String macAddress) {
+        ModifyVmNicConfigCommand modifynic = new ModifyVmNicConfigCommand(vmName, vlanId, macAddress);
+        URI agentUri = null;
+        try {
+            String cmdName = ModifyVmNicConfigCommand.class.getName();
+            agentUri =
+                    new URI("https", null, _agentIp, _port,
+                            "/api/HypervResource/" + cmdName, null, null);
+        } catch (URISyntaxException e) {
+            String errMsg = "Could not generate URI for Hyper-V agent";
+            s_logger.error(errMsg, e);
+        }
+        String ansStr = postHttpRequest(s_gson.toJson(modifynic), agentUri);
+        Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
+        s_logger.debug("executeRequest received response "
+                + s_gson.toJson(result));
+        if (result.length > 0) {
+            ModifyVmNicConfigAnswer ans = ((ModifyVmNicConfigAnswer)result[0]);
+        }
+    }
+
     protected void assignPublicIpAddress(final String vmName, final String privateIpAddress, final String publicIpAddress, final boolean add, final boolean firstIP,
-        final boolean sourceNat, final String vlanId, final String vlanGateway, final String vlanNetmask, final String vifMacAddress) throws Exception {
+            final boolean sourceNat, final String broadcastId, final String vlanGateway, final String vlanNetmask, final String vifMacAddress) throws Exception {
+
+        URI broadcastUri = BroadcastDomainType.fromString(broadcastId);
+        if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) {
+            throw new InternalErrorException("Unable to assign a public IP to a VIF on network " + broadcastId);
+        }
+        int vlanId = Integer.parseInt(BroadcastDomainType.getValue(broadcastUri));
+
+        int publicNicInfo = -1;
+        publicNicInfo = getVmNics(vmName, vlanId);
 
         boolean addVif = false;
-        if (add) {
+        if (add && publicNicInfo == -1) {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Plug new NIC to associate" + privateIpAddress + " to " + publicIpAddress);
             }
             addVif = true;
         } else if (!add && firstIP) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Unplug NIC " + publicNicInfo);
+            }
+        }
+
+        if (addVif) {
+            Pair<Integer, String> nicdevice = findRouterFreeEthDeviceIndex(privateIpAddress);
+            publicNicInfo = nicdevice.first();
+            if (publicNicInfo > 0) {
+                modifyNicVlan(vmName, vlanId, nicdevice.second());
+                // After modifying the vnic on VR, check the VR VNics config in the host and get the device position
+                publicNicInfo = getVmNics(vmName, vlanId);
+                // As a new nic got activated in the VR. add the entry in the NIC's table.
+                networkUsage(privateIpAddress, "addVif", "eth" + publicNicInfo);
+            }
+            else {
+                // we didn't find any eth device available in VR to configure the ip range with new VLAN
+                String msg = "No Nic is available on DomR VIF to associate/disassociate IP with.";
+                s_logger.error(msg);
+                throw new InternalErrorException(msg);
+            }
         }
 
         String args = null;
@@ -1450,8 +1576,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
         args += publicIpAddress + "/" + cidrSize;
 
         args += " -c ";
-        args += "eth" + "2";  // currently hardcoding to eth 2 (which is default public ipd)//publicNicInfo.first();
 
+        args += "eth" + publicNicInfo;
         args += " -g ";
         args += vlanGateway;
 
@@ -1464,7 +1590,7 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
         }
 
         Pair<Boolean, String> result =
-            SshHelper.sshExecute(privateIpAddress, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/ipassoc.sh " + args);
+                SshHelper.sshExecute(privateIpAddress, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/ipassoc.sh " + args);
 
         if (!result.first()) {
             s_logger.error("ipassoc command on domain router " + privateIpAddress + " failed. message: " + result.second());
@@ -1840,7 +1966,7 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
                 sch.connect(addr);
                 return null;
             } catch (IOException e) {
-                s_logger.info("Could not connect to " + ipAddress + " due to " + e.toString());
+                s_logger.info("Could] not connect to " + ipAddress + " due to " + e.toString());
                 if (e instanceof ConnectException) {
                     // if connection is refused because of VM is being started,
                     // we give it more sleep time

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index 13291d0..bf2516a 100755
--- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -2125,7 +2125,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
             buf.append(" dnssearchorder=").append(domain_suffix);
         }
 
-        if (profile.getHypervisorType() == HypervisorType.VMware) {
+        if (profile.getHypervisorType() == HypervisorType.VMware || profile.getHypervisorType() == HypervisorType.Hyperv) {
             buf.append(" extra_pubnics=" + _routerExtraPublicNics);
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/807dc091/systemvm/patches/debian/config/opt/cloud/bin/ipassoc.sh
----------------------------------------------------------------------
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/ipassoc.sh b/systemvm/patches/debian/config/opt/cloud/bin/ipassoc.sh
index ae2d7e4..2a9d780 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/ipassoc.sh
+++ b/systemvm/patches/debian/config/opt/cloud/bin/ipassoc.sh
@@ -254,10 +254,11 @@ remove_first_ip() {
   if [ $? -gt 0  -a $? -ne 2 ]
   then
      remove_routing $1
+     sudo ip link set $ethDev down
      return 1
   fi
   remove_routing $1
-
+  sudo ip link set $ethDev down
   return $?
 }