CLOUDSTACK-2328: Linux native VXLAN support on KVM hypervisor

Initial patch for VXLAN support.
Fully functional, hopefully, for GuestNetwork - AdvancedZone.

Patch Note:
 in cloudstack-server
- Add isolation method VXLAN
- Add VxlanGuestNetworkGuru as plugin for VXLAN isolation
- Modify NetworkServiceImpl to handle extended vNet range for VXLAN isolation
- Add VXLAN isolation option in zoneWizard UI

 in cloudstack-agent (kvm)
- Add modifyvxlan.sh script that handle bridge/vxlan interface manipulation script
-- Usage is exactly same to modifyvlan.sh
- BridgeVifDriver will call modifyvxlan.sh instead of modifyvlan.sh when VXLAN is used for isolation

Database changes:
- No change in database structure.
- VXLAN isolation uses same tables that VLAN uses to store vNet allocation status.

Known Issue:
- Some resource still says 'VLAN' in log even if VXLAN is used
- in UI, "Network - GuestNetworks" dosen't display VNI
-- VLAN ID field displays "N/A"
This commit is contained in:
Toshiaki Hatano 2013-08-21 02:48:15 +00:00
parent c6e569755f
commit 34ae32e0c2
15 changed files with 812 additions and 57 deletions

View File

@ -108,6 +108,7 @@ public class Networks {
},
Mido("mido", String.class),
Pvlan("pvlan", String.class),
Vxlan("vxlan", Long.class),
UnDecided(null, null);
private final String scheme;

View File

@ -39,7 +39,8 @@ public interface PhysicalNetwork extends Identity, InternalIdentity {
STT,
VNS,
MIDO,
SSP;
SSP,
VXLAN;
}
public enum BroadcastDomainRange {

View File

@ -104,6 +104,11 @@
<artifactId>cloud-plugin-network-internallb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-network-vxlan</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-hypervisor-xen</artifactId>

View File

@ -91,6 +91,13 @@
<bean id="ucsBladeDaoImpl" class="com.cloud.ucs.database.UcsBladeDaoImpl" />
<bean id="ucsManagerDaoImpl" class="com.cloud.ucs.database.UcsManagerDaoImpl" />
<!--
VXLAN support components
-->
<bean id="VxlanGuestNetworkGuru" class="com.cloud.network.guru.VxlanGuestNetworkGuru">
<property name="name" value="VxlanGuestNetworkGuru"/>
</bean>
<!--
Deployment configurations of various adapters
@ -265,6 +272,7 @@
<ref bean="NiciraNvpGuestNetworkGuru"/>
<ref bean="MidoNetGuestNetworkGuru"/>
<ref bean="SspGuestNetworkGuru"/>
<ref bean="VxlanGuestNetworkGuru"/>
</list>
</property>
</bean>

View File

@ -45,6 +45,8 @@ public class BridgeVifDriver extends VifDriverBase {
private static final Object _vnetBridgeMonitor = new Object();
private String _modifyVlanPath;
private String _modifyVxlanPath;
@Override
public void configure(Map<String, Object> params) throws ConfigurationException {
@ -67,6 +69,10 @@ public class BridgeVifDriver extends VifDriverBase {
if (_modifyVlanPath == null) {
throw new ConfigurationException("Unable to find modifyvlan.sh");
}
_modifyVxlanPath = Script.findScript(networkScriptsDir, "modifyvxlan.sh");
if (_modifyVxlanPath == null) {
throw new ConfigurationException("Unable to find modifyvxlan.sh");
}
try {
createControlNetwork();
@ -85,10 +91,16 @@ public class BridgeVifDriver extends VifDriverBase {
LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef();
String vlanId = null;
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan) {
String vNetId = null;
String protocol = null;
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan || nic.getBroadcastType() == Networks.BroadcastDomainType.Vxlan) {
URI broadcastUri = nic.getBroadcastUri();
vlanId = broadcastUri.getHost();
if(broadcastUri.isOpaque()) {
vNetId = broadcastUri.getSchemeSpecificPart();
} else {
vNetId = broadcastUri.getHost();
}
protocol = nic.getBroadcastType().scheme();
}
else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) {
throw new InternalErrorException("Nicira NVP Logicalswitches are not supported by the BridgeVifDriver");
@ -96,14 +108,14 @@ public class BridgeVifDriver extends VifDriverBase {
String trafficLabel = nic.getName();
if (nic.getType() == Networks.TrafficType.Guest) {
Integer networkRateKBps = (nic.getNetworkRateMbps() != null && nic.getNetworkRateMbps().intValue() != -1)? nic.getNetworkRateMbps().intValue() * 128: 0;
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan
&& !vlanId.equalsIgnoreCase("untagged")) {
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan && !vNetId.equalsIgnoreCase("untagged")
|| nic.getBroadcastType() == Networks.BroadcastDomainType.Vxlan) {
if(trafficLabel != null && !trafficLabel.isEmpty()) {
s_logger.debug("creating a vlan dev and bridge for guest traffic per traffic label " + trafficLabel);
String brName = createVlanBr(vlanId, _pifs.get(trafficLabel));
s_logger.debug("creating a vNet dev and bridge for guest traffic per traffic label " + trafficLabel);
String brName = createVnetBr(vNetId, _pifs.get(trafficLabel), protocol);
intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps);
} else {
String brName = createVlanBr(vlanId, _pifs.get("private"));
String brName = createVnetBr(vNetId, _pifs.get("private"), protocol);
intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps);
}
} else {
@ -116,13 +128,13 @@ public class BridgeVifDriver extends VifDriverBase {
} else if (nic.getType() == Networks.TrafficType.Public) {
Integer networkRateKBps = (nic.getNetworkRateMbps() != null && nic.getNetworkRateMbps().intValue() != -1)? nic.getNetworkRateMbps().intValue() * 128: 0;
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan
&& !vlanId.equalsIgnoreCase("untagged")) {
&& !vNetId.equalsIgnoreCase("untagged")) {
if(trafficLabel != null && !trafficLabel.isEmpty()){
s_logger.debug("creating a vlan dev and bridge for public traffic per traffic label " + trafficLabel);
String brName = createVlanBr(vlanId, _pifs.get(trafficLabel));
s_logger.debug("creating a vNet dev and bridge for public traffic per traffic label " + trafficLabel);
String brName = createVnetBr(vNetId, _pifs.get(trafficLabel), protocol);
intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps);
} else {
String brName = createVlanBr(vlanId, _pifs.get("public"));
String brName = createVnetBr(vNetId, _pifs.get("public"), protocol);
intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps);
}
} else {
@ -149,24 +161,29 @@ public class BridgeVifDriver extends VifDriverBase {
String cmdout = Script.runSimpleBashScript("brctl show | grep " + oldStyleBrName);
if (cmdout != null && cmdout.contains(oldStyleBrName)) {
s_logger.info("Using old style bridge name for vlan " + vnetId + " because existing bridge " + oldStyleBrName + " was found");
s_logger.info("Using old style bridge name for vNet " + vnetId + " because existing bridge " + oldStyleBrName + " was found");
brName = oldStyleBrName;
}
return brName;
}
private String createVlanBr(String vlanId, String nic)
private String createVnetBr(String vNetId, String nic, String protocol)
throws InternalErrorException {
String brName = setVnetBrName(nic, vlanId);
createVnet(vlanId, nic, brName);
String brName = setVnetBrName(nic, vNetId);
createVnet(vNetId, nic, brName, protocol);
return brName;
}
private void createVnet(String vnetId, String pif, String brName)
private void createVnet(String vnetId, String pif, String brName, String protocol)
throws InternalErrorException {
synchronized (_vnetBridgeMonitor) {
final Script command = new Script(_modifyVlanPath, _timeout, s_logger);
String script = _modifyVlanPath;
if(protocol.equals(Networks.BroadcastDomainType.Vxlan.scheme())) {
script = _modifyVxlanPath;
}
final Script command = new Script(script, _timeout, s_logger);
command.add("-v", vnetId);
command.add("-p", pif);
command.add("-b", brName);
@ -182,7 +199,7 @@ public class BridgeVifDriver extends VifDriverBase {
private void deleteVnetBr(String brName){
synchronized (_vnetBridgeMonitor) {
String cmdout = Script.runSimpleBashScript("ls /sys/class/net/" + brName + "/brif | grep vnet");
String cmdout = Script.runSimpleBashScript("ls /sys/class/net/" + brName + "/brif | tr '\n' ' '");
if (cmdout != null && cmdout.contains("vnet")) {
// Active VM remains on that bridge
return;
@ -213,7 +230,12 @@ public class BridgeVifDriver extends VifDriverBase {
return;
}
final Script command = new Script(_modifyVlanPath, _timeout, s_logger);
String script = _modifyVlanPath;
if (cmdout != null && cmdout.contains("vxlan")) {
script = _modifyVxlanPath;
}
final Script command = new Script(script, _timeout, s_logger);
command.add("-o", "delete");
command.add("-v", vNetId);
command.add("-p", pName);

View File

@ -1028,7 +1028,7 @@ ServerResource {
if (! f.isDirectory()){
s_logger.debug("failing to get physical interface from bridge "
+ bridgeName + ", does " + f.getAbsolutePath()
+ "exist?");
+ " exist?");
return "";
}
@ -1050,7 +1050,6 @@ ServerResource {
return "";
}
private boolean checkNetwork(String networkName) {
if (networkName == null) {
return true;
@ -1655,7 +1654,7 @@ ServerResource {
return pifparts[1];
} else {
s_logger.debug("failed to get vlan id from bridge " + brName
+ "attached to physical interface" + pif);
+ " attached to physical interface " + pif);
return "";
}
}
@ -3031,7 +3030,6 @@ ServerResource {
getUsage.add("-d", vif);
}
final OutputInterpreter.OneLineParser usageParser = new OutputInterpreter.OneLineParser();
String result = getUsage.execute(usageParser);
if (result != null) {

View File

@ -66,8 +66,12 @@ public class OvsVifDriver extends VifDriverBase {
String logicalSwitchUuid = null;
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan) {
URI broadcastUri = nic.getBroadcastUri();
if(broadcastUri.isOpaque()) {
vlanId = broadcastUri.getSchemeSpecificPart();
} else {
vlanId = broadcastUri.getHost();
}
}
else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) {
logicalSwitchUuid = nic.getBroadcastUri().getSchemeSpecificPart();
} else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) {

View File

@ -0,0 +1,29 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-network-vxlan</artifactId>
<name>Apache CloudStack Plugin - Network VXLAN</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>

View File

@ -0,0 +1,180 @@
// 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.network.guru;
import javax.ejb.Local;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes;
import com.cloud.event.EventVO;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
import com.cloud.network.Network;
import com.cloud.network.NetworkProfile;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.State;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.PhysicalNetwork;
import com.cloud.network.PhysicalNetwork.IsolationMethod;
import com.cloud.network.dao.NetworkVO;
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Component
@Local(value=NetworkGuru.class)
public class VxlanGuestNetworkGuru extends GuestNetworkGuru {
private static final Logger s_logger = Logger.getLogger(VxlanGuestNetworkGuru.class);
public VxlanGuestNetworkGuru() {
super();
_isolationMethods = new IsolationMethod[] { IsolationMethod.VXLAN };
}
@Override
protected boolean canHandle(NetworkOffering offering, final NetworkType networkType, final PhysicalNetwork physicalNetwork) {
// This guru handles only Guest Isolated network that supports Source nat service
if (networkType == NetworkType.Advanced
&& isMyTrafficType(offering.getTrafficType())
&& offering.getGuestType() == Network.GuestType.Isolated
&& isMyIsolationMethod(physicalNetwork)) {
return true;
} else {
s_logger.trace("We only take care of Guest networks of type " + GuestType.Isolated + " in zone of type " + NetworkType.Advanced);
return false;
}
}
@Override
public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) {
NetworkVO network = (NetworkVO) super.design(offering, plan, userSpecified, owner);
if (network == null) {
return null;
}
network.setBroadcastDomainType(BroadcastDomainType.Vxlan);
return network;
}
protected void allocateVnet(Network network, NetworkVO implemented, long dcId,
long physicalNetworkId, String reservationId) throws InsufficientVirtualNetworkCapcityException {
if (network.getBroadcastUri() == null) {
String vnet = _dcDao.allocateVnet(dcId, physicalNetworkId, network.getAccountId(), reservationId,
canUseSystemGuestVlan(network.getAccountId()));
if (vnet == null) {
throw new InsufficientVirtualNetworkCapcityException("Unable to allocate vnet as a " +
"part of network " + network + " implement ", DataCenter.class, dcId);
}
implemented.setBroadcastUri(BroadcastDomainType.Vxlan.toUri(vnet));
allocateVnetComplete(network, implemented, dcId, physicalNetworkId, reservationId, vnet);
} else {
implemented.setBroadcastUri(network.getBroadcastUri());
}
}
// For Test: Mockit cannot mock static method, wrap it
protected void allocateVnetComplete(Network network, NetworkVO implemented, long dcId,
long physicalNetworkId, String reservationId, String vnet) {
//TODO(VXLAN): Add new event type for vxlan?
ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(), network.getAccountId(),
EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone vNet: " + vnet + " Network Id: " + network.getId(), 0);
}
@Override
public Network implement(Network network, NetworkOffering offering,
DeployDestination dest, ReservationContext context)
throws InsufficientVirtualNetworkCapcityException {
assert (network.getState() == State.Implementing) : "Why are we implementing " + network;
long dcId = dest.getDataCenter().getId();
//get physical network id
Long physicalNetworkId = network.getPhysicalNetworkId();
// physical network id can be null in Guest Network in Basic zone, so locate the physical network
if (physicalNetworkId == null) {
physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType());
}
NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), State.Allocated,
network.getDataCenterId(), physicalNetworkId);
allocateVnet(network, implemented, dcId, physicalNetworkId, context.getReservationId());
if (network.getGateway() != null) {
implemented.setGateway(network.getGateway());
}
if (network.getCidr() != null) {
implemented.setCidr(network.getCidr());
}
return implemented;
}
@Override
public void reserve(NicProfile nic, Network network,
VirtualMachineProfile vm,
DeployDestination dest, ReservationContext context)
throws InsufficientVirtualNetworkCapcityException,
InsufficientAddressCapacityException {
super.reserve(nic, network, vm, dest, context);
}
@Override
public boolean release(NicProfile nic,
VirtualMachineProfile vm,
String reservationId) {
return super.release(nic, vm, reservationId);
}
@Override
public void shutdown(NetworkProfile profile, NetworkOffering offering) {
NetworkVO networkObject = _networkDao.findById(profile.getId());
if (networkObject.getBroadcastDomainType() != BroadcastDomainType.Vxlan ||
networkObject.getBroadcastUri() == null) {
s_logger.warn("BroadcastUri is empty or incorrect for guestnetwork " + networkObject.getDisplayText());
return;
}
super.shutdown(profile, offering);
}
@Override
public boolean trash(Network network, NetworkOffering offering,
Account owner) {
return super.trash(network, offering, owner);
}
}

View File

@ -0,0 +1,273 @@
// 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.network.guru;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Command;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.domain.Domain;
import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
import com.cloud.network.Network;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.Service;
import com.cloud.network.Network.State;
import com.cloud.network.NetworkManager;
import com.cloud.network.NetworkModel;
import com.cloud.network.NetworkProfile;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.dao.PhysicalNetworkDao;
import com.cloud.network.dao.PhysicalNetworkVO;
import com.cloud.offering.NetworkOffering;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.server.ConfigurationServer;
import com.cloud.user.Account;
import com.cloud.vm.ReservationContext;
import java.util.Arrays;
public class VxlanGuestNetworkGuruTest {
PhysicalNetworkDao physnetdao = mock (PhysicalNetworkDao.class);
DataCenterDao dcdao = mock(DataCenterDao.class);
AgentManager agentmgr = mock (AgentManager.class);
NetworkManager netmgr = mock (NetworkManager.class);
NetworkModel netmodel = mock (NetworkModel.class);
ConfigurationServer confsvr = mock(ConfigurationServer.class);
NetworkDao netdao = mock(NetworkDao.class);
VxlanGuestNetworkGuru guru;
@Before
public void setUp() {
guru = spy( new VxlanGuestNetworkGuru() );
((GuestNetworkGuru) guru)._physicalNetworkDao = physnetdao;
guru._physicalNetworkDao = physnetdao;
guru._dcDao = dcdao;
guru._networkModel = netmodel;
guru._networkDao = netdao;
((GuestNetworkGuru) guru)._configServer = confsvr;
DataCenterVO dc = mock(DataCenterVO.class);
when(dc.getNetworkType()).thenReturn(NetworkType.Advanced);
when(dc.getGuestNetworkCidr()).thenReturn("10.1.1.1/24");
when(dcdao.findById(anyLong())).thenReturn((DataCenterVO) dc);
}
@Test
public void testCanHandle() {
NetworkOffering offering = mock(NetworkOffering.class);
when(offering.getId()).thenReturn(42L);
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
when(offering.getGuestType()).thenReturn(GuestType.Isolated);
PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class);
when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] { "VXLAN" }));
when(physnet.getId()).thenReturn(42L);
assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet) == true);
// Not supported TrafficType != Guest
when(offering.getTrafficType()).thenReturn(TrafficType.Management);
assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet) == true);
// Not supported: GuestType Shared
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
when(offering.getGuestType()).thenReturn(GuestType.Shared);
assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet) == true);
// Not supported: Basic networking
when(offering.getGuestType()).thenReturn(GuestType.Isolated);
assertFalse(guru.canHandle(offering, NetworkType.Basic, physnet) == true);
// Not supported: IsolationMethod != VXLAN
when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] { "VLAN" }));
assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet) == true);
}
@Test
public void testDesign() {
PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class);
when(physnetdao.findById(anyLong())).thenReturn(physnet);
when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] { "VXLAN" }));
when(physnet.getId()).thenReturn(42L);
NetworkOffering offering = mock(NetworkOffering.class);
when(offering.getId()).thenReturn(42L);
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
when(offering.getGuestType()).thenReturn(GuestType.Isolated);
DeploymentPlan plan = mock(DeploymentPlan.class);
Network network = mock(Network.class);
Account account = mock(Account.class);
Network designednetwork = guru.design(offering, plan, network, account);
assertTrue(designednetwork != null);
assertTrue(designednetwork.getBroadcastDomainType() == BroadcastDomainType.Vxlan);
}
@Test
public void testImplement() throws InsufficientVirtualNetworkCapcityException {
PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class);
when(physnetdao.findById(anyLong())).thenReturn(physnet);
when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] { "VXLAN" }));
when(physnet.getId()).thenReturn(42L);
NetworkOffering offering = mock(NetworkOffering.class);
when(offering.getId()).thenReturn(42L);
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
when(offering.getGuestType()).thenReturn(GuestType.Isolated);
NetworkVO network = mock(NetworkVO.class);
when(network.getName()).thenReturn("testnetwork");
when(network.getState()).thenReturn(State.Implementing);
when(network.getPhysicalNetworkId()).thenReturn(42L);
DeployDestination dest = mock(DeployDestination.class);
DataCenter dc = mock(DataCenter.class);
when(dest.getDataCenter()).thenReturn(dc);
when(netmodel.findPhysicalNetworkId(anyLong(), (String) any(), (TrafficType) any())).thenReturn(42L);
//TODO(VXLAN): doesn't support VNI specified
when(confsvr.getConfigValue((String) any(), (String) any(), anyLong())).thenReturn("true");
when(dcdao.allocateVnet(anyLong(), anyLong(), anyLong(), (String) any(), eq(true))).thenReturn("42");
doNothing().when(guru).allocateVnetComplete((Network) any(), (NetworkVO) any(), anyLong(), anyLong(), (String) any(), eq("42"));
Domain dom = mock(Domain.class);
when(dom.getName()).thenReturn("domain");
Account acc = mock(Account.class);
when(acc.getAccountName()).thenReturn("accountname");
ReservationContext res = mock(ReservationContext.class);
when(res.getDomain()).thenReturn(dom);
when(res.getAccount()).thenReturn(acc);
Network implementednetwork = guru.implement(network, offering, dest, res);
assertTrue(implementednetwork != null);
}
@Test
public void testImplementWithCidr() throws InsufficientVirtualNetworkCapcityException {
PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class);
when(physnetdao.findById(anyLong())).thenReturn(physnet);
when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] { "VXLAN" }));
when(physnet.getId()).thenReturn(42L);
NetworkOffering offering = mock(NetworkOffering.class);
when(offering.getId()).thenReturn(42L);
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
when(offering.getGuestType()).thenReturn(GuestType.Isolated);
NetworkVO network = mock(NetworkVO.class);
when(network.getName()).thenReturn("testnetwork");
when(network.getState()).thenReturn(State.Implementing);
when(network.getGateway()).thenReturn("10.1.1.1");
when(network.getCidr()).thenReturn("10.1.1.0/24");
when(network.getPhysicalNetworkId()).thenReturn(42L);
DeployDestination dest = mock(DeployDestination.class);
DataCenter dc = mock(DataCenter.class);
when(dest.getDataCenter()).thenReturn(dc);
when(netmodel.findPhysicalNetworkId(anyLong(), (String) any(), (TrafficType) any())).thenReturn(42L);
//TODO(VXLAN): doesn't support VNI specified
when(confsvr.getConfigValue((String) any(), (String) any(), anyLong())).thenReturn("true");
when(dcdao.allocateVnet(anyLong(), anyLong(), anyLong(), (String) any(), eq(true))).thenReturn("42");
doNothing().when(guru).allocateVnetComplete((Network) any(), (NetworkVO) any(), anyLong(), anyLong(), (String) any(), eq("42"));
Domain dom = mock(Domain.class);
when(dom.getName()).thenReturn("domain");
Account acc = mock(Account.class);
when(acc.getAccountName()).thenReturn("accountname");
ReservationContext res = mock(ReservationContext.class);
when(res.getDomain()).thenReturn(dom);
when(res.getAccount()).thenReturn(acc);
Network implementednetwork = guru.implement(network, offering, dest, res);
assertTrue(implementednetwork != null);
assertTrue(implementednetwork.getCidr().equals("10.1.1.0/24"));
assertTrue(implementednetwork.getGateway().equals("10.1.1.1"));
}
@Test
public void testShutdown() throws InsufficientVirtualNetworkCapcityException, URISyntaxException {
PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class);
when(physnetdao.findById(anyLong())).thenReturn(physnet);
when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] { "VXLAN" }));
when(physnet.getId()).thenReturn(42L);
NetworkOffering offering = mock(NetworkOffering.class);
when(offering.getId()).thenReturn(42L);
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
when(offering.getGuestType()).thenReturn(GuestType.Isolated);
NetworkVO network = mock(NetworkVO.class);
when(network.getName()).thenReturn("testnetwork");
when(network.getState()).thenReturn(State.Implementing);
when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vxlan);
when(network.getBroadcastUri()).thenReturn(new URI("vxlan:12345"));
when(network.getPhysicalNetworkId()).thenReturn(42L);
when(netdao.findById(42L)).thenReturn(network);
DeployDestination dest = mock(DeployDestination.class);
DataCenter dc = mock(DataCenter.class);
when(dest.getDataCenter()).thenReturn(dc);
when(netmodel.findPhysicalNetworkId(anyLong(), (String) any(), (TrafficType) any())).thenReturn(42L);
Domain dom = mock(Domain.class);
when(dom.getName()).thenReturn("domain");
Account acc = mock(Account.class);
when(acc.getAccountName()).thenReturn("accountname");
ReservationContext res = mock(ReservationContext.class);
when(res.getDomain()).thenReturn(dom);
when(res.getAccount()).thenReturn(acc);
NetworkProfile implementednetwork = mock(NetworkProfile.class);
when(implementednetwork.getId()).thenReturn(42L);
when(implementednetwork.getBroadcastUri()).thenReturn(new URI("vxlan:12345"));
when(offering.getSpecifyVlan()).thenReturn(false);
guru.shutdown(implementednetwork, offering);
verify(implementednetwork, times(1)).setBroadcastUri(null);
}
}

View File

@ -62,6 +62,7 @@
<module>alert-handlers/snmp-alerts</module>
<module>alert-handlers/syslog-alerts</module>
<module>network-elements/internal-loadbalancer</module>
<module>network-elements/vxlan</module>
</modules>
<dependencies>

View File

@ -0,0 +1,230 @@
#!/usr/bin/env 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.
# modifyvnet.sh -- adds and deletes VXLANs from a Routing Server
# set -x
## TODO(VXLAN): MTU, IPv6 underlying
usage() {
printf "Usage: %s: -o <op>(add | delete) -v <vxlan id> -p <pif> -b <bridge name>\n"
}
addVxlan() {
local vxlanId=$1
local pif=$2
local vxlanDev=vxlan$vxlanId
local vxlanBr=$3
local mcastGrp="239.$(( $vxlanId >> 16 % 256 )).$(( $vxlanId >> 8 % 256 )).$(( $vxlanId % 256 ))"
## TODO(VXLAN): $brif (trafficlabel) should be passed from caller because we cannot assume 1:1 mapping between pif and brif.
# lookup bridge interface
local sysfs_dir=/sys/devices/virtual/net/
local brif=`find ${sysfs_dir}*/brif/ -name $pif | sed -e "s,$sysfs_dir,," | sed -e 's,/brif/.*$,,'`
if [ "$brif " == " " ]
then
printf "Failed to lookup bridge interface which includes pif: $pif."
return 1
fi
# confirm ip address of $brif
ip addr show $brif | grep -w inet
if [ $? -gt 0 ]
then
printf "Failed to find vxlan multicast source ip address on brif: $brif."
return 1
fi
# mcast route
## TODO(VXLAN): Can we assume there're only one IP address which can be multicast src IP on the IF?
ip route get $mcastGrp | grep -w "dev $brif"
if [ $? -gt 0 ]
then
ip route add $mcastGrp/32 dev $brif
if [ $? -gt 0 ]
then
printf "Failed to add vxlan multicast route on brif: $brif."
return 1
fi
fi
if [ ! -d /sys/class/net/$vxlanDev ]
then
ip link add $vxlanDev type vxlan id $vxlanId group $mcastGrp ttl 10 dev $brif
if [ $? -gt 0 ]
then
# race condition that someone already creates the vxlan
if [ ! -d /sys/class/net/$vxlanDev ]
then
printf "Failed to create vxlan $vxlanId on brif: $brif."
return 1
fi
fi
fi
# is up?
ip link show $vxlanDev | grep -w UP > /dev/null
if [ $? -gt 0 ]
then
ip link set $vxlanDev up > /dev/null
fi
if [ ! -d /sys/class/net/$vxlanBr ]
then
brctl addbr $vxlanBr > /dev/null
if [ $? -gt 0 ]
then
if [ ! -d /sys/class/net/$vxlanBr ]
then
printf "Failed to create br: $vxlanBr"
return 2
fi
fi
brctl setfd $vxlanBr 0
fi
#pif is eslaved into vxlanBr?
ls /sys/class/net/$vxlanBr/brif/ | grep -w "$vxlanDev" > /dev/null
if [ $? -gt 0 ]
then
brctl addif $vxlanBr $vxlanDev > /dev/null
if [ $? -gt 0 ]
then
ls /sys/class/net/$vxlanBr/brif/ | grep -w "$vxlanDev" > /dev/null
if [ $? -gt 0 ]
then
printf "Failed to add vxlan: $vxlanDev to $vxlanBr"
return 3
fi
fi
fi
# is vxlanBr up?
ip link show $vxlanBr | grep -w UP > /dev/null
if [ $? -gt 0 ]
then
ip link set $vxlanBr up
fi
return 0
}
deleteVxlan() {
local vxlanId=$1
local pif=$2
local vxlanDev=vxlan$vxlanId
local vxlanBr=$3
local mcastGrp="239.$(( $vxlanId >> 16 % 256 )).$(( $vxlanId >> 8 % 256 )).$(( $vxlanId % 256 ))"
ip route del $mcastGrp/32 dev $brif
ip link delete $vxlanDev
if [ $? -gt 0 ]
then
printf "Failed to del vxlan: $vxlanId"
printf "Continue..."
fi
ip link set $vxlanBr down
if [ $? -gt 0 ]
then
return 1
fi
brctl delbr $vxlanBr
if [ $? -gt 0 ]
then
printf "Failed to del bridge $vxlanBr"
return 1
fi
return 0
}
op=
vxlanId=
option=$@
while getopts 'o:v:p:b:' OPTION
do
case $OPTION in
o) oflag=1
op="$OPTARG"
;;
v) vflag=1
vxlanId="$OPTARG"
;;
p) pflag=1
pif="$OPTARG"
;;
b) bflag=1
brName="$OPTARG"
;;
?) usage
exit 2
;;
esac
done
# Check that all arguments were passed in
if [ "$oflag$vflag$pflag$bflag" != "1111" ]
then
usage
exit 2
fi
# Do we support Vxlan?
lsmod|grep ^vxlan >& /dev/null
if [ $? -gt 0 ]
then
modprobe=`modprobe vxlan 2>&1`
if [ $? -gt 0 ]
then
printf "Failed to load vxlan kernel module: $modprobe"
exit 1
fi
fi
if [ "$op" == "add" ]
then
# Add the vxlan
addVxlan $vxlanId $pif $brName
# If the add fails then return failure
if [ $? -gt 0 ]
then
exit 1
fi
else
if [ "$op" == "delete" ]
then
# Delete the vxlan
deleteVxlan $vxlanId $pif $brName
# Always exit with success
exit 0
fi
fi

View File

@ -631,7 +631,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
try {
if (predefined == null
|| (offering.getTrafficType() != TrafficType.Guest && predefined.getCidr() == null && predefined.getBroadcastUri() == null &&
!(predefined.getBroadcastDomainType() == BroadcastDomainType.Vlan || predefined.getBroadcastDomainType() == BroadcastDomainType.Lswitch))) {
!(predefined.getBroadcastDomainType() == BroadcastDomainType.Vlan || predefined.getBroadcastDomainType() == BroadcastDomainType.Lswitch ||
predefined.getBroadcastDomainType() == BroadcastDomainType.Vxlan))) {
List<NetworkVO> configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId());
if (configs.size() > 0) {
if (s_logger.isDebugEnabled()) {
@ -1754,6 +1755,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
}
}
//TODO(VXLAN): Support VNI specified
// VlanId can be specified only when network offering supports it
boolean vlanSpecified = (vlanId != null);
if (vlanSpecified != ntwkOff.getSpecifyVlan()) {
@ -1812,9 +1814,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
vlanId + " already exists " + "in zone " + zoneId);
}
}
}
// If networkDomain is not specified, take it from the global configuration

View File

@ -187,7 +187,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
private static final long MAX_VLAN_ID = 4095L; // 2^12 - 1
private static final long MIN_GRE_KEY = 0L;
private static final long MAX_GRE_KEY = 4294967295L; // 2^32 -1
private static final long MIN_VXLAN_VNI = 0L;
private static final long MAX_VXLAN_VNI = 16777215L; // 2^24 -1
@Inject
DataCenterDao _dcDao = null;
@ -2645,6 +2646,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
if (network.getIsolationMethods().contains("GRE")) {
minVnet = MIN_GRE_KEY;
maxVnet = MAX_GRE_KEY;
} else if (network.getIsolationMethods().contains("VXLAN")) {
minVnet = MIN_VXLAN_VNI;
maxVnet = MAX_VXLAN_VNI;
}
String rangeMessage = " between " + minVnet + " and " + maxVnet;
if (VnetRange.length == 1 && VnetRange[0].equals("")) {