* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
- * Authors : Madhu Venugopal, Brent Salisbury
+ * Authors : Madhu Venugopal, Brent Salisbury, Sam Hague
*/
package org.opendaylight.ovsdb.neutron;
import java.util.Map;
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.ovsdb.lib.table.Bridge;
import org.opendaylight.ovsdb.lib.table.Interface;
import org.opendaylight.ovsdb.lib.table.Port;
-import org.opendaylight.ovsdb.lib.table.internal.Table;
-import org.opendaylight.ovsdb.neutron.provider.ProviderNetworkManager;
+import org.opendaylight.ovsdb.lib.table.Table;
+import org.opendaylight.ovsdb.neutron.provider.IProviderNetworkManager;
import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
import org.opendaylight.ovsdb.plugin.StatusWithUuid;
import org.slf4j.LoggerFactory;
/**
- * OpenStack Neutron with the OpenVswitch data plan relies on a typical OVS bridge configurations that
+ * OpenStack Neutron with the OpenvSwitch data plan relies on a typical OVS bridge configurations that
* consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
*
* In DevStack like setups, the br-tun is not automatically created on the controller nodes.
- * Hence this class attempts to bring all the nodes to be elibible for OpenStack operations.
+ * Hence this class attempts to bring all the nodes to be eligible for OpenStack operations.
*
*/
-public class InternalNetworkManager {
+public class InternalNetworkManager implements IInternalNetworkManager {
static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
private static final int LLDP_PRIORITY = 1000;
private static final int NORMAL_PRIORITY = 0;
- private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
- private InternalNetworkManager() {
- }
+ // The implementation for each of these services is resolved by the OSGi Service Manager
+ private volatile IAdminConfigManager adminConfigManager;
+ private volatile IProviderNetworkManager providerNetworkManager;
- public static InternalNetworkManager getManager() {
- return internalNetwork;
+ public InternalNetworkManager() {
}
public String getInternalBridgeUUID (Node node, String bridgeName) {
return null;
}
+ public Bridge getInternalBridge (Node node, String bridgeName) {
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
+ if (bridgeTable != null) {
+ for (String key : bridgeTable.keySet()) {
+ Bridge bridge = (Bridge) bridgeTable.get(key);
+ if (bridge.getName().equals(bridgeName)) {
+ return bridge;
+ }
+ }
+ }
+ } catch (Exception e) {
+ logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
+ }
+ return null;
+ }
+
public boolean isInternalNetworkNeutronReady(Node node) {
- if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
+ if (this.getInternalBridgeUUID(node, adminConfigManager.getIntegrationBridgeName()) != null) {
return true;
} else {
return false;
if (!this.isInternalNetworkNeutronReady(node)) {
return false;
}
- if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
+ if (this.getInternalBridgeUUID(node, adminConfigManager.getNetworkBridgeName()) != null) {
return true;
} else {
return false;
}
}
+ public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+
+ for (UUID portsUUID : bridge.getPorts()) {
+ try {
+ Port port = (Port) ovsdbTable.getRow(node, Port.NAME.getName(), portsUUID.toString());
+ if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
+ return true;
+ }
+ } catch (Exception e) {
+ logger.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
+ boolean isPatchCreated = false;
+
+ String portName = adminConfigManager.getPatchToNetwork();
+ if (isPortOnBridge(node, intBridge, portName)) {
+ portName = adminConfigManager.getPatchToIntegration();
+ if (isPortOnBridge(node, netBridge, portName)) {
+ isPatchCreated = true;
+ }
+ }
+
+ return isPatchCreated;
+ }
+
+ /* Determine if internal network is ready for tunnel network types.
+ * - OF 1.0 requires br-int, br-net and a patch connecting them.
+ * - OF 1.3 requires br-int.
+ */
+ public boolean isInternalNetworkTunnelReady (Node node) {
+ /* Is br-int created? */
+ Bridge intBridge = this.getInternalBridge(node, adminConfigManager.getIntegrationBridgeName());
+ if (intBridge == null) {
+ return false;
+ }
+
+ if (providerNetworkManager == null) {
+ logger.error("Provider Network Manager is not available");
+ return false;
+ }
+ if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
+ /* Is br-net created? */
+ Bridge netBridge = this.getInternalBridge(node, adminConfigManager.getNetworkBridgeName());
+ if (netBridge == null) {
+ return false;
+ }
+
+ if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* Determine if internal network is ready for vlan network types.
+ * - OF 1.0 requires br-int, br-net, a patch connecting them and
+ * physical device added to br-net.
+ * - OF 1.3 requires br-int and physical device added to br-int.
+ */
+ public boolean isInternalNetworkVlanReady (Node node, NeutronNetwork network) {
+ /* is br-int created */
+ Bridge intBridge = this.getInternalBridge(node, adminConfigManager.getIntegrationBridgeName());
+ if (intBridge == null) {
+ logger.trace("shague isInternalNetworkVlanReady: node: {}, br-int missing", node);
+ return false;
+ }
+
+ if (providerNetworkManager == null) {
+ logger.error("Provider Network Manager is not available");
+ return false;
+ }
+ if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
+ /* is br-net created? */
+ Bridge netBridge = this.getInternalBridge(node, adminConfigManager.getNetworkBridgeName());
+
+ if (netBridge == null) {
+ logger.trace("shague isInternalNetworkVlanReady: node: {}, br-net missing", node);
+ return false;
+ }
+
+ if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
+ logger.trace("shague isInternalNetworkVlanReady: node: {}, patch missing", node);
+ return false;
+ }
+
+ /* Check if physical device is added to br-net. */
+ String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
+ if (isPortOnBridge(node, netBridge, phyNetName)) {
+ return true;
+ }
+ } else {
+ /* Check if physical device is added to br-int. */
+ String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
+ if (isPortOnBridge(node, intBridge, phyNetName)) {
+ return true;
+ }
+ }
+
+ logger.trace("shague isInternalNetworkVlanReady: node: {}, eth missing", node);
+ return false;
+ }
+
+ /*
+ * Create the integration bridge.
+ *
+ Bridge br-int
+ Port br-int
+ Interface br-int
+ type: internal
+ */
+ public void createIntegrationBridge (Node node) throws Exception {
+ String brInt = adminConfigManager.getIntegrationBridgeName();
+
+ Status status = this.addInternalBridge(node, brInt, null, null);
+ if (!status.isSuccess()) {
+ logger.debug("Integration Bridge Creation Status: {}", status);
+ }
+ }
+
/*
- * Lets create these if not already present :
+ * Create complete network for all network types and OpenFlow versions.
*
+ OF 1.0 vlan:
Bridge br-int
- Port patch-tun
- Interface patch-tun
+ Port patch-net
+ Interface patch-net
type: patch
options: {peer=patch-int}
Port br-int
Interface br-int
type: internal
- Bridge br-tun
+ Bridge br-net
+ Port "eth1"
+ Interface "eth1"
Port patch-int
Interface patch-int
type: patch
- options: {peer=patch-tun}
- Port br-tun
- Interface br-tun
+ options: {peer=patch-net}
+ Port br-net
+ Interface br-net
type: internal
- */
- public void createInternalNetworkForOverlay(Node node) throws Exception {
- String brTun = AdminConfigManager.getManager().getTunnelBridgeName();
- String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
- String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
- String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
- Status status = this.addInternalBridge(node, brInt, patchTun, patchInt);
- if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
- if (ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
- status = this.addInternalBridge(node, brTun, patchInt, patchTun);
- if (!status.isSuccess()) logger.debug("Tunnel Bridge Creation Status : "+status.toString());
- }
- }
+ OF 1.0 tunnel:
+ Bridge br-int
+ Port patch-net
+ Interface patch-net
+ type: patch
+ options: {peer=patch-int}
+ Port br-int
+ Interface br-int
+ type: internal
+ Bridge "br-net"
+ Port patch-int
+ Interface patch-int
+ type: patch
+ options: {peer=patch-net}
+ Port br-net
+ Interface br-net
+ type: internal
- /*
- * Lets create these if not already present :
- *
+ OF 1.3 vlan:
+ Bridge br-int
+ Port "eth1"
+ Interface "eth1"
+ Port br-int
+ Interface br-int
+ type: internal
+
+ OF 1.3 tunnel:
Bridge br-int
Port br-int
Interface br-int
type: internal
*/
- public void createInternalNetworkForNeutron(Node node) throws Exception {
- String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
+ public boolean createNetNetwork (Node node, NeutronNetwork network) throws Exception {
+ Status status;
- Status status = this.addInternalBridge(node, brInt, null, null);
- if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
+ logger.debug("createNetNetwork: node: {}, network type: {}", node, network.getProviderNetworkType());
+
+ if (providerNetworkManager == null) {
+ logger.error("Provider Network Manager is not available");
+ return false;
+ }
+ if (providerNetworkManager.getProvider().hasPerTenantTunneling()) { /* indicates OF 1.0 */
+ String brInt = adminConfigManager.getIntegrationBridgeName();
+ String brNet = adminConfigManager.getNetworkBridgeName();
+ String patchNet = adminConfigManager.getPatchToNetwork();
+ String patchInt = adminConfigManager.getPatchToIntegration();
+
+ status = this.addInternalBridge(node, brInt, patchNet, patchInt);
+ if (!status.isSuccess()) {
+ logger.debug("{} Bridge Creation Status: {}", brInt, status);
+ return false;
+ }
+ status = this.addInternalBridge(node, brNet, patchInt, patchNet);
+ if (!status.isSuccess()) {
+ logger.debug("{} Bridge Creation Status: {}", brNet, status);
+ return false;
+ }
+
+ /* For vlan network types add physical port to br-net. */
+ if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+ String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
+ status = addPortToBridge(node, brNet, phyNetName);
+ if (!status.isSuccess()) {
+ logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
+ return false;
+ }
+ }
+ } else {
+ String brInt = adminConfigManager.getIntegrationBridgeName();
+ status = this.addInternalBridge(node, brInt, null, null);
+ if (!status.isSuccess()) {
+ logger.debug("{} Bridge Creation Status: {}", brInt, status);
+ return false;
+ }
+
+ /* For vlan network types add physical port to br-int. */
+ if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+ String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
+ status = addPortToBridge(node, brInt, phyNetName);
+ if (!status.isSuccess()) {
+ logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
+ return false;
+ }
+ }
+ }
+
+ logger.debug("createNetNetwork: node: {}, status: success", node);
+ return true;
}
- private Status addInternalBridge (Node node, String bridgeName, String localPathName, String remotePatchName) throws Exception {
+ private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
+ logger.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
- Bridge bridge = new Bridge();
if (bridgeUUID == null) {
- bridge.setName(bridgeName);
- if (!ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
- OvsDBSet<String> protocols = new OvsDBSet<String>();
- protocols.add("OpenFlow13");
- bridge.setProtocols(protocols);
+ logger.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
+ return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
+ }
+
+ /* Check if the port already exists. */
+ Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
+ if (bridge != null) {
+ if (isPortOnBridge(node, bridge, portName)) {
+ logger.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
+ return new Status(StatusCode.SUCCESS);
}
+ } else {
+ logger.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
+ return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
+ }
- StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
- if (!statusWithUuid.isSuccess()) return statusWithUuid;
- bridgeUUID = statusWithUuid.getUuid().toString();
- Port port = new Port();
- port.setName(bridgeName);
- ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
- } else if (!ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
- OvsDBSet<String> protocols = new OvsDBSet<String>();
- protocols.add("OpenFlow13");
- bridge.setProtocols(protocols);
- ovsdbTable.updateRow(node, Bridge.NAME.getName(), null, bridgeUUID, bridge);
+ Port port = new Port();
+ port.setName(portName);
+ StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
+ if (!statusWithUuid.isSuccess()) {
+ logger.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
+ return statusWithUuid;
}
- IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
- connectionService.setOFController(node, bridgeUUID);
+ String portUUID = statusWithUuid.getUuid().toString();
+ String interfaceUUID = null;
+ int timeout = 6;
+ while ((interfaceUUID == null) && (timeout > 0)) {
+ port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
+ OvsDBSet<UUID> interfaces = port.getInterfaces();
+ if (interfaces == null || interfaces.size() == 0) {
+ // Wait for the OVSDB update to sync up the Local cache.
+ Thread.sleep(500);
+ timeout--;
+ continue;
+ }
+ interfaceUUID = interfaces.toArray()[0].toString();
+ Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
+ if (intf == null) {
+ interfaceUUID = null;
+ }
+ }
- if (localPathName != null && remotePatchName != null && ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
- return addPatchPort(node, bridgeUUID, localPathName, remotePatchName);
+ if (interfaceUUID == null) {
+ logger.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
+ return new Status(StatusCode.INTERNALERROR);
}
+
return new Status(StatusCode.SUCCESS);
}
- private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
+ private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ logger.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
+ node, bridgeUUID, portName, peerPortName);
+
+ /* Check if the port already exists. */
+ Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
+ if (bridge != null) {
+ if (isPortOnBridge(node, bridge, portName)) {
+ logger.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
+ return new Status(StatusCode.SUCCESS);
+ }
+ } else {
+ logger.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
+ return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
+ }
+
Port patchPort = new Port();
patchPort.setName(portName);
// Create patch port and interface
return new Status(StatusCode.INTERNALERROR);
}
- Interface tunInterface = new Interface();
- tunInterface.setType("patch");
+ Interface intf = new Interface();
+ intf.setType("patch");
OvsDBMap<String, String> options = new OvsDBMap<String, String>();
- options.put("peer", patchName);
- tunInterface.setOptions(options);
- return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
+ options.put("peer", peerPortName);
+ intf.setOptions(options);
+ return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, intf);
+ }
+
+ private Status addInternalBridge (Node node, String bridgeName, String localPatchName, String remotePatchName) throws Exception {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+
+ String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
+ Bridge bridge = new Bridge();
+ OvsDBSet<String> failMode = new OvsDBSet<String>();
+ failMode.add("secure");
+ bridge.setFail_mode(failMode);
+
+ OvsDBSet<String> protocols = new OvsDBSet<String>();
+ if (providerNetworkManager == null) {
+ logger.error("Provider Network Manager is not available");
+ return new Status(StatusCode.INTERNALERROR);
+ }
+ if (!providerNetworkManager.getProvider().hasPerTenantTunneling()) {
+ protocols.add("OpenFlow13");
+ } else {
+ protocols.add("OpenFlow10");
+ }
+ bridge.setProtocols(protocols);
+
+ if (bridgeUUID == null) {
+ bridge.setName(bridgeName);
+
+ StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
+ if (!statusWithUuid.isSuccess()) return statusWithUuid;
+ bridgeUUID = statusWithUuid.getUuid().toString();
+ Port port = new Port();
+ port.setName(bridgeName);
+ Status status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
+ logger.debug("addInternalBridge: Inserting Bridge {} {} with protocols {} and status {}",
+ bridgeName, bridgeUUID, protocols, status);
+ } else {
+ Status status = ovsdbTable.updateRow(node, Bridge.NAME.getName(), null, bridgeUUID, bridge);
+ logger.debug("addInternalBridge: Updating Bridge {} {} with protocols {} and status {}",
+ bridgeName, bridgeUUID, protocols, status);
+ }
+
+ IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+ connectionService.setOFController(node, bridgeUUID);
+
+ if (localPatchName != null && remotePatchName != null && providerNetworkManager.getProvider().hasPerTenantTunneling()) {
+ return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
+ }
+ return new Status(StatusCode.SUCCESS);
}
public void prepareInternalNetwork(Node node) {
try {
- this.createInternalNetworkForOverlay(node);
+ this.createIntegrationBridge(node);
} catch (Exception e) {
logger.error("Error creating internal network "+node.toString(), e);
+ return;
+ }
+ if (providerNetworkManager == null) {
+ logger.error("Error creating internal network. Provider Network Manager unavailable");
+ return;
+ }
+ providerNetworkManager.getProvider().initializeFlowRules(node);
+ }
+
+ /*
+ * Check if the full network setup is available. If not, create it.
+ */
+ public boolean checkAndCreateNetwork (Node node, NeutronNetwork network) {
+ boolean isCreated = false;
+ if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+ if (!this.isInternalNetworkVlanReady(node, network)) {
+ try {
+ isCreated = this.createNetNetwork(node, network);
+ } catch (Exception e) {
+ logger.error("Error creating internal net network ", node, e);
+ }
+ } else {
+ isCreated = true;
+ }
+ } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
+ network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
+ if (!this.isInternalNetworkTunnelReady(node)) {
+ try {
+ isCreated = this.createNetNetwork(node, network);
+ } catch (Exception e) {
+ logger.error("Error creating internal net network ", node, e);
+ }
+ } else {
+ isCreated = true;
+ }
}
- ProviderNetworkManager.getManager().initializeFlowRules(node);
+ return isCreated;
}
}