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.IProviderNetworkManager;
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 implements IInternalNetworkManager {
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 // The implementation for each of these services is resolved by the OSGi Service Manager
47 private volatile IAdminConfigManager adminConfigManager;
48 private volatile IProviderNetworkManager providerNetworkManager;
50 public InternalNetworkManager() {
53 public String getInternalBridgeUUID (Node node, String bridgeName) {
55 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
56 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
57 if (bridgeTable == null) return null;
58 for (String key : bridgeTable.keySet()) {
59 Bridge bridge = (Bridge)bridgeTable.get(key);
60 if (bridge.getName().equals(bridgeName)) return key;
62 } catch (Exception e) {
63 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
68 public Bridge getInternalBridge (Node node, String bridgeName) {
70 OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
71 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
72 if (bridgeTable != null) {
73 for (String key : bridgeTable.keySet()) {
74 Bridge bridge = (Bridge) bridgeTable.get(key);
75 if (bridge.getName().equals(bridgeName)) {
80 } catch (Exception e) {
81 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
86 public boolean isInternalNetworkNeutronReady(Node node) {
87 if (this.getInternalBridgeUUID(node, adminConfigManager.getIntegrationBridgeName()) != null) {
94 public boolean isInternalNetworkOverlayReady(Node node) {
95 if (!this.isInternalNetworkNeutronReady(node)) {
98 if (this.getInternalBridgeUUID(node, adminConfigManager.getNetworkBridgeName()) != null) {
105 public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
106 OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
108 for (UUID portsUUID : bridge.getPorts()) {
110 Port port = (Port) ovsdbTable.getRow(node, Port.NAME.getName(), portsUUID.toString());
111 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
114 } catch (Exception e) {
115 logger.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
122 public boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
123 boolean isPatchCreated = false;
125 String portName = adminConfigManager.getPatchToNetwork();
126 if (isPortOnBridge(node, intBridge, portName)) {
127 portName = adminConfigManager.getPatchToIntegration();
128 if (isPortOnBridge(node, netBridge, portName)) {
129 isPatchCreated = true;
133 return isPatchCreated;
136 /* Determine if internal network is ready for tunnel network types.
137 * - OF 1.0 requires br-int, br-net and a patch connecting them.
138 * - OF 1.3 requires br-int.
140 public boolean isInternalNetworkTunnelReady (Node node) {
141 /* Is br-int created? */
142 Bridge intBridge = this.getInternalBridge(node, adminConfigManager.getIntegrationBridgeName());
143 if (intBridge == null) {
147 if (providerNetworkManager == null) {
148 logger.error("Provider Network Manager is not available");
151 if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
152 /* Is br-net created? */
153 Bridge netBridge = this.getInternalBridge(node, adminConfigManager.getNetworkBridgeName());
154 if (netBridge == null) {
158 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
165 /* Determine if internal network is ready for vlan network types.
166 * - OF 1.0 requires br-int, br-net, a patch connecting them and
167 * physical device added to br-net.
168 * - OF 1.3 requires br-int and physical device added to br-int.
170 public boolean isInternalNetworkVlanReady (Node node, NeutronNetwork network) {
171 /* is br-int created */
172 Bridge intBridge = this.getInternalBridge(node, adminConfigManager.getIntegrationBridgeName());
173 if (intBridge == null) {
174 logger.trace("shague isInternalNetworkVlanReady: node: {}, br-int missing", node);
178 if (providerNetworkManager == null) {
179 logger.error("Provider Network Manager is not available");
182 if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
183 /* is br-net created? */
184 Bridge netBridge = this.getInternalBridge(node, adminConfigManager.getNetworkBridgeName());
186 if (netBridge == null) {
187 logger.trace("shague isInternalNetworkVlanReady: node: {}, br-net missing", node);
191 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
192 logger.trace("shague isInternalNetworkVlanReady: node: {}, patch missing", node);
196 /* Check if physical device is added to br-net. */
197 String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
198 if (isPortOnBridge(node, netBridge, phyNetName)) {
202 /* Check if physical device is added to br-int. */
203 String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
204 if (isPortOnBridge(node, intBridge, phyNetName)) {
209 logger.trace("shague isInternalNetworkVlanReady: node: {}, eth missing", node);
214 * Create the integration bridge.
221 public void createIntegrationBridge (Node node) throws Exception {
222 String brInt = adminConfigManager.getIntegrationBridgeName();
224 Status status = this.addInternalBridge(node, brInt, null, null);
225 if (!status.isSuccess()) {
226 logger.debug("Integration Bridge Creation Status: {}", status);
231 * Create complete network for all network types and OpenFlow versions.
238 options: {peer=patch-int}
248 options: {peer=patch-net}
258 options: {peer=patch-int}
266 options: {peer=patch-net}
285 public boolean createNetNetwork (Node node, NeutronNetwork network) throws Exception {
288 logger.debug("createNetNetwork: node: {}, network type: {}", node, network.getProviderNetworkType());
290 if (providerNetworkManager == null) {
291 logger.error("Provider Network Manager is not available");
294 if (providerNetworkManager.getProvider().hasPerTenantTunneling()) { /* indicates OF 1.0 */
295 String brInt = adminConfigManager.getIntegrationBridgeName();
296 String brNet = adminConfigManager.getNetworkBridgeName();
297 String patchNet = adminConfigManager.getPatchToNetwork();
298 String patchInt = adminConfigManager.getPatchToIntegration();
300 status = this.addInternalBridge(node, brInt, patchNet, patchInt);
301 if (!status.isSuccess()) {
302 logger.debug("{} Bridge Creation Status: {}", brInt, status);
305 status = this.addInternalBridge(node, brNet, patchInt, patchNet);
306 if (!status.isSuccess()) {
307 logger.debug("{} Bridge Creation Status: {}", brNet, status);
311 /* For vlan network types add physical port to br-net. */
312 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
313 String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
314 status = addPortToBridge(node, brNet, phyNetName);
315 if (!status.isSuccess()) {
316 logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
321 String brInt = adminConfigManager.getIntegrationBridgeName();
322 status = this.addInternalBridge(node, brInt, null, null);
323 if (!status.isSuccess()) {
324 logger.debug("{} Bridge Creation Status: {}", brInt, status);
328 /* For vlan network types add physical port to br-int. */
329 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
330 String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
331 status = addPortToBridge(node, brInt, phyNetName);
332 if (!status.isSuccess()) {
333 logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
339 logger.debug("createNetNetwork: node: {}, status: success", node);
343 private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
344 logger.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
345 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
347 String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
348 if (bridgeUUID == null) {
349 logger.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
350 return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
353 /* Check if the port already exists. */
354 Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
355 if (bridge != null) {
356 if (isPortOnBridge(node, bridge, portName)) {
357 logger.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
358 return new Status(StatusCode.SUCCESS);
361 logger.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
362 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
365 Port port = new Port();
366 port.setName(portName);
367 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
368 if (!statusWithUuid.isSuccess()) {
369 logger.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
370 return statusWithUuid;
373 String portUUID = statusWithUuid.getUuid().toString();
374 String interfaceUUID = null;
376 while ((interfaceUUID == null) && (timeout > 0)) {
377 port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
378 OvsDBSet<UUID> interfaces = port.getInterfaces();
379 if (interfaces == null || interfaces.size() == 0) {
380 // Wait for the OVSDB update to sync up the Local cache.
385 interfaceUUID = interfaces.toArray()[0].toString();
386 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
388 interfaceUUID = null;
392 if (interfaceUUID == null) {
393 logger.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
394 return new Status(StatusCode.INTERNALERROR);
397 return new Status(StatusCode.SUCCESS);
400 private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
401 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
403 logger.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
404 node, bridgeUUID, portName, peerPortName);
406 /* Check if the port already exists. */
407 Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
408 if (bridge != null) {
409 if (isPortOnBridge(node, bridge, portName)) {
410 logger.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
411 return new Status(StatusCode.SUCCESS);
414 logger.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
415 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
418 Port patchPort = new Port();
419 patchPort.setName(portName);
420 // Create patch port and interface
421 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
422 if (!statusWithUuid.isSuccess()) return statusWithUuid;
424 String patchPortUUID = statusWithUuid.getUuid().toString();
426 String interfaceUUID = null;
428 while ((interfaceUUID == null) && (timeout > 0)) {
429 patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
430 OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
431 if (interfaces == null || interfaces.size() == 0) {
432 // Wait for the OVSDB update to sync up the Local cache.
437 interfaceUUID = interfaces.toArray()[0].toString();
440 if (interfaceUUID == null) {
441 return new Status(StatusCode.INTERNALERROR);
444 Interface intf = new Interface();
445 intf.setType("patch");
446 OvsDBMap<String, String> options = new OvsDBMap<String, String>();
447 options.put("peer", peerPortName);
448 intf.setOptions(options);
449 return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, intf);
452 private Status addInternalBridge (Node node, String bridgeName, String localPatchName, String remotePatchName) throws Exception {
453 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
455 String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
456 Bridge bridge = new Bridge();
457 OvsDBSet<String> failMode = new OvsDBSet<String>();
458 failMode.add("secure");
459 bridge.setFail_mode(failMode);
461 OvsDBSet<String> protocols = new OvsDBSet<String>();
462 if (providerNetworkManager == null) {
463 logger.error("Provider Network Manager is not available");
464 return new Status(StatusCode.INTERNALERROR);
466 if (!providerNetworkManager.getProvider().hasPerTenantTunneling()) {
467 protocols.add("OpenFlow13");
469 protocols.add("OpenFlow10");
471 bridge.setProtocols(protocols);
473 if (bridgeUUID == null) {
474 bridge.setName(bridgeName);
476 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
477 if (!statusWithUuid.isSuccess()) return statusWithUuid;
478 bridgeUUID = statusWithUuid.getUuid().toString();
479 Port port = new Port();
480 port.setName(bridgeName);
481 Status status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
482 logger.debug("addInternalBridge: Inserting Bridge {} {} with protocols {} and status {}",
483 bridgeName, bridgeUUID, protocols, status);
485 Status status = ovsdbTable.updateRow(node, Bridge.NAME.getName(), null, bridgeUUID, bridge);
486 logger.debug("addInternalBridge: Updating Bridge {} {} with protocols {} and status {}",
487 bridgeName, bridgeUUID, protocols, status);
490 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
491 connectionService.setOFController(node, bridgeUUID);
493 if (localPatchName != null && remotePatchName != null && providerNetworkManager.getProvider().hasPerTenantTunneling()) {
494 return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
496 return new Status(StatusCode.SUCCESS);
499 public void prepareInternalNetwork(Node node) {
501 this.createIntegrationBridge(node);
502 } catch (Exception e) {
503 logger.error("Error creating internal network "+node.toString(), e);
505 if (providerNetworkManager == null) {
506 logger.error("Error creating internal network. Provider Network Manager unavailable");
509 providerNetworkManager.getProvider().initializeFlowRules(node);
513 * Check if the full network setup is available. If not, create it.
515 public boolean checkAndCreateNetwork (Node node, NeutronNetwork network) {
516 boolean isCreated = false;
517 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
518 if (!this.isInternalNetworkVlanReady(node, network)) {
520 isCreated = this.createNetNetwork(node, network);
521 } catch (Exception e) {
522 logger.error("Error creating internal net network ", node, e);
527 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
528 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
529 if (!this.isInternalNetworkTunnelReady(node)) {
531 isCreated = this.createNetNetwork(node, network);
532 } catch (Exception e) {
533 logger.error("Error creating internal net network ", node, e);