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

[3/3] git commit: updated refs/heads/master to b11e3bc

CLOUDSTACK-6278
Baremetal Advanced Networking support


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

Branch: refs/heads/master
Commit: 8b89494a350979162d986edb5125970222895324
Parents: d315a5e
Author: Frank Zhang <fr...@citrix.com>
Authored: Wed Sep 17 12:39:21 2014 -0700
Committer: Frank Zhang <fr...@citrix.com>
Committed: Thu Sep 18 16:54:37 2014 -0700

----------------------------------------------------------------------
 .../core/spring-baremetal-core-context.xml      |   8 +-
 .../baremetal/manager/BaremetalVlanManager.java |   3 +
 .../manager/BaremetalVlanManagerImpl.java       |  12 +-
 .../networkservice/BareMetalResourceBase.java   |   2 +-
 .../BaremetalKickStartServiceImpl.java          |  14 +--
 .../networkservice/BaremetalPxeElement.java     |   5 +-
 .../Force10BaremetalSwitchBackend.java          | 116 ++++++++++++++-----
 scripts/network/ping/baremetal_snat.sh          |  21 +++-
 scripts/network/ping/prepare_pxe.sh             |  45 +++----
 .../patches/debian/config/etc/dnsmasq.conf.tmpl |   6 +-
 .../com/cloud/utils/xmlobject/XmlObject.java    |  15 ++-
 .../cloud/utils/xmlobject/XmlObjectParser.java  |  22 ++--
 .../cloud/utils/xmlobject/TestXmlObject.java    |   5 +
 13 files changed, 182 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/plugins/hypervisors/baremetal/resources/META-INF/cloudstack/core/spring-baremetal-core-context.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/resources/META-INF/cloudstack/core/spring-baremetal-core-context.xml b/plugins/hypervisors/baremetal/resources/META-INF/cloudstack/core/spring-baremetal-core-context.xml
index ae28efa..a153e7f 100755
--- a/plugins/hypervisors/baremetal/resources/META-INF/cloudstack/core/spring-baremetal-core-context.xml
+++ b/plugins/hypervisors/baremetal/resources/META-INF/cloudstack/core/spring-baremetal-core-context.xml
@@ -28,7 +28,13 @@
                       >
 
     <bean id="BaremetalManager" class="com.cloud.baremetal.manager.BaremetalManagerImpl" />
-    <bean id="BaremetalVlanManager" class="com.cloud.baremetal.manager.BaremetalVlanManagerImpl" />
+    <bean id="BaremetalVlanManager" class="com.cloud.baremetal.manager.BaremetalVlanManagerImpl" >
+       <property name="backends">
+           <map>
+               <entry key="Force10" value-ref="Force10BaremetalSwitchBackend"/>
+           </map>
+       </property>
+    </bean>
     <bean id="Force10BaremetalSwitchBackend" class="com.cloud.baremetal.networkservice.Force10BaremetalSwitchBackend" />
 
     <bean id="BaremetalKickStartPxeService"

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManager.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManager.java
index 1662668..9527f08 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManager.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManager.java
@@ -18,6 +18,7 @@
 package com.cloud.baremetal.manager;
 
 import com.cloud.baremetal.networkservice.BaremetalRctResponse;
+import com.cloud.baremetal.networkservice.BaremetalSwitchBackend;
 import com.cloud.deploy.DeployDestination;
 import com.cloud.network.Network;
 import com.cloud.utils.component.Manager;
@@ -36,4 +37,6 @@ public interface BaremetalVlanManager extends Manager, PluggableService {
     void prepareVlan(Network nw, DeployDestination destHost);
 
     void releaseVlan(Network nw, VirtualMachineProfile vm);
+
+    void registerSwitchBackend(BaremetalSwitchBackend backend);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java
index 0334fb3..6cb91f8 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java
@@ -47,7 +47,6 @@ import javax.inject.Inject;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -69,13 +68,17 @@ public class BaremetalVlanManagerImpl extends ManagerBase implements BaremetalVl
     @Inject
     private AccountManager acntMgr;
 
-    private Map<String, BaremetalSwitchBackend> backends = new HashMap<>();
+    private Map<String, BaremetalSwitchBackend> backends;
 
     private class RackPair {
         BaremetalRct.Rack rack;
         BaremetalRct.HostEntry host;
     }
 
+    public void setBackends(Map<String, BaremetalSwitchBackend> backends) {
+        this.backends = backends;
+    }
+
     @Override
     public BaremetalRctResponse addRct(AddBaremetalRctCmd cmd) {
         try {
@@ -161,6 +164,11 @@ public class BaremetalVlanManagerImpl extends ManagerBase implements BaremetalVl
         backend.removePortFromVlan(struct);
     }
 
+    @Override
+    public void registerSwitchBackend(BaremetalSwitchBackend backend) {
+        backends.put(backend.getSwitchBackendType(), backend);
+    }
+
     private BaremetalSwitchBackend getSwitchBackend(String type) {
         BaremetalSwitchBackend backend = backends.get(type);
         if (backend == null) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
index fedfb8b..49a935a 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
@@ -391,7 +391,7 @@ public class BareMetalResourceBase extends ManagerBase implements ServerResource
                 VMInstanceVO vm = vms.get(0);
                 SecurityGroupHttpClient client = new SecurityGroupHttpClient();
                 HashMap<String, Pair<Long, Long>> nwGrpStates = client.sync(vm.getInstanceName(), vm.getId(), vm.getPrivateIpAddress());
-                return new PingRoutingWithNwGroupsCommand(getType(), id, getHostVmStateReport(), nwGrpStates);
+                return new PingRoutingWithNwGroupsCommand(getType(), id, null, nwGrpStates);
             }
         } else {
             return new PingRoutingCommand(getType(), id, getHostVmStateReport());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java
index bd363f6..2e236c2 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java
@@ -219,19 +219,19 @@ public class BaremetalKickStartServiceImpl extends BareMetalPxeServiceBase imple
         }
 
         List<String> tuple =  parseKickstartUrl(profile);
-        Pair<Boolean, String> ret = SshHelper.sshExecute(mgmtNic.getIp4Address(), 3922, "root", getSystemVMKeyFile(), null,
-                String.format("/usr/bin/prepare_pxe.sh %s %s %s %s %s", tuple.get(1), tuple.get(2), profile.getTemplate().getUuid(),
-                        String.format("01-%s", nic.getMacAddress().replaceAll(":", "-")), tuple.get(0))
-                );
+        String cmd =  String.format("/usr/bin/prepare_pxe.sh %s %s %s %s %s %s", tuple.get(1), tuple.get(2), profile.getTemplate().getUuid(),
+                String.format("01-%s", nic.getMacAddress().replaceAll(":", "-")).toLowerCase(), tuple.get(0), nic.getMacAddress().toLowerCase());
+        s_logger.debug(String.format("prepare pxe on virtual router[ip:%s], cmd: %s", mgmtNic.getIp4Address(), cmd));
+        Pair<Boolean, String> ret = SshHelper.sshExecute(mgmtNic.getIp4Address(), 3922, "root", getSystemVMKeyFile(), null, cmd);
         if (!ret.first()) {
             throw new CloudRuntimeException(String.format("failed preparing PXE in virtual router[id:%s], because %s", vr.getId(), ret.second()));
         }
 
         //String internalServerIp = _configDao.getValue(Config.BaremetalInternalStorageServer.key());
         String internalServerIp = "10.223.110.231";
-        ret = SshHelper.sshExecute(mgmtNic.getIp4Address(), 3922, "root", getSystemVMKeyFile(), null,
-                String.format("/usr/bin/baremetal_snat.sh %s %s", mgmtNic.getIp4Address(), internalServerIp)
-                );
+        cmd = String.format("/usr/bin/baremetal_snat.sh %s %s %s", mgmtNic.getIp4Address(), internalServerIp, mgmtNic.getGateway());
+        s_logger.debug(String.format("prepare SNAT on virtual router[ip:%s], cmd: %s", mgmtNic.getIp4Address(), cmd));
+        ret = SshHelper.sshExecute(mgmtNic.getIp4Address(), 3922, "root", getSystemVMKeyFile(), null, cmd);
         if (!ret.first()) {
             throw new CloudRuntimeException(String.format("failed preparing PXE in virtual router[id:%s], because %s", vr.getId(), ret.second()));
         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java
index 5d20d31..10b81c2 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java
@@ -21,6 +21,7 @@ package com.cloud.baremetal.networkservice;
 import com.cloud.baremetal.database.BaremetalPxeVO;
 import com.cloud.baremetal.manager.BaremetalVlanManager;
 import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.Pod;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.deploy.DeployDestination;
@@ -139,11 +140,9 @@ public class BaremetalPxeElement extends AdapterBase implements NetworkElement {
             }
         }
 
-        /*
         if (dest.getDataCenter().getNetworkType() == DataCenter.NetworkType.Advanced){
             prepareVlan(network, dest);
         }
-        */
 
         return true;
     }
@@ -159,12 +158,10 @@ public class BaremetalPxeElement extends AdapterBase implements NetworkElement {
             return false;
         }
 
-        /*
         DataCenterVO dc = zoneDao.findById(vm.getVirtualMachine().getDataCenterId());
         if (dc.getNetworkType() == DataCenter.NetworkType.Advanced) {
             releaseVlan(network, vm);
         }
-        */
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/Force10BaremetalSwitchBackend.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/Force10BaremetalSwitchBackend.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/Force10BaremetalSwitchBackend.java
old mode 100644
new mode 100755
index 9009b02..ceaf25c
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/Force10BaremetalSwitchBackend.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/Force10BaremetalSwitchBackend.java
@@ -32,11 +32,16 @@ import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.client.ResponseErrorHandler;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 
+import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -46,17 +51,38 @@ public class Force10BaremetalSwitchBackend implements BaremetalSwitchBackend {
     private Logger logger = Logger.getLogger(Force10BaremetalSwitchBackend.class);
     public static final String TYPE = "Force10";
 
+    private static List<HttpStatus> successHttpStatusCode = new ArrayList<>();
+    {
+        successHttpStatusCode.add(HttpStatus.OK);
+        successHttpStatusCode.add(HttpStatus.ACCEPTED);
+        successHttpStatusCode.add(HttpStatus.CREATED);
+        successHttpStatusCode.add(HttpStatus.NO_CONTENT);
+        successHttpStatusCode.add(HttpStatus.PARTIAL_CONTENT);
+        successHttpStatusCode.add(HttpStatus.RESET_CONTENT);
+        successHttpStatusCode.add(HttpStatus.ALREADY_REPORTED);
+    }
+
     RestTemplate rest = new RestTemplate();
+    {
+        // fake error handler, we handle error in business logic code
+        rest.setErrorHandler(new ResponseErrorHandler() {
+            @Override
+            public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
+                return false;
+            }
 
-    private String buildLink(String switchIp, Integer vlan) {
+            @Override
+            public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
+            }
+        });
+    }
+
+    private String buildLink(String switchIp, String path) {
         UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
         builder.scheme("http");
         builder.host(switchIp);
         builder.port(8008);
-        builder.path("/api/running/ftos/interface/vlan");
-        if (vlan != null) {
-            builder.path(vlan.toString());
-        }
+        builder.path(path);
         return builder.build().toUriString();
     }
 
@@ -67,29 +93,36 @@ public class Force10BaremetalSwitchBackend implements BaremetalSwitchBackend {
 
     @Override
     public void prepareVlan(BaremetalVlanStruct struct) {
-        String link = buildLink(struct.getSwitchIp(), struct.getVlan());
+        String link = buildLink(struct.getSwitchIp(), String.format("/api/running/ftos/interface/vlan/%s", struct.getVlan()));
         HttpHeaders headers = createBasicAuthenticationHeader(struct);
         HttpEntity<String> request = new HttpEntity<>(headers);
         ResponseEntity rsp = rest.exchange(link, HttpMethod.GET, request, String.class);
+        logger.debug(String.format("http get: %s", link));
 
         if (rsp.getStatusCode() == HttpStatus.NOT_FOUND) {
             PortInfo port = new PortInfo(struct);
-            XmlObject xml = new XmlObject("vlan").putElement("vlan-id", String.valueOf(struct.getVlan())).putElement("tagged",
-                    new XmlObject(port.interfaceType).putElement("name", port.port)
-            ).putElement("shutdown", "false");
-            request = new HttpEntity<>(xml.toString(), headers);
-            link = buildLink(struct.getSwitchIp(), null);
-            rsp = rest.exchange(link, HttpMethod.GET, request, String.class);
-            if (rsp.getStatusCode() != HttpStatus.OK) {
+            XmlObject xml = new XmlObject("vlan").putElement("vlan-id",
+                    new XmlObject("vlan-id").setText(String.valueOf(struct.getVlan()))).putElement("untagged",
+                    new XmlObject("untagged").putElement(port.interfaceType, new XmlObject(port.interfaceType)
+                            .putElement("name", new XmlObject("name").setText(port.port)))
+            ).putElement("shutdown", new XmlObject("shutdown").setText("false"));
+            request = new HttpEntity<>(xml.dump(), headers);
+            link = buildLink(struct.getSwitchIp(), String.format("/api/running/ftos/interface/"));
+            logger.debug(String.format("http get: %s, body: %s", link, request));
+            rsp = rest.exchange(link, HttpMethod.POST, request, String.class);
+            if (!successHttpStatusCode.contains(rsp.getStatusCode())) {
                 throw new CloudRuntimeException(String.format("unable to create vlan[%s] on force10 switch[ip:%s]. HTTP status code:%s, body dump:%s",
-                        struct.getVlan(), rsp.getStatusCode(), struct.getSwitchIp(), rsp.getBody()));
+                        struct.getVlan(), struct.getSwitchIp(),rsp.getStatusCode(), rsp.getBody()));
+            } else {
+                logger.debug(String.format("successfully programmed vlan[%s] on Force10[ip:%s, port:%s]. http response[status code:%s, body:%s]",
+                        struct.getVlan(), struct.getSwitchIp(), struct.getPort(), rsp.getStatusCode(), rsp.getBody()));
             }
-        } else if (rsp.getStatusCode() == HttpStatus.OK) {
+        } else if (successHttpStatusCode.contains(rsp.getStatusCode())) {
             PortInfo port = new PortInfo(struct);
             XmlObject xml = XmlObjectParser.parseFromString((String)rsp.getBody());
-            List<XmlObject> ports = xml.getAsList("tagged.tengigabitethernet");
-            ports.addAll(xml.<XmlObject>getAsList("tagged.gigabitethernet"));
-            ports.addAll(xml.<XmlObject>getAsList("tagged.fortyGigE"));
+            List<XmlObject> ports = xml.getAsList("untagged.tengigabitethernet");
+            ports.addAll(xml.<XmlObject>getAsList("untagged.gigabitethernet"));
+            ports.addAll(xml.<XmlObject>getAsList("untagged.fortyGigE"));
             for (XmlObject pxml : ports) {
                 XmlObject name = pxml.get("name");
                 if (port.port.equals(name.getText())) {
@@ -98,14 +131,26 @@ public class Force10BaremetalSwitchBackend implements BaremetalSwitchBackend {
                 }
             }
 
-            XmlObject tag = xml.get("tagged");
-            tag.putElement(port.interfaceType, new XmlObject("name").setText(port.port));
-            request = new HttpEntity<>(xml.toString(), headers);
-            link = buildLink(struct.getSwitchIp(), struct.getVlan());
+            xml.removeElement("mtu");
+            xml.setText(null);
+            XmlObject tag = xml.get("untagged");
+            if (tag == null) {
+                tag = new XmlObject("untagged");
+                xml.putElement("untagged", tag);
+            }
+
+            tag.putElement(port.interfaceType, new XmlObject(port.interfaceType)
+                    .putElement("name", new XmlObject("name").setText(port.port)));
+            request = new HttpEntity<>(xml.dump(), headers);
+            link = buildLink(struct.getSwitchIp(), String.format("/api/running/ftos/interface/vlan/%s", struct.getVlan()));
+            logger.debug(String.format("http get: %s, body: %s", link, request));
             rsp = rest.exchange(link, HttpMethod.PUT, request, String.class);
-            if (rsp.getStatusCode() != HttpStatus.NO_CONTENT) {
+            if (!successHttpStatusCode.contains(rsp.getStatusCode())) {
                 throw new CloudRuntimeException(String.format("failed to program vlan[%s] for port[%s] on force10[ip:%s]. http status:%s, body dump:%s",
                         struct.getVlan(), struct.getPort(), struct.getSwitchIp(), rsp.getStatusCode(), rsp.getBody()));
+            } else {
+                logger.debug(String.format("successfully join port[%s] into vlan[%s] on Force10[ip:%s]. http response[status code:%s, body:%s]",
+                        struct.getPort(), struct.getVlan(), struct.getSwitchIp(), rsp.getStatusCode(), rsp.getBody()));
             }
         } else {
             throw new CloudRuntimeException(String.format("force10[ip:%s] returns unexpected error[%s] when http getting %s, body dump:%s",
@@ -115,18 +160,19 @@ public class Force10BaremetalSwitchBackend implements BaremetalSwitchBackend {
 
     @Override
     public void removePortFromVlan(BaremetalVlanStruct struct) {
-        String link = buildLink(struct.getSwitchIp(), struct.getVlan());
+        String link = buildLink(struct.getSwitchIp(), String.format("/api/running/ftos/interface/vlan/%s", struct.getVlan()));
         HttpHeaders headers = createBasicAuthenticationHeader(struct);
         HttpEntity<String> request = new HttpEntity<>(headers);
+        logger.debug(String.format("http get: %s, body: %s", link, request));
         ResponseEntity rsp = rest.exchange(link, HttpMethod.GET, request, String.class);
         if (rsp.getStatusCode() == HttpStatus.NOT_FOUND) {
             logger.debug(String.format("vlan[%s] has been deleted on force10[ip:%s], no need to remove the port[%s] anymore", struct.getVlan(), struct.getSwitchIp(), struct.getPort()));
         } else if (rsp.getStatusCode() == HttpStatus.OK) {
             PortInfo port = new PortInfo(struct);
             XmlObject xml = XmlObjectParser.parseFromString((String)rsp.getBody());
-            List<XmlObject> ports = xml.getAsList("tagged.tengigabitethernet");
-            ports.addAll(xml.<XmlObject>getAsList("tagged.gigabitethernet"));
-            ports.addAll(xml.<XmlObject>getAsList("tagged.fortyGigE"));
+            List<XmlObject> ports = xml.getAsList("untagged.tengigabitethernet");
+            ports.addAll(xml.<XmlObject>getAsList("untagged.gigabitethernet"));
+            ports.addAll(xml.<XmlObject>getAsList("untagged.fortyGigE"));
             List<XmlObject> newPorts = new ArrayList<>();
             boolean needRemove = false;
             for (XmlObject pxml : ports) {
@@ -143,11 +189,19 @@ public class Force10BaremetalSwitchBackend implements BaremetalSwitchBackend {
                 return;
             }
 
-            xml.putElement("tagged", newPorts);
+            xml.setText(null);
+            xml.removeElement("mtu");
+            XmlObject tagged = xml.get("untagged");
+            tagged.removeAllChildren();
+            for (XmlObject p : newPorts) {
+                tagged.putElement(p.getTag(), p);
+            }
+
 
-            request = new HttpEntity<>(xml.toString(), headers);
+            request = new HttpEntity<>(xml.dump(), headers);
+            logger.debug(String.format("http get: %s, body: %s", link, request));
             rsp = rest.exchange(link, HttpMethod.PUT, request, String.class);
-            if (rsp.getStatusCode() != HttpStatus.NO_CONTENT) {
+            if (!successHttpStatusCode.contains(rsp.getStatusCode())) {
                 throw new CloudRuntimeException(String.format("failed to program vlan[%s] for port[%s] on force10[ip:%s]. http status:%s, body dump:%s",
                         struct.getVlan(), struct.getPort(), struct.getSwitchIp(), rsp.getStatusCode(), rsp.getBody()));
             } else {
@@ -166,6 +220,8 @@ public class Force10BaremetalSwitchBackend implements BaremetalSwitchBackend {
         String base64Creds = new String(base64CredsBytes);
         HttpHeaders headers = new HttpHeaders();
         headers.add("Authorization", "Basic " + base64Creds);
+        headers.setAccept(Arrays.asList(MediaType.ALL));
+        headers.setContentType(MediaType.valueOf("application/vnd.yang.data+xml"));
         return  headers;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/scripts/network/ping/baremetal_snat.sh
----------------------------------------------------------------------
diff --git a/scripts/network/ping/baremetal_snat.sh b/scripts/network/ping/baremetal_snat.sh
index f35a16f..22e5669 100755
--- a/scripts/network/ping/baremetal_snat.sh
+++ b/scripts/network/ping/baremetal_snat.sh
@@ -21,11 +21,12 @@ set +u
 
 mgmt_nic_ip=$1
 internal_server_ip=$2
+gateway_ip=$3
 
 ip route | grep "$internal_server_ip" > /dev/null
 
 if [ $? -ne 0 ]; then
-    ip route add $internal_server_ip via $mgmt_nic_ip
+    ip route add $internal_server_ip via $gateway_ip
 fi
 
 iptables-save | grep -- "-A POSTROUTING -d $internal_server_ip" > /dev/null
@@ -33,3 +34,21 @@ iptables-save | grep -- "-A POSTROUTING -d $internal_server_ip" > /dev/null
 if [ $? -ne 0 ]; then
     iptables -t nat -A POSTROUTING -d $internal_server_ip -j SNAT --to-source $mgmt_nic_ip
 fi
+
+
+iptables-save | grep -- "-A INPUT -i eth0 -p udp -m udp --dport 69 -j ACCEPT" > /dev/null
+if [ $? -ne 0 ]; then
+    iptables -I INPUT -i eth0 -p udp -m udp --dport 69 -j ACCEPT
+fi
+
+iptables-save | grep -- "-A FORWARD -i eth1 -o eth0 -j ACCEPT" > /dev/null
+if [ $? -ne 0 ]; then
+    iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
+fi
+
+rule="-A FORWARD -d $internal_server_ip/32 -i eth0 -o eth1 -j ACCEPT"
+iptables-save | grep -- "$rule" > /dev/null
+if [ $? -ne 0 ]; then 
+    iptables -I FORWARD -d $internal_server_ip/32 -i eth0 -o eth1 -j ACCEPT
+fi
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/scripts/network/ping/prepare_pxe.sh
----------------------------------------------------------------------
diff --git a/scripts/network/ping/prepare_pxe.sh b/scripts/network/ping/prepare_pxe.sh
index 2f22b25..2970b4a 100755
--- a/scripts/network/ping/prepare_pxe.sh
+++ b/scripts/network/ping/prepare_pxe.sh
@@ -1,21 +1,4 @@
 #!/bin/sh
-
-#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.
 set +u
 
 err_exit() {
@@ -38,6 +21,20 @@ tmpt_uuid=$3
 pxe_cfg_filename=$4
 ks_file=$5
 
+kernel_path=$tmpt_uuid/$kernel_file_name
+initrd_path=$tmpt_uuid/$initrd_file_name
+
+cat > $PXELINUX_CFG_DIR/$pxe_cfg_filename <<EOF
+DEFAULT default
+PROMPT 1
+TIMEOUT 26
+DISPLAY boot.msg
+LABEL default
+KERNEL $kernel_path
+APPEND ramdisk_size=66000 initrd=$initrd_path ks=$ks_file
+
+EOF
+
 tmpt_dir=$TFTP_ROOT/$tmpt_uuid
 if [ -d $tmpt_dir ]; then
     success
@@ -45,9 +42,6 @@ fi
 
 mkdir -p $tmpt_dir
 
-kernel_path=$tmpt_uuid/$kernel_file_name
-initrd_path=$tmpt_uuid/$initrd_file_name
-
 mnt_path=/tmp/$(uuid)
 
 mkdir -p $mnt_path
@@ -59,17 +53,6 @@ mount `dirname $initrd_nfs_path` $mnt_path
 cp -f $mnt_path/$initrd_file_name $tmpt_dir/$initrd_file_name
 umount $mnt_path
 
-cat > $PXELINUX_CFG_DIR/$pxe_cfg_filename <<EOF
-DEFAULT default
-PROMPT 1
-TIMEOUT 26
-DISPLAY boot.msg
-LABEL default
-KERNEL $kernel_path
-APPEND ramdisk_size=66000 initrd=$initrd_path ks=$ks_file
-
-EOF
-
 success
 
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/systemvm/patches/debian/config/etc/dnsmasq.conf.tmpl
----------------------------------------------------------------------
diff --git a/systemvm/patches/debian/config/etc/dnsmasq.conf.tmpl b/systemvm/patches/debian/config/etc/dnsmasq.conf.tmpl
index 447e748..28b598c 100644
--- a/systemvm/patches/debian/config/etc/dnsmasq.conf.tmpl
+++ b/systemvm/patches/debian/config/etc/dnsmasq.conf.tmpl
@@ -415,7 +415,7 @@ dhcp-option=vendor:MSFT,2,1i
 # this is you want to boot machines over the network and you will need
 # a TFTP server; either dnsmasq's built in TFTP server or an
 # external one. (See below for how to enable the TFTP server.)
-#dhcp-boot=pxelinux.0
+dhcp-boot=pxelinux.0
 
 # The same as above, but use custom tftp-server instead machine running dnsmasq
 #dhcp-boot=pxelinux,server.name,192.168.1.100
@@ -472,10 +472,10 @@ dhcp-option=vendor:MSFT,2,1i
 
 
 # Enable dnsmasq's built-in TFTP server
-#enable-tftp
+enable-tftp
 
 # Set the root directory for files available via FTP.
-#tftp-root=/var/ftpd
+tftp-root=/opt/tftpboot
 
 # Make the TFTP server more secure: with this set, only files owned by
 # the user dnsmasq is running as will be send over the net.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/utils/src/com/cloud/utils/xmlobject/XmlObject.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObject.java b/utils/src/com/cloud/utils/xmlobject/XmlObject.java
index e4e4363..42af945 100755
--- a/utils/src/com/cloud/utils/xmlobject/XmlObject.java
+++ b/utils/src/com/cloud/utils/xmlobject/XmlObject.java
@@ -27,10 +27,12 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.logging.Logger;
 
 import com.cloud.utils.exception.CloudRuntimeException;
 
 public class XmlObject {
+    private final Logger logger = Logger.getLogger(XmlObject.class.getName());
     private final Map<String, Object> elements = new HashMap<String, Object>();
     private String text;
     private String tag;
@@ -38,6 +40,10 @@ public class XmlObject {
     XmlObject() {
     }
 
+    public void removeAllChildren() {
+        elements.clear();
+    }
+
     public XmlObject(String tag) {
         this.tag = tag;
     }
@@ -99,8 +105,12 @@ public class XmlObject {
         if (e instanceof List) {
             return (List<T>)e;
         }
+
         List lst = new ArrayList(1);
-        lst.add(e);
+        if (e != null) {
+            lst.add(e);
+        }
+
         return lst;
     }
 
@@ -142,7 +152,8 @@ public class XmlObject {
         }
 
         if (!children.isEmpty() && text != null) {
-            throw new CloudRuntimeException(String.format("element %s cannot have both text[%s] and child elements", tag, text));
+            logger.info(String.format("element %s cannot have both text[%s] and child elements, set text to null", tag, text));
+            text = null;
         }
 
         if (!children.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java b/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java
old mode 100644
new mode 100755
index 321af0c..f0e8ce3
--- a/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java
+++ b/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java
@@ -19,6 +19,13 @@
 
 package com.cloud.utils.xmlobject;
 
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -26,15 +33,6 @@ import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.util.Stack;
 
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import com.cloud.utils.exception.CloudRuntimeException;
-
 public class XmlObjectParser {
     final private InputStream is;
 
@@ -109,7 +107,11 @@ public class XmlObjectParser {
     public static XmlObject parseFromString(String xmlString) {
         InputStream stream = new ByteArrayInputStream(xmlString.getBytes());
         XmlObjectParser p = new XmlObjectParser(stream);
-        return p.parse();
+        XmlObject obj = p.parse();
+        if (obj.getText() != null && obj.getText().replaceAll("\\n", "").replaceAll("\\r", "").replaceAll(" ", "").isEmpty()) {
+            obj.setText(null);
+        }
+        return obj;
     }
 
     private XmlObject parse() {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8b89494a/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java
----------------------------------------------------------------------
diff --git a/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java b/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java
old mode 100644
new mode 100755
index cbd24b0..faaf980
--- a/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java
+++ b/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java
@@ -43,6 +43,11 @@ public class TestXmlObject {
                 }
             }
             */
+
+        XmlObject xml = new XmlObject("vlan").putElement("vlan-id", String.valueOf(19)).putElement("tagged",
+                new XmlObject("teng").putElement("name", "0/0")
+        ).putElement("shutdown", "false");
+        System.out.println(xml.toString());
     }
 
 }