2 * Copyright (C) 2013 Red Hat, Inc.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 * Authors : Madhu Venugopal, Brent Salisbury, Sam Hague
10 package org.opendaylight.ovsdb.neutron;
14 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
15 import org.opendaylight.controller.sal.core.Node;
16 import org.opendaylight.controller.sal.utils.ServiceHelper;
17 import org.opendaylight.controller.sal.utils.Status;
18 import org.opendaylight.controller.sal.utils.StatusCode;
19 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
20 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
21 import org.opendaylight.ovsdb.lib.notation.UUID;
22 import org.opendaylight.ovsdb.lib.table.Bridge;
23 import org.opendaylight.ovsdb.lib.table.Interface;
24 import org.opendaylight.ovsdb.lib.table.Port;
25 import org.opendaylight.ovsdb.lib.table.internal.Table;
26 import org.opendaylight.ovsdb.neutron.provider.ProviderNetworkManager;
27 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
28 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
29 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * OpenStack Neutron with the OpenvSwitch data plan relies on a typical OVS bridge configurations that
35 * consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
37 * In DevStack like setups, the br-tun is not automatically created on the controller nodes.
38 * Hence this class attempts to bring all the nodes to be eligible for OpenStack operations.
41 public class InternalNetworkManager {
42 static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
43 private static final int LLDP_PRIORITY = 1000;
44 private static final int NORMAL_PRIORITY = 0;
46 private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
47 private InternalNetworkManager() {
50 public static InternalNetworkManager getManager() {
51 return internalNetwork;
54 public String getInternalBridgeUUID (Node node, String bridgeName) {
56 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
57 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
58 if (bridgeTable == null) return null;
59 for (String key : bridgeTable.keySet()) {
60 Bridge bridge = (Bridge)bridgeTable.get(key);
61 if (bridge.getName().equals(bridgeName)) return key;
63 } catch (Exception e) {
64 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
69 public Bridge getInternalBridge (Node node, String bridgeName) {
71 OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
72 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
73 if (bridgeTable != null) {
74 for (String key : bridgeTable.keySet()) {
75 Bridge bridge = (Bridge) bridgeTable.get(key);
76 if (bridge.getName().equals(bridgeName)) {
81 } catch (Exception e) {
82 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
87 public boolean isInternalNetworkNeutronReady(Node node) {
88 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
95 public boolean isInternalNetworkOverlayReady(Node node) {
96 if (!this.isInternalNetworkNeutronReady(node)) {
99 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getNetworkBridgeName()) != null) {
106 public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
107 OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
109 for (UUID portsUUID : bridge.getPorts()) {
111 Port port = (Port) ovsdbTable.getRow(node, Port.NAME.getName(), portsUUID.toString());
112 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
115 } catch (Exception e) {
116 logger.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
123 public boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
124 boolean isPatchCreated = false;
126 String portName = AdminConfigManager.getManager().getPatchToNetwork();
127 if (isPortOnBridge(node, intBridge, portName)) {
128 portName = AdminConfigManager.getManager().getPatchToIntegration();
129 if (isPortOnBridge(node, netBridge, portName)) {
130 isPatchCreated = true;
134 return isPatchCreated;
137 /* Determine if internal network is ready for tunnel network types.
138 * - OF 1.0 requires br-int, br-net and a patch connecting them.
139 * - OF 1.3 requires br-int.
141 public boolean isInternalNetworkTunnelReady (Node node) {
142 /* Is br-int created? */
143 Bridge intBridge = this.getInternalBridge(node, AdminConfigManager.getManager().getIntegrationBridgeName());
144 if (intBridge == null) {
148 if (ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
149 /* Is br-net created? */
150 Bridge netBridge = this.getInternalBridge(node, AdminConfigManager.getManager().getNetworkBridgeName());
151 if (netBridge == null) {
155 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
162 /* Determine if internal network is ready for vlan network types.
163 * - OF 1.0 requires br-int, br-net, a patch connecting them and
164 * physical device added to br-net.
165 * - OF 1.3 requires br-int and physical device added to br-int.
167 public boolean isInternalNetworkVlanReady (Node node, NeutronNetwork network) {
168 /* is br-int created */
169 Bridge intBridge = this.getInternalBridge(node, AdminConfigManager.getManager().getIntegrationBridgeName());
170 if (intBridge == null) {
171 logger.trace("shague isInternalNetworkVlanReady: node: {}, br-int missing", node);
175 if (ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
176 /* is br-net created? */
177 Bridge netBridge = this.getInternalBridge(node, AdminConfigManager.getManager().getNetworkBridgeName());
179 if (netBridge == null) {
180 logger.trace("shague isInternalNetworkVlanReady: node: {}, br-net missing", node);
184 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
185 logger.trace("shague isInternalNetworkVlanReady: node: {}, patch missing", node);
189 /* Check if physical device is added to br-net. */
190 String phyNetName = AdminConfigManager.getManager().getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
191 if (isPortOnBridge(node, netBridge, phyNetName)) {
195 /* Check if physical device is added to br-int. */
196 String phyNetName = AdminConfigManager.getManager().getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
197 if (isPortOnBridge(node, intBridge, phyNetName)) {
202 logger.trace("shague isInternalNetworkVlanReady: node: {}, eth missing", node);
207 * Create the integration bridge.
214 public void createIntegrationBridge (Node node) throws Exception {
215 String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
217 Status status = this.addInternalBridge(node, brInt, null, null);
218 if (!status.isSuccess()) {
219 logger.debug("Integration Bridge Creation Status: {}", status);
224 * Create complete network for all network types and OpenFlow versions.
231 options: {peer=patch-int}
241 options: {peer=patch-net}
251 options: {peer=patch-int}
259 options: {peer=patch-net}
278 public boolean createNetNetwork (Node node, NeutronNetwork network) throws Exception {
281 logger.debug("createNetNetwork: node: {}, network type: {}", node, network.getProviderNetworkType());
283 if (ProviderNetworkManager.getManager().hasPerTenantTunneling()) { /* indicates OF 1.0 */
284 String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
285 String brNet = AdminConfigManager.getManager().getNetworkBridgeName();
286 String patchNet = AdminConfigManager.getManager().getPatchToNetwork();
287 String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
289 status = this.addInternalBridge(node, brInt, patchNet, patchInt);
290 if (!status.isSuccess()) {
291 logger.debug("{} Bridge Creation Status: {}", brInt, status);
294 status = this.addInternalBridge(node, brNet, patchInt, patchNet);
295 if (!status.isSuccess()) {
296 logger.debug("{} Bridge Creation Status: {}", brNet, status);
300 /* For vlan network types add physical port to br-net. */
301 if (network.getProviderNetworkType().equalsIgnoreCase("vlan")) {
302 String phyNetName = AdminConfigManager.getManager().getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
303 status = addPortToBridge(node, brNet, phyNetName);
304 if (!status.isSuccess()) {
305 logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
310 String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
311 status = this.addInternalBridge(node, brInt, null, null);
312 if (!status.isSuccess()) {
313 logger.debug("{} Bridge Creation Status: {}", brInt, status);
317 /* For vlan network types add physical port to br-int. */
318 if (network.getProviderNetworkType().equalsIgnoreCase("vlan")) {
319 String phyNetName = AdminConfigManager.getManager().getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
320 status = addPortToBridge(node, brInt, phyNetName);
321 if (!status.isSuccess()) {
322 logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
328 logger.debug("createNetNetwork: node: {}, status: success", node);
332 private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
333 logger.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
334 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
336 String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
337 if (bridgeUUID == null) {
338 logger.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
339 return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
342 /* Check if the port already exists. */
343 Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
344 if (bridge != null) {
345 if (isPortOnBridge(node, bridge, portName)) {
346 logger.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
347 return new Status(StatusCode.SUCCESS);
350 logger.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
351 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
354 Port port = new Port();
355 port.setName(portName);
356 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
357 if (!statusWithUuid.isSuccess()) {
358 logger.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
359 return statusWithUuid;
362 String portUUID = statusWithUuid.getUuid().toString();
363 String interfaceUUID = null;
365 while ((interfaceUUID == null) && (timeout > 0)) {
366 port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
367 OvsDBSet<UUID> interfaces = port.getInterfaces();
368 if (interfaces == null || interfaces.size() == 0) {
369 // Wait for the OVSDB update to sync up the Local cache.
374 interfaceUUID = interfaces.toArray()[0].toString();
375 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
377 interfaceUUID = null;
381 if (interfaceUUID == null) {
382 logger.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
383 return new Status(StatusCode.INTERNALERROR);
386 return new Status(StatusCode.SUCCESS);
389 private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
390 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
392 logger.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
393 node, bridgeUUID, portName, peerPortName);
395 /* Check if the port already exists. */
396 Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
397 if (bridge != null) {
398 if (isPortOnBridge(node, bridge, portName)) {
399 logger.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
400 return new Status(StatusCode.SUCCESS);
403 logger.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
404 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
407 Port patchPort = new Port();
408 patchPort.setName(portName);
409 // Create patch port and interface
410 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
411 if (!statusWithUuid.isSuccess()) return statusWithUuid;
413 String patchPortUUID = statusWithUuid.getUuid().toString();
415 String interfaceUUID = null;
417 while ((interfaceUUID == null) && (timeout > 0)) {
418 patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
419 OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
420 if (interfaces == null || interfaces.size() == 0) {
421 // Wait for the OVSDB update to sync up the Local cache.
426 interfaceUUID = interfaces.toArray()[0].toString();
429 if (interfaceUUID == null) {
430 return new Status(StatusCode.INTERNALERROR);
433 Interface intf = new Interface();
434 intf.setType("patch");
435 OvsDBMap<String, String> options = new OvsDBMap<String, String>();
436 options.put("peer", peerPortName);
437 intf.setOptions(options);
438 return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, intf);
441 private Status addInternalBridge (Node node, String bridgeName, String localPatchName, String remotePatchName) throws Exception {
442 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
444 String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
445 Bridge bridge = new Bridge();
446 OvsDBSet<String> failMode = new OvsDBSet<String>();
447 failMode.add("secure");
448 bridge.setFail_mode(failMode);
450 OvsDBSet<String> protocols = new OvsDBSet<String>();
451 if (!ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
452 protocols.add("OpenFlow13");
454 protocols.add("OpenFlow10");
456 bridge.setProtocols(protocols);
458 if (bridgeUUID == null) {
459 bridge.setName(bridgeName);
461 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
462 if (!statusWithUuid.isSuccess()) return statusWithUuid;
463 bridgeUUID = statusWithUuid.getUuid().toString();
464 Port port = new Port();
465 port.setName(bridgeName);
466 Status status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
467 logger.debug("addInternalBridge: Inserting Bridge {} {} with protocols {} and status {}",
468 bridgeName, bridgeUUID, protocols, status);
470 Status status = ovsdbTable.updateRow(node, Bridge.NAME.getName(), null, bridgeUUID, bridge);
471 logger.debug("addInternalBridge: Updating Bridge {} {} with protocols {} and status {}",
472 bridgeName, bridgeUUID, protocols, status);
475 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
476 connectionService.setOFController(node, bridgeUUID);
478 if (localPatchName != null && remotePatchName != null && ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
479 return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
481 return new Status(StatusCode.SUCCESS);
484 public void prepareInternalNetwork(Node node) {
486 this.createIntegrationBridge(node);
487 } catch (Exception e) {
488 logger.error("Error creating internal network "+node.toString(), e);
490 ProviderNetworkManager.getManager().initializeFlowRules(node);
494 * Check if the full network setup is available. If not, create it.
496 public boolean checkAndCreateNetwork (Node node, NeutronNetwork network) {
497 boolean isCreated = false;
498 if (network.getProviderNetworkType().equalsIgnoreCase("vlan")) {
499 if (!InternalNetworkManager.getManager().isInternalNetworkVlanReady(node, network)) {
501 isCreated = InternalNetworkManager.getManager().createNetNetwork(node, network);
502 } catch (Exception e) {
503 logger.error("Error creating internal net network ", node, e);
508 } else if (network.getProviderNetworkType().equalsIgnoreCase("vxlan") ||
509 network.getProviderNetworkType().equalsIgnoreCase("gre")) {
510 if (!InternalNetworkManager.getManager().isInternalNetworkTunnelReady(node)) {
512 isCreated = InternalNetworkManager.getManager().createNetNetwork(node, network);
513 } catch (Exception e) {
514 logger.error("Error creating internal net network ", node, e);