Merge branch 'pvlan'

Conflicts:
	scripts/vm/hypervisor/xenserver/xenserver60/patch
	server/src/com/cloud/network/NetworkManager.java
	server/src/com/cloud/network/NetworkManagerImpl.java
	server/src/com/cloud/network/NetworkServiceImpl.java
	server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java
	server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
	server/src/com/cloud/network/vpc/VpcManagerImpl.java
	server/src/com/cloud/vm/UserVmManagerImpl.java
	server/test/com/cloud/network/MockNetworkManagerImpl.java
	server/test/com/cloud/vpc/MockNetworkManagerImpl.java
	server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java
This commit is contained in:
Sheng Yang 2013-05-15 16:07:21 -07:00
commit 2d2c0c48cd
29 changed files with 994 additions and 33 deletions

View File

@ -0,0 +1,121 @@
// 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.net.URI;
import com.cloud.utils.net.NetUtils;
public class PvlanSetupCommand extends Command {
public enum Type {
DHCP,
VM
}
private String op;
private String primary;
private String isolated;
private String vmMac;
private String dhcpName;
private String dhcpMac;
private String dhcpIp;
private Type type;
private String networkTag;
protected PvlanSetupCommand() {}
protected PvlanSetupCommand(Type type, String op, URI uri, String networkTag)
{
this.type = type;
this.op = op;
this.primary = NetUtils.getPrimaryPvlanFromUri(uri);
this.isolated = NetUtils.getIsolatedPvlanFromUri(uri);
this.networkTag = networkTag;
}
static public PvlanSetupCommand createDhcpSetup(String op, URI uri, String networkTag, String dhcpName, String dhcpMac, String dhcpIp)
{
PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, uri, networkTag);
cmd.setDhcpName(dhcpName);
cmd.setDhcpMac(dhcpMac);
cmd.setDhcpIp(dhcpIp);
return cmd;
}
static public PvlanSetupCommand createVmSetup(String op, URI uri, String networkTag, String vmMac)
{
PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, uri, networkTag);
cmd.setVmMac(vmMac);
return cmd;
}
@Override
public boolean executeInSequence() {
return true;
}
public String getOp() {
return op;
}
public String getPrimary() {
return primary;
}
public String getIsolated() {
return isolated;
}
public String getVmMac() {
return vmMac;
}
protected void setVmMac(String vmMac) {
this.vmMac = vmMac;
}
public String getDhcpMac() {
return dhcpMac;
}
protected void setDhcpMac(String dhcpMac) {
this.dhcpMac = dhcpMac;
}
public String getDhcpIp() {
return dhcpIp;
}
protected void setDhcpIp(String dhcpIp) {
this.dhcpIp = dhcpIp;
}
public Type getType() {
return type;
}
public String getDhcpName() {
return dhcpName;
}
public void setDhcpName(String dhcpName) {
this.dhcpName = dhcpName;
}
public String getNetworkTag() {
return networkTag;
}
}

View File

@ -63,6 +63,7 @@ public class Networks {
Storage("storage", Integer.class),
Lswitch("lswitch", String.class),
Mido("mido", String.class),
Pvlan("pvlan", String.class),
UnDecided(null, null);
private String scheme;

View File

@ -230,6 +230,7 @@ public class ApiConstants {
public static final String VLAN_RANGE = "vlanrange";
public static final String REMOVE_VLAN="removevlan";
public static final String VLAN_ID = "vlanid";
public static final String ISOLATED_PVLAN = "isolatedpvlan";
public static final String VM_AVAILABLE = "vmavailable";
public static final String VM_LIMIT = "vmlimit";
public static final String VM_TOTAL = "vmtotal";

View File

@ -80,6 +80,9 @@ public class CreateNetworkCmd extends BaseCmd {
@Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="the ID or VID of the network")
private String vlan;
@Parameter(name=ApiConstants.ISOLATED_PVLAN, type=CommandType.STRING, description="the isolated private vlan for this network")
private String isolatedPvlan;
@Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="network domain")
private String networkDomain;
@ -141,6 +144,10 @@ public class CreateNetworkCmd extends BaseCmd {
return vlan;
}
public String getIsolatedPvlan() {
return isolatedPvlan;
}
public String getAccountName() {
return accountName;
}

View File

@ -125,6 +125,7 @@ import com.cloud.agent.api.PlugNicAnswer;
import com.cloud.agent.api.PlugNicCommand;
import com.cloud.agent.api.PrepareForMigrationAnswer;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.PvlanSetupCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
@ -267,6 +268,8 @@ ServerResource {
private String _createTmplPath;
private String _heartBeatPath;
private String _securityGroupPath;
private String _ovsPvlanDhcpHostPath;
private String _ovsPvlanVmPath;
private String _routerProxyPath;
private String _host;
private String _dcId;
@ -587,6 +590,18 @@ ServerResource {
"Unable to find the router_proxy.sh");
}
_ovsPvlanDhcpHostPath = Script.findScript(networkScriptsDir, "ovs-pvlan-dhcp-host.sh");
if ( _ovsPvlanDhcpHostPath == null) {
throw new ConfigurationException(
"Unable to find the ovs-pvlan-dhcp-host.sh");
}
_ovsPvlanVmPath = Script.findScript(networkScriptsDir, "ovs-pvlan-vm.sh");
if ( _ovsPvlanVmPath == null) {
throw new ConfigurationException(
"Unable to find the ovs-pvlan-vm.sh");
}
String value = (String) params.get("developer");
boolean isDeveloper = Boolean.parseBoolean(value);
@ -1202,6 +1217,8 @@ ServerResource {
return execute((CheckNetworkCommand) cmd);
} else if (cmd instanceof NetworkRulesVmSecondaryIpCommand) {
return execute((NetworkRulesVmSecondaryIpCommand) cmd);
} else if (cmd instanceof PvlanSetupCommand) {
return execute((PvlanSetupCommand) cmd);
} else {
s_logger.warn("Unsupported command ");
return Answer.createUnsupportedCommandAnswer(cmd);
@ -1517,6 +1534,65 @@ ServerResource {
}
}
private Answer execute(PvlanSetupCommand cmd) {
String primaryPvlan = cmd.getPrimary();
String isolatedPvlan = cmd.getIsolated();
String op = cmd.getOp();
String dhcpName = cmd.getDhcpName();
String dhcpMac = cmd.getDhcpMac();
String dhcpIp = cmd.getDhcpIp();
String vmMac = cmd.getVmMac();
boolean add = true;
String opr = "-A";
if (op.equals("delete")) {
opr = "-D";
add = false;
}
String result = null;
Connect conn;
try {
if (cmd.getType() == PvlanSetupCommand.Type.DHCP) {
Script script = new Script(_ovsPvlanDhcpHostPath, _timeout, s_logger);
if (add) {
conn = LibvirtConnection.getConnectionByVmName(dhcpName);
List<InterfaceDef> ifaces = getInterfaces(conn, dhcpName);
InterfaceDef guestNic = ifaces.get(0);
script.add(opr, "-b", _guestBridgeName,
"-p", primaryPvlan, "-i", isolatedPvlan, "-n", dhcpName,
"-d", dhcpIp, "-m", dhcpMac, "-I", guestNic.getDevName());
} else {
script.add(opr, "-b", _guestBridgeName,
"-p", primaryPvlan, "-i", isolatedPvlan, "-n", dhcpName,
"-d", dhcpIp, "-m", dhcpMac);
}
result = script.execute();
if (result != null) {
s_logger.warn("Failed to program pvlan for dhcp server with mac " + dhcpMac);
return new Answer(cmd, false, result);
} else {
s_logger.info("Programmed pvlan for dhcp server with mac " + dhcpMac);
}
} else if (cmd.getType() == PvlanSetupCommand.Type.VM) {
Script script = new Script(_ovsPvlanVmPath, _timeout, s_logger);
script.add(opr, "-b", _guestBridgeName,
"-p", primaryPvlan, "-i", isolatedPvlan, "-v", vmMac);
result = script.execute();
if (result != null) {
s_logger.warn("Failed to program pvlan for vm with mac " + vmMac);
return new Answer(cmd, false, result);
} else {
s_logger.info("Programmed pvlan for vm with mac " + vmMac);
}
}
} catch (LibvirtException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new Answer(cmd, true, result);
}
private void VifHotPlug(Connect conn, String vmName, String vlanId,
String macAddr) throws InternalErrorException, LibvirtException {
NicTO nicTO = new NicTO();

View File

@ -76,10 +76,12 @@ public class OvsVifDriver extends VifDriverBase {
}
else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) {
logicalSwitchUuid = nic.getBroadcastUri().getSchemeSpecificPart();
} else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) {
vlanId = NetUtils.getPrimaryPvlanFromUri(nic.getBroadcastUri());
}
String trafficLabel = nic.getName();
if (nic.getType() == Networks.TrafficType.Guest) {
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan
if ((nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan || nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan)
&& !vlanId.equalsIgnoreCase("untagged")) {
if(trafficLabel != null && !trafficLabel.isEmpty()) {
s_logger.debug("creating a vlan dev and bridge for guest traffic per traffic label " + trafficLabel);

View File

@ -83,6 +83,7 @@ import com.cloud.agent.api.PlugNicCommand;
import com.cloud.agent.api.PoolEjectCommand;
import com.cloud.agent.api.PrepareForMigrationAnswer;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.PvlanSetupCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
@ -614,6 +615,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return execute((NetworkRulesVmSecondaryIpCommand)cmd);
} else if (clazz == ScaleVmCommand.class) {
return execute((ScaleVmCommand) cmd);
} else if (clazz == PvlanSetupCommand.class) {
return execute((PvlanSetupCommand) cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
@ -1030,6 +1033,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
} else if (nic.getBroadcastType() == BroadcastDomainType.Lswitch) {
// Nicira Logical Switch
return network.getNetwork();
} else if (nic.getBroadcastType() == BroadcastDomainType.Pvlan) {
URI broadcastUri = nic.getBroadcastUri();
assert broadcastUri.getScheme().equals(BroadcastDomainType.Pvlan.scheme());
long vlan = Long.parseLong(NetUtils.getPrimaryPvlanFromUri(broadcastUri));
return enableVlanNetwork(conn, vlan, network);
}
throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri());
@ -1065,7 +1073,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
vifr = vif.getRecord(conn);
s_logger.debug("Created a vif " + vifr.uuid + " on " + nic.getDeviceId());
}
return vif;
}
@ -1476,6 +1484,55 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
}
private Answer execute(PvlanSetupCommand cmd) {
Connection conn = getConnection();
String primaryPvlan = cmd.getPrimary();
String isolatedPvlan = cmd.getIsolated();
String op = cmd.getOp();
String dhcpName = cmd.getDhcpName();
String dhcpMac = cmd.getDhcpMac();
String dhcpIp = cmd.getDhcpIp();
String vmMac = cmd.getVmMac();
String networkTag = cmd.getNetworkTag();
XsLocalNetwork nw = null;
String nwNameLabel = null;
try {
nw = getNativeNetworkForTraffic(conn, TrafficType.Guest, networkTag);
nwNameLabel = nw.getNetwork().getNameLabel(conn);
} catch (XenAPIException e) {
s_logger.warn("Fail to get network", e);
return new Answer(cmd, false, e.toString());
} catch (XmlRpcException e) {
s_logger.warn("Fail to get network", e);
return new Answer(cmd, false, e.toString());
}
String result = null;
if (cmd.getType() == PvlanSetupCommand.Type.DHCP) {
result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "nw-label", nwNameLabel,
"primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-name", dhcpName,
"dhcp-ip", dhcpIp, "dhcp-mac", dhcpMac);
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program pvlan for dhcp server with mac " + dhcpMac);
return new Answer(cmd, false, result);
} else {
s_logger.info("Programmed pvlan for dhcp server with mac " + dhcpMac);
}
} else if (cmd.getType() == PvlanSetupCommand.Type.VM) {
result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm", "op", op, "nw-label", nwNameLabel,
"primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac);
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program pvlan for vm with mac " + vmMac);
return new Answer(cmd, false, result);
} else {
s_logger.info("Programmed pvlan for vm with mac " + vmMac);
}
}
return new Answer(cmd, true, result);
}
@Override
public StartAnswer execute(StartCommand cmd) {

View File

@ -0,0 +1,27 @@
#!/bin/bash
# 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.
nw_label=$1
br=`xe network-list name-label="$nw_label" params=bridge |cut -d ':' -f 2 |tr -d ' ' `
pbr=`ovs-vsctl br-to-parent $br`
while [ "$br" != "$pbr" ]
do
br=$pbr
pbr=`ovs-vsctl br-to-parent $br`
done
echo $pbr

View File

@ -0,0 +1,25 @@
#!/bin/bash
# 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.
#!/bin/bash
bridge=$1
dhcp_name=$2
dom_id=`xe vm-list is-control-domain=false power-state=running params=dom-id name-label=$dhcp_name|cut -d ':' -f 2 |tr -d ' ' `
iface="vif${dom_id}.0"
echo $iface

View File

@ -0,0 +1,145 @@
#!/usr/bin/python
# 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.
import cloudstack_pluginlib as lib
import logging
import os
import sys
import subprocess
import time
import XenAPIPlugin
sys.path.append("/opt/xensource/sm/")
import util
from time import localtime as _localtime, asctime as _asctime
xePath = "/opt/xensource/bin/xe"
lib.setup_logging("/var/log/ovs-pvlan.log")
dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh"
vmSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh"
getDhcpIfacePath = "/opt/xensource/bin/ovs-get-dhcp-iface.sh"
pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh"
getBridgePath = "/opt/xensource/bin/ovs-get-bridge.sh"
def echo(fn):
def wrapped(*v, **k):
name = fn.__name__
util.SMlog("#### VMOPS enter %s ####" % name)
res = fn(*v, **k)
util.SMlog("#### VMOPS exit %s ####" % name)
return res
return wrapped
@echo
def setup_pvlan_dhcp(session, args):
op = args.pop("op")
nw_label = args.pop("nw-label")
primary = args.pop("primary-pvlan")
isolated = args.pop("isolated-pvlan")
dhcp_name = args.pop("dhcp-name")
dhcp_ip = args.pop("dhcp-ip")
dhcp_mac = args.pop("dhcp-mac")
res = lib.check_switch()
if res != "SUCCESS":
return "FAILURE:%s" % res
logging.debug("Network is:%s" % (nw_label))
bridge = lib.do_cmd([getBridgePath, nw_label])
logging.debug("Determine bridge/switch is :%s" % (bridge))
if op == "add":
logging.debug("Try to get dhcp vm %s port on the switch:%s" % (dhcp_name, bridge))
dhcp_iface = lib.do_cmd([getDhcpIfacePath, bridge, dhcp_name])
logging.debug("About to setup dhcp vm on the switch:%s" % bridge)
res = lib.do_cmd([dhcpSetupPath, "-A", "-b", bridge, "-p", primary,
"-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac,
"-I", dhcp_iface])
if res:
result = "FAILURE:%s" % res
return result;
logging.debug("Setup dhcp vm on switch program done")
elif op == "delete":
logging.debug("About to remove dhcp the switch:%s" % bridge)
res = lib.do_cmd([dhcpSetupPath, "-D", "-b", bridge, "-p", primary,
"-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac])
if res:
result = "FAILURE:%s" % res
return result;
logging.debug("Remove DHCP on switch program done")
result = "true"
logging.debug("Setup_pvlan_dhcp completed with result:%s" % result)
return result
@echo
def setup_pvlan_vm(session, args):
op = args.pop("op")
nw_label = args.pop("nw-label")
primary = args.pop("primary-pvlan")
isolated = args.pop("isolated-pvlan")
vm_mac = args.pop("vm-mac")
trunk_port = 1
res = lib.check_switch()
if res != "SUCCESS":
return "FAILURE:%s" % res
bridge = lib.do_cmd([getBridgePath, nw_label])
logging.debug("Determine bridge/switch is :%s" % (bridge))
if op == "add":
logging.debug("About to setup vm on the switch:%s" % bridge)
res = lib.do_cmd([vmSetupPath, "-A", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac])
if res:
result = "FAILURE:%s" % res
return result;
logging.debug("Setup vm on switch program done")
elif op == "delete":
logging.debug("About to remove vm on the switch:%s" % bridge)
res = lib.do_cmd([vmSetupPath, "-D", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac])
if res:
result = "FAILURE:%s" % res
return result;
logging.debug("Remove vm on switch program done")
result = "true"
logging.debug("Setup_pvlan_vm_alone completed with result:%s" % result)
return result
@echo
def cleanup(session, args):
res = lib.check_switch()
if res != "SUCCESS":
return "FAILURE:%s" % res
res = lib.do_cmd([pvlanCleanUpPath])
if res:
result = "FAILURE:%s" % res
return result;
result = "true"
logging.debug("Setup_pvlan_vm_dhcp completed with result:%s" % result)
return result
if __name__ == "__main__":
XenAPIPlugin.dispatch({"setup-pvlan-dhcp": setup_pvlan_dhcp,
"setup-pvlan-vm": setup_pvlan_vm,
"cleanup":cleanup})

View File

@ -70,4 +70,9 @@ swift=..,0755,/opt/xensource/bin
swiftxen=..,0755,/etc/xapi.d/plugins
s3xen=..,0755,/etc/xapi.d/plugins
add_to_vcpus_params_live.sh=..,0755,/opt/xensource/bin
ovs-pvlan=..,0755,/etc/xapi.d/plugins
ovs-pvlan-dhcp-host.sh=../../../network,0755,/opt/xensource/bin
ovs-pvlan-vm.sh=../../../network,0755,/opt/xensource/bin
ovs-pvlan-cleanup.sh=../../../network,0755,/opt/xensource/bin
ovs-get-dhcp-iface.sh=..,0755,/opt/xensource/bin
ovs-get-bridge.sh=..,0755,/opt/xensource/bin

View File

@ -0,0 +1,23 @@
#!/bin/bash
# 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.
#!/bin/bash
ovs-ofctl del-flows xenbr0
ovs-ofctl add-flow xenbr0 priority=0,actions=NORMAL

View File

@ -0,0 +1,123 @@
#!/bin/bash
# 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.
#!/bin/bash
usage() {
printf "Usage: %s: (-A|-D) -b <bridge/switch> -p <primary vlan> -i <secondary isolated vlan> -n <DHCP server name> -d <DHCP server IP> -m <DHCP server MAC> -I <interface> -v <VM MAC> -h \n" $(basename $0) >&2
exit 2
}
br=
pri_vlan=
sec_iso_vlan=
dhcp_name=
dhcp_ip=
dhcp_mac=
vm_mac=
iface=
op=
while getopts 'ADb:p:i:d:m:v:n:I:h' OPTION
do
case $OPTION in
A) op="add"
;;
D) op="del"
;;
b) br="$OPTARG"
;;
p) pri_vlan="$OPTARG"
;;
i) sec_iso_vlan="$OPTARG"
;;
n) dhcp_name="$OPTARG"
;;
d) dhcp_ip="$OPTARG"
;;
m) dhcp_mac="$OPTARG"
;;
I) iface="$OPTARG"
;;
v) vm_mac="$OPTARG"
;;
h) usage
exit 1
;;
esac
done
if [ -z "$op" ]
then
echo Missing operation pararmeter!
exit 1
fi
if [ -z "$br" ]
then
echo Missing parameter bridge!
exit 1
fi
if [ -z "$pri_vlan" ]
then
echo Missing parameter primary vlan!
exit 1
fi
if [ -z "$sec_iso_vlan" ]
then
echo Missing parameter secondary isolate vlan!
exit 1
fi
if [ -z "$dhcp_name" ]
then
echo Missing parameter DHCP NAME!
exit 1
fi
if [ -z "$dhcp_ip" ]
then
echo Missing parameter DHCP IP!
exit 1
fi
if [ -z "$dhcp_mac" ]
then
echo Missing parameter DHCP MAC!
exit 1
fi
if [ "$op" == "add" -a -z "$iface" ]
then
echo Missing parameter DHCP VM interface!
exit 1
fi
if [ "$op" == "add" ]
then
dhcp_port=`ovs-ofctl show $br | grep $iface | cut -d '(' -f 1|tr -d ' '`
ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port
ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=strip_vlan,output:$dhcp_port
ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=strip_vlan,output:$dhcp_port
else
ovs-ofctl del-flows --strict $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip
ovs-ofctl del-flows --strict $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac
ovs-ofctl del-flows --strict $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67
fi

View File

@ -0,0 +1,99 @@
#!/bin/bash
# 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.
#!/bin/bash
usage() {
printf "Usage: %s: (-A|-D) -b <bridge/switch> -p <primary vlan> -i <secondary isolated vlan> -d <DHCP server IP> -m <DHCP server MAC> -v <VM MAC> -h \n" $(basename $0) >&2
exit 2
}
br=
pri_vlan=
sec_iso_vlan=
dhcp_ip=
dhcp_mac=
vm_mac=
op=
while getopts 'ADb:p:i:d:m:v:h' OPTION
do
case $OPTION in
A) op="add"
;;
D) op="del"
;;
b) br="$OPTARG"
;;
p) pri_vlan="$OPTARG"
;;
i) sec_iso_vlan="$OPTARG"
;;
d) dhcp_ip="$OPTARG"
;;
m) dhcp_mac="$OPTARG"
;;
v) vm_mac="$OPTARG"
;;
h) usage
exit 1
;;
esac
done
if [ -z "$op" ]
then
echo Missing operation pararmeter!
exit 1
fi
if [ -z "$br" ]
then
echo Missing parameter bridge!
exit 1
fi
if [ -z "$vm_mac" ]
then
echo Missing parameter VM MAC!
exit 1
fi
if [ -z "$pri_vlan" ]
then
echo Missing parameter secondary isolate vlan!
exit 1
fi
if [ -z "$sec_iso_vlan" ]
then
echo Missing parameter secondary isolate vlan!
exit 1
fi
trunk_port=1
if [ "$op" == "add" ]
then
ovs-ofctl add-flow $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,resubmit:$trunk_port
ovs-ofctl add-flow $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac,actions=output:$trunk_port
else
ovs-ofctl del-flows --strict $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac
ovs-ofctl del-flows --strict $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac
fi

View File

@ -2657,6 +2657,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
if (uri != null) {
String[] vlan = uri.toString().split("vlan:\\/\\/");
networkVlanId = vlan[1];
//For pvlan
networkVlanId = networkVlanId.split("-")[0];
}
if (vlanId != null) {

View File

@ -130,7 +130,8 @@ public interface NetworkManager {
Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr,
String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork,
long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, Boolean displayNetworkEnabled)
long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
Boolean displayNetworkEnabled, String isolatedPvlan)
throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
/**

View File

@ -1900,7 +1900,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
@DB
public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway,
String cidr, String vlanId, String networkDomain, Account owner, Long domainId,
PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, Boolean isDisplayNetworkEnabled)
PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
Boolean isDisplayNetworkEnabled, String isolatedPvlan)
throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
@ -1990,6 +1991,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
if (ipv6) {
throw new InvalidParameterValueException("IPv6 is not supported with security group!");
}
if (isolatedPvlan != null) {
throw new InvalidParameterValueException("Isolated Private VLAN is not supported with security group!");
}
// Only Account specific Isolated network with sourceNat service disabled are allowed in security group
// enabled zone
if ( ntwkOff.getGuestType() != GuestType.Shared ){
@ -2149,13 +2153,20 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
}
if (vlanId != null) {
userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId));
userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) {
userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
} else {
userNetwork.setBroadcastDomainType(BroadcastDomainType.Native);
}
if (isolatedPvlan == null) {
userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId));
if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) {
userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
} else {
userNetwork.setBroadcastDomainType(BroadcastDomainType.Native);
}
} else {
if (vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) {
throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!");
}
userNetwork.setBroadcastUri(NetUtils.generateUriForPvlan(vlanId, isolatedPvlan));
userNetwork.setBroadcastDomainType(BroadcastDomainType.Pvlan);
}
}
List<NetworkVO> networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId,
@ -2758,7 +2769,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
guestNetwork = createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network"
, owner.getAccountName() + "-network", null, null, null, null, owner, null, physicalNetwork,
zoneId, ACLType.Account,
null, null, null, null, true);
null, null, null, null, true, null);
if (guestNetwork == null) {
s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId);
throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " +
@ -3634,8 +3645,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
nic.setGateway(ip.getGateway());
nic.setNetmask(ip.getNetmask());
nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag()));
nic.setBroadcastType(BroadcastDomainType.Vlan);
nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag()));
//nic.setBroadcastType(BroadcastDomainType.Vlan);
//nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag()));
nic.setBroadcastType(network.getBroadcastDomainType());
nic.setBroadcastUri(network.getBroadcastUri());
nic.setFormat(AddressFormat.Ip4);
nic.setReservationId(String.valueOf(ip.getVlanTag()));
nic.setMacAddress(ip.getMacAddress());

View File

@ -952,6 +952,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
String ip6Cidr = cmd.getIp6Cidr();
Boolean displayNetwork = cmd.getDisplayNetwork();
Long aclId = cmd.getAclId();
String isolatedPvlan = cmd.getIsolatedPvlan();
// Validate network offering
NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
@ -1143,6 +1144,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
}
}
if (isolatedPvlan != null && (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared)) {
throw new InvalidParameterValueException("Can only support create Private VLAN network with advance shared network!");
}
if (isolatedPvlan != null && ipv6) {
throw new InvalidParameterValueException("Can only support create Private VLAN network with IPv4!");
}
// Regular user can create Guest Isolated Source Nat enabled network only
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL
&& (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated
@ -1175,6 +1184,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
throw new InvalidParameterValueException("Cannot support IPv6 on network offering with external devices!");
}
if (isolatedPvlan != null && providersConfiguredForExternalNetworking(ntwkProviders)) {
throw new InvalidParameterValueException("Cannot support private vlan on network offering with external devices!");
}
if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) {
if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) &&
isSharedNetworkOfferingWithServices(networkOfferingId)) {
@ -1265,8 +1278,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
throw new InvalidParameterValueException("Internal Lb can be enabled on vpc networks only");
}
network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, displayNetwork);
network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId,
ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan);
}
if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) {
@ -3813,8 +3827,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
if (privateNetwork == null) {
//create Guest network
privateNetwork = _networkMgr.createGuestNetwork(ntwkOff.getId(), networkName, displayText, gateway, cidr, vlan,
null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, vpcId, null, null, true);
null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, vpcId, null, null, true, null);
s_logger.debug("Created private network " + privateNetwork);
} else {
s_logger.debug("Private network already exists: " + privateNetwork);

View File

@ -30,6 +30,7 @@ import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElement
import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd;
import org.apache.log4j.Logger;
import com.cloud.agent.api.PvlanSetupCommand;
import com.cloud.agent.api.to.LoadBalancerTO;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.dao.ConfigurationDao;
@ -47,6 +48,7 @@ import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.NetworkModel;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PhysicalNetworkServiceProvider;
import com.cloud.network.PublicIpAddress;
@ -228,7 +230,6 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl
throw new ResourceUnavailableException("Can't find at least one running router!",
DataCenter.class, network.getDataCenterId());
}
return true;
}

View File

@ -33,6 +33,7 @@ import com.cloud.user.User;
import com.cloud.uservm.UserVm;
import com.cloud.utils.component.Manager;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.VirtualMachineProfile;
@ -112,4 +113,4 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA
boolean removeDhcpSupportForSubnet(Network network, List<DomainRouterVO> routers) throws ResourceUnavailableException;
}
}

View File

@ -34,6 +34,7 @@ import com.cloud.agent.api.GetDomRVersionCmd;
import com.cloud.agent.api.ModifySshKeysCommand;
import com.cloud.agent.api.NetworkUsageAnswer;
import com.cloud.agent.api.NetworkUsageCommand;
import com.cloud.agent.api.PvlanSetupCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.check.CheckSshAnswer;
@ -2222,6 +2223,28 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
return dhcpRange;
}
private boolean setupDhcpForPvlan(boolean add, DomainRouterVO router, Nic nic) {
if (!nic.getBroadcastUri().getScheme().equals("pvlan")) {
return false;
}
String op = "add";
if (!add) {
op = "delete";
}
Network network = _networkDao.findById(nic.getNetworkId());
String networkTag = _networkModel.getNetworkTag(router.getHypervisorType(), network);
PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, nic.getBroadcastUri(), networkTag, router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address());
Commands cmds = new Commands(cmd);
// In fact we send command to the host of router, we're not programming router but the host
try {
sendCommandsToRouter(router, cmds);
} catch (AgentUnavailableException e) {
s_logger.warn("Agent Unavailable ", e);
return false;
}
return true;
}
@Override
public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile,
DeployDestination dest, ReservationContext context) throws ResourceUnavailableException {
@ -2535,13 +2558,20 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
List<Network> guestNetworks = new ArrayList<Network>();
List<? extends Nic> routerNics = _nicDao.listByVmId(profile.getId());
for (Nic routerNic : routerNics) {
Network network = _networkModel.getNetwork(routerNic.getNetworkId());
for (Nic nic : routerNics) {
Network network = _networkModel.getNetwork(nic.getNetworkId());
if (network.getTrafficType() == TrafficType.Guest) {
guestNetworks.add(network);
if (nic.getBroadcastUri().getScheme().equals("pvlan")) {
result = setupDhcpForPvlan(true, router, nic);
}
}
}
if (!result) {
return result;
}
answer = cmds.getAnswer("getDomRVersion");
if (answer != null && answer instanceof GetDomRVersionAnswer) {
GetDomRVersionAnswer versionAnswer = (GetDomRVersionAnswer)answer;
@ -2567,6 +2597,14 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
VMInstanceVO vm = profile.getVirtualMachine();
DomainRouterVO domR = _routerDao.findById(vm.getId());
processStopOrRebootAnswer(domR, answer);
List<? extends Nic> routerNics = _nicDao.listByVmId(profile.getId());
for (Nic nic : routerNics) {
Network network = _networkModel.getNetwork(nic.getNetworkId());
if (network.getTrafficType() == TrafficType.Guest && nic.getBroadcastUri().getScheme().equals("pvlan")) {
setupDhcpForPvlan(false, domR, nic);
}
}
}
}

View File

@ -2025,8 +2025,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
//2) Create network
Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null, isDisplayNetworkEnabled);
networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null, isDisplayNetworkEnabled, null);
if(guestNetwork != null){
guestNetwork.setNetworkACLId(aclId);

View File

@ -69,6 +69,7 @@ import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.PlugNicAnswer;
import com.cloud.agent.api.PlugNicCommand;
import com.cloud.agent.api.PvlanSetupCommand;
import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.UnPlugNicAnswer;
@ -2191,7 +2192,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
s_logger.debug("Creating network for account " + owner + " from the network offering id=" +requiredOfferings.get(0).getId() + " as a part of deployVM process");
Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(),
owner.getAccountName() + "-network", owner.getAccountName() + "-network", null, null,
null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true);
null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true, null);
defaultNetwork = _networkDao.findById(newNetwork.getId());
} else if (virtualNetworks.size() > 1) {
throw new InvalidParameterValueException(
@ -2788,6 +2789,37 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
return true;
}
private boolean setupVmForPvlan(boolean add, Long hostId, NicVO nic) {
if (!nic.getBroadcastUri().getScheme().equals("pvlan")) {
return false;
}
String op = "add";
if (!add) {
// "delete" would remove all the rules(if using ovs) related to this vm
op = "delete";
}
Network network = _networkDao.findById(nic.getNetworkId());
Host host = _hostDao.findById(hostId);
String networkTag = _networkModel.getNetworkTag(host.getHypervisorType(), network);
PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadcastUri(), networkTag, nic.getMacAddress());
Answer answer = null;
try {
answer = _agentMgr.send(hostId, cmd);
} catch (OperationTimedoutException e) {
s_logger.warn("Timed Out", e);
return false;
} catch (AgentUnavailableException e) {
s_logger.warn("Agent Unavailable ", e);
return false;
}
boolean result = true;
if (answer == null || !answer.getResult()) {
result = false;
}
return result;
}
@Override
public boolean finalizeDeployment(Commands cmds,
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest,
@ -2849,6 +2881,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
originalIp = nic.getIp4Address();
guestNic = nic;
guestNetwork = network;
if (nic.getBroadcastUri().getScheme().equals("pvlan")) {
if (!setupVmForPvlan(true, hostId, nic)) {
return false;
}
}
}
}
boolean ipChanged = false;
@ -2979,6 +3016,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
+ " stop due to exception ", ex);
}
}
VMInstanceVO vm = profile.getVirtualMachine();
List<NicVO> nics = _nicDao.listByVmId(vm.getId());
for (NicVO nic : nics) {
NetworkVO network = _networkDao.findById(nic.getNetworkId());
if (network.getTrafficType() == TrafficType.Guest) {
if (nic.getBroadcastUri().getScheme().equals("pvlan")) {
setupVmForPvlan(false, vm.getHostId(), nic);
}
}
}
}
public String generateRandomPassword() {
@ -4038,7 +4086,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
requiredOfferings.get(0).getId() + " as a part of deployVM process");
Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(),
newAccount.getAccountName() + "-network", newAccount.getAccountName() + "-network", null, null,
null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true);
null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true, null);
// if the network offering has persistent set to true, implement the network
if (requiredOfferings.get(0).getIsPersistent()) {
DeployDestination dest = new DeployDestination(zone, null, null, null);

View File

@ -272,7 +272,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
@Override
public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId,
PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6, Boolean displayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6, Boolean displayNetworkEnabled, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
// TODO Auto-generated method stub
return null;
}

View File

@ -868,7 +868,8 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
@Override
public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway,
String cidr, String vlanId, String networkDomain, Account owner, Long domainId,
PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6, Boolean displayNetworkEnabled)
PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6,
Boolean displayNetworkEnabled, String isolatedPvlan)
throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
// TODO Auto-generated method stub
return null;

View File

@ -0,0 +1,86 @@
# 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.
""" test for private vlan isolation
"""
#Import Local Modules
import marvin
from marvin.cloudstackTestCase import *
from marvin.cloudstackAPI import *
from marvin import remoteSSHClient
from marvin.integration.lib.utils import *
from marvin.integration.lib.base import *
from marvin.integration.lib.common import *
from nose.plugins.attrib import attr
import telnetlib
#Import System modules
import time
_multiprocess_shared_ = True
class TestPVLAN(cloudstackTestCase):
zoneId = 1
networkOfferingId = 7
vlan = 1234
isolatedpvlan = 567
def setUp(self):
self.apiClient = self.testClient.getApiClient()
def test_create_pvlan_network(self):
self.debug("Test create pvlan network")
createNetworkCmd = createNetwork.createNetworkCmd()
createNetworkCmd.name = "pvlan network"
createNetworkCmd.displaytext = "pvlan network"
createNetworkCmd.netmask = "255.255.255.0"
createNetworkCmd.gateway = "10.10.10.1"
createNetworkCmd.startip = "10.10.10.10"
createNetworkCmd.gateway = "10.10.10.20"
createNetworkCmd.vlan = "1234"
createNetworkCmd.isolatedpvlan = "567"
createNetworkCmd.zoneid = self.zoneId
createNetworkCmd.networkofferingid = self.networkOfferingId
createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd)
self.networkId = createNetworkResponse.id
self.broadcasttype = createNetworkResponse.broadcastdomaintype
self.broadcasturi = createNetworkResponse.broadcasturi
self.assertIsNotNone(createNetworkResponse.id, "Network failed to create")
self.assertTrue(createNetworkResponse.broadcastdomaintype, "Pvlan")
self.assertTrue(createNetworkResponse.broadcasturi, "pvlan://1234-i567")
self.debug("Clean up test pvlan network")
deleteNetworkCmd = deleteNetwork.deleteNetworkCmd()
deleteNetworkCmd.id = self.networkId;
self.apiClient.deleteNetwork(deleteNetworkCmd)
#Test invalid parameter
# CLOUDSTACK-2392: Should not allow create pvlan with ipv6
createNetworkCmd.ip6gateway="fc00:1234::1"
createNetworkCmd.ip6cidr="fc00:1234::/64"
createNetworkCmd.startipv6="fc00:1234::10"
createNetworkCmd.endipv6="fc00:1234::20"
err = 0;
try:
createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd)
except Exception as e:
err = 1;
self.debug("Try alloc with ipv6, got:%s" % e)
self.assertEqual(err, 1, "Shouldn't allow create PVLAN network with IPv6");

View File

@ -1300,6 +1300,7 @@
name: { label: 'label.name' },
type: { label: 'label.type' },
vlan: { label: 'label.vlan.id' },
broadcasturi: { label: 'broadcast URI' },
cidr: { label: 'IPv4 CIDR' },
ip6cidr: { label: 'IPv6 CIDR'}
//scope: { label: 'label.scope' }
@ -1335,7 +1336,10 @@
label: 'label.vlan.id',
docID: 'helpGuestNetworkZoneVLANID'
},
isolatedpvlanId: {
label: 'Private VLAN ID'
},
scope: {
label: 'label.scope',
docID: 'helpGuestNetworkZoneScope',
@ -1549,11 +1553,15 @@
if(this.id == selectedNetworkOfferingId) {
if(this.specifyvlan == false) {
$form.find('.form-item[rel=vlanId]').hide();
cloudStack.dialog.createFormField.validation.required.remove($form.find('.form-item[rel=vlanId]')); //make vlanId optional
cloudStack.dialog.createFormField.validation.required.remove($form.find('.form-item[rel=vlanId]')); //make vlanId optional
$form.find('.form-item[rel=isolatedpvlanId]').hide();
}
else {
$form.find('.form-item[rel=vlanId]').css('display', 'inline-block');
cloudStack.dialog.createFormField.validation.required.add($form.find('.form-item[rel=vlanId]')); //make vlanId required
cloudStack.dialog.createFormField.validation.required.add($form.find('.form-item[rel=vlanId]')); //make vlanId required
$form.find('.form-item[rel=isolatedpvlanId]').css('display', 'inline-block');
}
return false; //break each loop
}
@ -1639,7 +1647,10 @@
if(($form.find('.form-item[rel=vlanId]').css("display") != "none") && (args.data.vlanId != null && args.data.vlanId.length > 0))
array1.push("&vlan=" + todb(args.data.vlanId));
if(($form.find('.form-item[rel=isolatedpvlanId]').css("display") != "none") && (args.data.isolatedpvlanId != null && args.data.isolatedpvlanId.length > 0))
array1.push("&isolatedpvlan=" + todb(args.data.isolatedpvlanId));
if($form.find('.form-item[rel=domainId]').css("display") != "none") {
array1.push("&domainId=" + args.data.domainId);
@ -2007,6 +2018,7 @@
}
},
vlan: { label: 'label.vlan.id' },
broadcasturi: { label: 'broadcast URI' },
scope: { label: 'label.scope' },
networkofferingdisplaytext: { label: 'label.network.offering' },
networkofferingid: {

View File

@ -24,6 +24,7 @@ import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Formatter;
@ -1294,4 +1295,29 @@ public class NetUtils {
}
return resultIp;
}
public static URI generateUriForPvlan(String primaryVlan, String isolatedPvlan) {
return URI.create("pvlan://" + primaryVlan + "-i" + isolatedPvlan);
}
public static String getPrimaryPvlanFromUri(URI uri) {
String[] vlans = uri.getHost().split("-");
if (vlans.length < 1) {
return null;
}
return vlans[0];
}
public static String getIsolatedPvlanFromUri(URI uri) {
String[] vlans = uri.getHost().split("-");
if (vlans.length < 2) {
return null;
}
for (String vlan : vlans) {
if (vlan.startsWith("i")) {
return vlan.replace("i", " ").trim();
}
}
return null;
}
}

View File

@ -17,6 +17,7 @@
package com.cloud.utils.net;
import java.math.BigInteger;
import java.net.URI;
import java.util.SortedSet;
import java.util.TreeSet;
@ -128,4 +129,11 @@ public class NetUtilsTest extends TestCase {
assertFalse(NetUtils.isIp6InRange("1234:5678:abcd::1", null));
assertTrue(NetUtils.isIp6InRange("1234:5678:abcd::1", "1234:5678::1-1234:5679::1"));
}
public void testPvlan() {
URI uri = NetUtils.generateUriForPvlan("123", "456");
assertTrue(uri.toString().equals("pvlan://123-i456"));
assertTrue(NetUtils.getPrimaryPvlanFromUri(uri).equals("123"));
assertTrue(NetUtils.getIsolatedPvlanFromUri(uri).equals("456"));
}
}