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.openstack.netvirt.impl;
12 import org.opendaylight.neutron.spi.NeutronNetwork;
13 import org.opendaylight.controller.sal.core.Node;
14 import org.opendaylight.controller.sal.utils.Status;
15 import org.opendaylight.controller.sal.utils.StatusCode;
16 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
17 import org.opendaylight.ovsdb.lib.notation.Row;
18 import org.opendaylight.ovsdb.lib.notation.UUID;
19 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
24 import org.opendaylight.ovsdb.compatibility.plugin.api.OvsdbConfigurationService;
25 import org.opendaylight.controller.sal.utils.Status;
26 import org.opendaylight.controller.sal.utils.StatusCode;
27 import org.opendaylight.ovsdb.compatibility.plugin.api.StatusWithUuid;
28 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
29 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
30 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
31 import org.opendaylight.ovsdb.schema.openvswitch.Port;
33 import com.google.common.base.Preconditions;
34 import com.google.common.collect.Lists;
35 import com.google.common.collect.Maps;
36 import org.apache.commons.lang3.tuple.ImmutablePair;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 import java.util.HashSet;
41 import java.util.List;
45 public class BridgeConfigurationManagerImpl implements BridgeConfigurationManager {
46 static final Logger LOGGER = LoggerFactory.getLogger(BridgeConfigurationManagerImpl.class);
48 // The implementation for each of these services is resolved by the OSGi Service Manager
49 private volatile ConfigurationService configurationService;
50 private volatile NetworkingProviderManager networkingProviderManager;
51 private volatile OvsdbConfigurationService ovsdbConfigurationService;
53 public BridgeConfigurationManagerImpl() {
57 public String getBridgeUuid(Node node, String bridgeName) {
58 Preconditions.checkNotNull(ovsdbConfigurationService);
60 Map<String, Row> bridgeTable =
61 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
62 if (bridgeTable == null) {
65 for (String key : bridgeTable.keySet()) {
66 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
67 if (bridge.getName().equals(bridgeName)) {
71 } catch (Exception e) {
72 LOGGER.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
78 public boolean isNodeNeutronReady(Node node) {
79 Preconditions.checkNotNull(configurationService);
80 return this.getBridgeUuid(node, configurationService.getIntegrationBridgeName()) != null;
84 public boolean isNodeOverlayReady(Node node) {
85 Preconditions.checkNotNull(ovsdbConfigurationService);
86 return this.isNodeNeutronReady(node)
87 && this.getBridgeUuid(node, configurationService.getNetworkBridgeName()) != null;
91 public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
92 Preconditions.checkNotNull(ovsdbConfigurationService);
93 for (UUID portsUUID : bridge.getPortsColumn().getData()) {
95 Row portRow = ovsdbConfigurationService.getRow(node,
96 ovsdbConfigurationService.getTableName(node, Port.class),
97 portsUUID.toString());
99 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
100 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
103 } catch (Exception e) {
104 LOGGER.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
112 public boolean isNodeTunnelReady(Node node) {
113 Preconditions.checkNotNull(configurationService);
114 Preconditions.checkNotNull(networkingProviderManager);
116 /* Is br-int created? */
117 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
118 if (intBridge == null) {
122 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
123 /* Is br-net created? */
124 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
125 if (netBridge == null) {
129 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
137 public boolean isNodeVlanReady(Node node, NeutronNetwork network) {
138 Preconditions.checkNotNull(ovsdbConfigurationService);
139 Preconditions.checkNotNull(networkingProviderManager);
141 /* is br-int created */
142 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
143 if (intBridge == null) {
144 LOGGER.trace("isNodeVlanReady: node: {}, br-int missing", node);
148 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
149 /* is br-net created? */
150 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
152 if (netBridge == null) {
153 LOGGER.trace("isNodeVlanReady: node: {}, br-net missing", node);
157 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
158 LOGGER.trace("isNodeVlanReady: node: {}, patch missing", node);
162 /* Check if physical device is added to br-net. */
163 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
164 if (isPortOnBridge(node, netBridge, phyNetName)) {
168 /* Check if physical device is added to br-int. */
169 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
170 if (isPortOnBridge(node, intBridge, phyNetName)) {
175 LOGGER.trace("isNodeVlanReady: node: {}, eth missing", node);
180 public void prepareNode(Node node) {
181 Preconditions.checkNotNull(networkingProviderManager);
184 this.createIntegrationBridge(node);
185 } catch (Exception e) {
186 LOGGER.error("Error creating Integration Bridge on " + node.toString(), e);
189 if (networkingProviderManager == null) {
190 LOGGER.error("Error creating internal network. Provider Network Manager unavailable");
193 networkingProviderManager.getProvider(node).initializeFlowRules(node);
197 * Check if the full network setup is available. If not, create it.
200 public boolean createLocalNetwork (Node node, NeutronNetwork network) {
201 boolean isCreated = false;
202 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
203 if (!this.isNodeVlanReady(node, network)) {
205 isCreated = this.createBridges(node, network);
206 } catch (Exception e) {
207 LOGGER.error("Error creating internal net network " + node, e);
212 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
213 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
214 if (!this.isNodeTunnelReady(node)) {
216 isCreated = this.createBridges(node, network);
217 } catch (Exception e) {
218 LOGGER.error("Error creating internal net network " + node, e);
228 public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
231 Map<String, Row> ovsTable =
232 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
234 if (ovsTable == null) {
235 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
239 // Loop through all the Open_vSwitch rows looking for the first occurrence of other_config.
240 // The specification does not restrict the number of rows so we choose the first we find.
241 for (Row row : ovsTable.values()) {
243 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
244 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
246 if (configs == null) {
247 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
251 providerMaps = configs.get(configurationService.getProviderMappingsKey());
252 if (providerMaps == null) {
253 providerMaps = configurationService.getDefaultProviderMapping();
256 if (providerMaps != null) {
257 for (String map : providerMaps.split(",")) {
258 String[] pair = map.split(":");
259 if (pair[0].equals(physicalNetwork)) {
270 } catch (Exception e) {
271 LOGGER.error("Unable to find physical interface for Node: {}, Network {}",
272 node, physicalNetwork, e);
276 LOGGER.error("Physical interface not found for Node: {}, Network {}",
277 node, physicalNetwork);
284 public List<String> getAllPhysicalInterfaceNames(Node node) {
285 List<String> phyIfName = Lists.newArrayList();
288 Map<String, Row> ovsTable =
289 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
291 if (ovsTable == null) {
292 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
296 // While there is only one entry in the HashMap, we can't access it by index...
297 for (Row row : ovsTable.values()) {
299 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
300 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
302 if (configs == null) {
303 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
307 bridgeMaps = configs.get(configurationService.getProviderMappingsKey());
308 if (bridgeMaps == null) {
309 bridgeMaps = configurationService.getDefaultProviderMapping();
312 if (bridgeMaps != null) {
313 for (String map : bridgeMaps.split(",")) {
314 String[] pair = map.split(":");
315 phyIfName.add(pair[1]);
319 } catch (Exception e) {
320 LOGGER.error("Unable to find physical interface for Node: " + node, e);
323 LOGGER.debug("Physical interface for Node: {}, If: {}",
330 * Returns the Bridge for a given node and bridgeName
332 public Bridge getBridge (Node node, String bridgeName) {
333 Preconditions.checkNotNull(ovsdbConfigurationService);
335 Map<String, Row> bridgeTable =
336 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
337 if (bridgeTable != null) {
338 for (String key : bridgeTable.keySet()) {
339 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
340 if (bridge.getName().equals(bridgeName)) {
345 } catch (Exception e) {
346 LOGGER.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
352 * Returns true if a patch port exists between the Integration Bridge and Network Bridge
354 private boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
355 Preconditions.checkNotNull(configurationService);
357 boolean isPatchCreated = false;
359 String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
360 if (isPortOnBridge(node, intBridge, portName)) {
361 portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
362 if (isPortOnBridge(node, netBridge, portName)) {
363 isPatchCreated = true;
367 return isPatchCreated;
371 * Creates the Integration Bridge
373 private void createIntegrationBridge (Node node) throws Exception {
374 Preconditions.checkNotNull(configurationService);
376 String brInt = configurationService.getIntegrationBridgeName();
378 Status status = this.addBridge(node, brInt, null, null);
379 if (!status.isSuccess()) {
380 LOGGER.debug("Integration Bridge Creation Status: {}", status);
385 * Create and configure bridges for all network types and OpenFlow versions.
392 options: {peer=patch-int}
402 options: {peer=patch-net}
412 options: {peer=patch-int}
420 options: {peer=patch-net}
439 private boolean createBridges(Node node, NeutronNetwork network) throws Exception {
440 Preconditions.checkNotNull(configurationService);
441 Preconditions.checkNotNull(networkingProviderManager);
444 LOGGER.debug("createBridges: node: {}, network type: {}", node, network.getProviderNetworkType());
446 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) { /* indicates OF 1.0 */
447 String brInt = configurationService.getIntegrationBridgeName();
448 String brNet = configurationService.getNetworkBridgeName();
449 String patchNet = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brNet));
450 String patchInt = configurationService.getPatchPortName(new ImmutablePair<>(brNet, brInt));
452 status = this.addBridge(node, brInt, patchNet, patchInt);
453 if (!status.isSuccess()) {
454 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
457 status = this.addBridge(node, brNet, patchInt, patchNet);
458 if (!status.isSuccess()) {
459 LOGGER.debug("{} Bridge Creation Status: {}", brNet, status);
463 /* For vlan network types add physical port to br-net. */
464 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
465 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
466 status = addPortToBridge(node, brNet, phyNetName);
467 if (!status.isSuccess()) {
468 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
473 String brInt = configurationService.getIntegrationBridgeName();
474 status = this.addBridge(node, brInt, null, null);
475 if (!status.isSuccess()) {
476 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
480 /* For vlan network types add physical port to br-int. */
481 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
482 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
483 status = addPortToBridge(node, brInt, phyNetName);
484 if (!status.isSuccess()) {
485 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
491 LOGGER.debug("createNetNetwork: node: {}, status: success", node);
496 * Add a Port to a Bridge
498 private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
499 Preconditions.checkNotNull(ovsdbConfigurationService);
501 LOGGER.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
503 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
504 if (bridgeUUID == null) {
505 LOGGER.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
506 return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
509 /* Check if the port already exists. */
510 Row row = ovsdbConfigurationService
511 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
512 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
513 if (bridge != null) {
514 if (isPortOnBridge(node, bridge, portName)) {
515 LOGGER.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
516 return new Status(StatusCode.SUCCESS);
519 LOGGER.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
520 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
523 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
524 port.setName(portName);
525 StatusWithUuid statusWithUuid =
526 ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
527 if (!statusWithUuid.isSuccess()) {
528 LOGGER.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
529 return statusWithUuid;
532 String portUUID = statusWithUuid.getUuid().toString();
533 String interfaceUUID = null;
535 while ((interfaceUUID == null) && (timeout > 0)) {
536 Row portRow = ovsdbConfigurationService.getRow(node, port.getSchema().getName(), portUUID);
537 port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
538 Set<UUID> interfaces = port.getInterfacesColumn().getData();
539 if (interfaces == null || interfaces.size() == 0) {
540 // Wait for the OVSDB update to sync up the Local cache.
545 interfaceUUID = interfaces.toArray()[0].toString();
546 Row intf = ovsdbConfigurationService.getRow(node,
547 ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
549 interfaceUUID = null;
553 if (interfaceUUID == null) {
554 LOGGER.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
555 return new Status(StatusCode.INTERNALERROR);
558 return new Status(StatusCode.SUCCESS);
562 * Add a Patch Port to a Bridge
564 private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
565 Preconditions.checkNotNull(ovsdbConfigurationService);
567 LOGGER.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
568 node, bridgeUUID, portName, peerPortName);
570 /* Check if the port already exists. */
571 Row bridgeRow = ovsdbConfigurationService.getRow(node,
572 ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
573 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
574 if (bridge != null) {
575 if (isPortOnBridge(node, bridge, portName)) {
576 LOGGER.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
577 return new Status(StatusCode.SUCCESS);
580 LOGGER.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
581 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
584 Port patchPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
585 patchPort.setName(portName);
586 // Create patch port and interface
587 StatusWithUuid statusWithUuid =
588 ovsdbConfigurationService.insertRow(node, patchPort.getSchema().getName(), bridgeUUID, patchPort.getRow());
589 if (!statusWithUuid.isSuccess()) {
590 return statusWithUuid;
593 String patchPortUUID = statusWithUuid.getUuid().toString();
595 String interfaceUUID = null;
597 while ((interfaceUUID == null) && (timeout > 0)) {
598 Row portRow = ovsdbConfigurationService.getRow(node, patchPort.getSchema().getName(), patchPortUUID);
599 patchPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
600 Set<UUID> interfaces = patchPort.getInterfacesColumn().getData();
601 if (interfaces == null || interfaces.size() == 0) {
602 // Wait for the OVSDB update to sync up the Local cache.
607 interfaceUUID = interfaces.toArray()[0].toString();
610 if (interfaceUUID == null) {
611 return new Status(StatusCode.INTERNALERROR);
614 Interface intf = ovsdbConfigurationService.createTypedRow(node, Interface.class);
615 intf.setType("patch");
616 Map<String, String> options = Maps.newHashMap();
617 options.put("peer", peerPortName);
618 intf.setOptions(options);
619 return ovsdbConfigurationService.updateRow(node,
620 intf.getSchema().getName(),
627 * Add Bridge to a Node
629 private Status addBridge(Node node, String bridgeName,
630 String localPatchName, String remotePatchName) throws Exception {
631 Preconditions.checkNotNull(ovsdbConfigurationService);
632 Preconditions.checkNotNull(networkingProviderManager);
634 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
635 Bridge bridge = ovsdbConfigurationService.createTypedRow(node, Bridge.class);
636 Set<String> failMode = new HashSet<>();
637 failMode.add("secure");
638 bridge.setFailMode(failMode);
640 Set<String> protocols = new HashSet<>();
642 /* ToDo: Plugin should expose an easy way to get the OVS Version or Schema Version
643 * or, alternatively it should not attempt to add set unsupported fields
647 protocols.add(Constants.OPENFLOW13);
648 bridge.setProtocols(protocols);
649 } catch (SchemaVersionMismatchException e) {
650 LOGGER.info("Failed to add protocol.", e);
653 if (bridgeUUID == null) {
654 bridge.setName(bridgeName);
656 StatusWithUuid statusWithUuid = ovsdbConfigurationService.insertRow(node,
657 bridge.getSchema().getName(),
660 if (!statusWithUuid.isSuccess()) {
661 return statusWithUuid;
663 bridgeUUID = statusWithUuid.getUuid().toString();
664 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
665 port.setName(bridgeName);
666 Status status = ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
667 LOGGER.debug("addBridge: Inserting Bridge {} {} with protocols {} and status {}",
668 bridgeName, bridgeUUID, protocols, status);
670 Status status = ovsdbConfigurationService.updateRow(node,
671 bridge.getSchema().getName(),
675 LOGGER.debug("addBridge: Updating Bridge {} {} with protocols {} and status {}",
676 bridgeName, bridgeUUID, protocols, status);
679 ovsdbConfigurationService.setOFController(node, bridgeUUID);
681 if (localPatchName != null &&
682 remotePatchName != null &&
683 networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
684 return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
686 return new Status(StatusCode.SUCCESS);