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.ovsdb.lib.error.SchemaVersionMismatchException;
14 import org.opendaylight.ovsdb.lib.notation.Row;
15 import org.opendaylight.ovsdb.lib.notation.UUID;
16 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
19 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.MdsalConsumer;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbConfigurationService;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusWithUuid;
26 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
27 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
28 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
29 import org.opendaylight.ovsdb.schema.openvswitch.Port;
30 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
32 import com.google.common.base.Preconditions;
33 import com.google.common.collect.Lists;
34 import com.google.common.collect.Maps;
35 import org.apache.commons.lang3.tuple.ImmutablePair;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import java.util.HashSet;
40 import java.util.List;
44 public class BridgeConfigurationManagerImpl implements BridgeConfigurationManager {
45 static final Logger LOGGER = LoggerFactory.getLogger(BridgeConfigurationManagerImpl.class);
47 // The implementation for each of these services is resolved by the OSGi Service Manager
48 private volatile ConfigurationService configurationService;
49 private volatile NetworkingProviderManager networkingProviderManager;
50 private volatile OvsdbConfigurationService ovsdbConfigurationService;
51 //private volatile MdsalConsumer mdsalConsumer;
53 public BridgeConfigurationManagerImpl() {
57 public String getBridgeUuid(Node node, String bridgeName) {
58 //Preconditions.checkNotNull(mdsalConsumer);
59 /* TODO SB_MIGRATION */
61 Map<String, Row> bridgeTable =
62 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
63 if (bridgeTable == null) {
66 for (String key : bridgeTable.keySet()) {
67 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
68 if (bridge.getName().equals(bridgeName)) {
72 } catch (Exception e) {
73 LOGGER.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
79 public boolean isNodeNeutronReady(Node node) {
80 Preconditions.checkNotNull(configurationService);
81 return this.getBridgeUuid(node, configurationService.getIntegrationBridgeName()) != null;
85 public boolean isNodeOverlayReady(Node node) {
86 /* TODO SB_MIGRATION */
87 Preconditions.checkNotNull(ovsdbConfigurationService);
88 return this.isNodeNeutronReady(node)
89 && this.getBridgeUuid(node, configurationService.getNetworkBridgeName()) != null;
93 public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
94 /* TODO SB_MIGRATION */
95 Preconditions.checkNotNull(ovsdbConfigurationService);
96 for (UUID portsUUID : bridge.getPortsColumn().getData()) {
98 Row portRow = ovsdbConfigurationService.getRow(node,
99 ovsdbConfigurationService.getTableName(node, Port.class),
100 portsUUID.toString());
102 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
103 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
106 } catch (Exception e) {
107 LOGGER.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
114 public boolean isNodeTunnelReady(Node node) {
115 Preconditions.checkNotNull(configurationService);
116 Preconditions.checkNotNull(networkingProviderManager);
118 /* Is br-int created? */
119 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
120 if (intBridge == null) {
124 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
125 /* Is br-net created? */
126 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
127 if (netBridge == null) {
131 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
139 public boolean isNodeVlanReady(Node node, NeutronNetwork network) {
140 /* TODO SB_MIGRATION */
141 Preconditions.checkNotNull(ovsdbConfigurationService);
142 Preconditions.checkNotNull(networkingProviderManager);
144 /* is br-int created */
145 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
146 if (intBridge == null) {
147 LOGGER.trace("isNodeVlanReady: node: {}, br-int missing", node);
151 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
152 /* is br-net created? */
153 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
155 if (netBridge == null) {
156 LOGGER.trace("isNodeVlanReady: node: {}, br-net missing", node);
160 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
161 LOGGER.trace("isNodeVlanReady: node: {}, patch missing", node);
165 /* Check if physical device is added to br-net. */
166 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
167 if (isPortOnBridge(node, netBridge, phyNetName)) {
171 /* Check if physical device is added to br-int. */
172 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
173 if (isPortOnBridge(node, intBridge, phyNetName)) {
178 LOGGER.trace("isNodeVlanReady: node: {}, eth missing", node);
183 public void prepareNode(Node node) {
184 Preconditions.checkNotNull(networkingProviderManager);
187 this.createIntegrationBridge(node);
188 } catch (Exception e) {
189 LOGGER.error("Error creating Integration Bridge on " + node.toString(), e);
192 if (networkingProviderManager == null) {
193 LOGGER.error("Error creating internal network. Provider Network Manager unavailable");
196 networkingProviderManager.getProvider(node).initializeFlowRules(node);
200 * Check if the full network setup is available. If not, create it.
203 public boolean createLocalNetwork (Node node, NeutronNetwork network) {
204 boolean isCreated = false;
205 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
206 if (!this.isNodeVlanReady(node, network)) {
208 isCreated = this.createBridges(node, network);
209 } catch (Exception e) {
210 LOGGER.error("Error creating internal net network " + node, e);
215 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
216 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
217 if (!this.isNodeTunnelReady(node)) {
219 isCreated = this.createBridges(node, network);
220 } catch (Exception e) {
221 LOGGER.error("Error creating internal net network " + node, e);
231 public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
233 /* TODO SB_MIGRATION */
235 Map<String, Row> ovsTable =
236 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
238 if (ovsTable == null) {
239 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
243 // Loop through all the Open_vSwitch rows looking for the first occurrence of other_config.
244 // The specification does not restrict the number of rows so we choose the first we find.
245 for (Row row : ovsTable.values()) {
247 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
248 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
250 if (configs == null) {
251 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
255 providerMaps = configs.get(configurationService.getProviderMappingsKey());
256 if (providerMaps == null) {
257 providerMaps = configurationService.getDefaultProviderMapping();
260 if (providerMaps != null) {
261 for (String map : providerMaps.split(",")) {
262 String[] pair = map.split(":");
263 if (pair[0].equals(physicalNetwork)) {
274 } catch (Exception e) {
275 LOGGER.error("Unable to find physical interface for Node: {}, Network {}",
276 node, physicalNetwork, e);
280 LOGGER.error("Physical interface not found for Node: {}, Network {}",
281 node, physicalNetwork);
288 public List<String> getAllPhysicalInterfaceNames(Node node) {
289 List<String> phyIfName = Lists.newArrayList();
290 /* TODO SB_MIGRATION */
292 Map<String, Row> ovsTable =
293 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
295 if (ovsTable == null) {
296 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
300 // While there is only one entry in the HashMap, we can't access it by index...
301 for (Row row : ovsTable.values()) {
303 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
304 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
306 if (configs == null) {
307 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
311 bridgeMaps = configs.get(configurationService.getProviderMappingsKey());
312 if (bridgeMaps == null) {
313 bridgeMaps = configurationService.getDefaultProviderMapping();
316 if (bridgeMaps != null) {
317 for (String map : bridgeMaps.split(",")) {
318 String[] pair = map.split(":");
319 phyIfName.add(pair[1]);
323 } catch (Exception e) {
324 LOGGER.error("Unable to find physical interface for Node: " + node, e);
327 LOGGER.debug("Physical interface for Node: {}, If: {}",
334 * Returns the Bridge for a given node and bridgeName
336 public Bridge getBridge (Node node, String bridgeName) {
337 /* TODO SB_MIGRATION */
338 Preconditions.checkNotNull(ovsdbConfigurationService);
340 Map<String, Row> bridgeTable =
341 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
342 if (bridgeTable != null) {
343 for (String key : bridgeTable.keySet()) {
344 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
345 if (bridge.getName().equals(bridgeName)) {
350 } catch (Exception e) {
351 LOGGER.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
358 * Returns true if a patch port exists between the Integration Bridge and Network Bridge
360 private boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
361 Preconditions.checkNotNull(configurationService);
363 boolean isPatchCreated = false;
365 String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
366 if (isPortOnBridge(node, intBridge, portName)) {
367 portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
368 if (isPortOnBridge(node, netBridge, portName)) {
369 isPatchCreated = true;
373 return isPatchCreated;
377 * Creates the Integration Bridge
379 private void createIntegrationBridge (Node node) throws Exception {
380 Preconditions.checkNotNull(configurationService);
382 String brInt = configurationService.getIntegrationBridgeName();
384 Status status = this.addBridge(node, brInt, null, null);
385 if (!status.isSuccess()) {
386 LOGGER.debug("Integration Bridge Creation Status: {}", status);
391 * Create and configure bridges for all network types and OpenFlow versions.
398 options: {peer=patch-int}
408 options: {peer=patch-net}
418 options: {peer=patch-int}
426 options: {peer=patch-net}
445 private boolean createBridges(Node node, NeutronNetwork network) throws Exception {
446 Preconditions.checkNotNull(configurationService);
447 Preconditions.checkNotNull(networkingProviderManager);
450 LOGGER.debug("createBridges: node: {}, network type: {}", node, network.getProviderNetworkType());
452 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) { /* indicates OF 1.0 */
453 String brInt = configurationService.getIntegrationBridgeName();
454 String brNet = configurationService.getNetworkBridgeName();
455 String patchNet = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brNet));
456 String patchInt = configurationService.getPatchPortName(new ImmutablePair<>(brNet, brInt));
458 status = this.addBridge(node, brInt, patchNet, patchInt);
459 if (!status.isSuccess()) {
460 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
463 status = this.addBridge(node, brNet, patchInt, patchNet);
464 if (!status.isSuccess()) {
465 LOGGER.debug("{} Bridge Creation Status: {}", brNet, status);
469 /* For vlan network types add physical port to br-net. */
470 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
471 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
472 status = addPortToBridge(node, brNet, phyNetName);
473 if (!status.isSuccess()) {
474 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
479 String brInt = configurationService.getIntegrationBridgeName();
480 status = this.addBridge(node, brInt, null, null);
481 if (!status.isSuccess()) {
482 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
486 /* For vlan network types add physical port to br-int. */
487 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
488 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
489 status = addPortToBridge(node, brInt, phyNetName);
490 if (!status.isSuccess()) {
491 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
497 LOGGER.debug("createNetNetwork: node: {}, status: success", node);
502 * Add a Port to a Bridge
504 private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
505 /* TODO SB_MIGRATION */
506 Preconditions.checkNotNull(ovsdbConfigurationService);
508 LOGGER.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
510 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
511 if (bridgeUUID == null) {
512 LOGGER.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
513 return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
516 /* Check if the port already exists. */
517 Row row = ovsdbConfigurationService
518 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
519 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
520 if (bridge != null) {
521 if (isPortOnBridge(node, bridge, portName)) {
522 LOGGER.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
523 return new Status(StatusCode.SUCCESS);
526 LOGGER.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
527 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
530 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
531 port.setName(portName);
532 StatusWithUuid statusWithUuid =
533 ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
534 if (!statusWithUuid.isSuccess()) {
535 LOGGER.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
536 return statusWithUuid;
539 String portUUID = statusWithUuid.getUuid().toString();
540 String interfaceUUID = null;
542 while ((interfaceUUID == null) && (timeout > 0)) {
543 Row portRow = ovsdbConfigurationService.getRow(node, port.getSchema().getName(), portUUID);
544 port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
545 Set<UUID> interfaces = port.getInterfacesColumn().getData();
546 if (interfaces == null || interfaces.size() == 0) {
547 // Wait for the OVSDB update to sync up the Local cache.
552 interfaceUUID = interfaces.toArray()[0].toString();
553 Row intf = ovsdbConfigurationService.getRow(node,
554 ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
556 interfaceUUID = null;
560 if (interfaceUUID == null) {
561 LOGGER.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
562 return new Status(StatusCode.INTERNALERROR);
565 return new Status(StatusCode.SUCCESS);
569 * Add a Patch Port to a Bridge
571 private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
572 /* TODO SB_MIGRATION */
573 Preconditions.checkNotNull(ovsdbConfigurationService);
575 LOGGER.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
576 node, bridgeUUID, portName, peerPortName);
578 /* Check if the port already exists. */
579 Row bridgeRow = ovsdbConfigurationService.getRow(node,
580 ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
581 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
582 if (bridge != null) {
583 if (isPortOnBridge(node, bridge, portName)) {
584 LOGGER.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
585 return new Status(StatusCode.SUCCESS);
588 LOGGER.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
589 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
592 Port patchPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
593 patchPort.setName(portName);
594 // Create patch port and interface
595 StatusWithUuid statusWithUuid =
596 ovsdbConfigurationService.insertRow(node, patchPort.getSchema().getName(), bridgeUUID, patchPort.getRow());
597 if (!statusWithUuid.isSuccess()) {
598 return statusWithUuid;
601 String patchPortUUID = statusWithUuid.getUuid().toString();
603 String interfaceUUID = null;
605 while ((interfaceUUID == null) && (timeout > 0)) {
606 Row portRow = ovsdbConfigurationService.getRow(node, patchPort.getSchema().getName(), patchPortUUID);
607 patchPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
608 Set<UUID> interfaces = patchPort.getInterfacesColumn().getData();
609 if (interfaces == null || interfaces.size() == 0) {
610 // Wait for the OVSDB update to sync up the Local cache.
615 interfaceUUID = interfaces.toArray()[0].toString();
618 if (interfaceUUID == null) {
619 return new Status(StatusCode.INTERNALERROR);
622 Interface intf = ovsdbConfigurationService.createTypedRow(node, Interface.class);
623 intf.setType("patch");
624 Map<String, String> options = Maps.newHashMap();
625 options.put("peer", peerPortName);
626 intf.setOptions(options);
627 return ovsdbConfigurationService.updateRow(node,
628 intf.getSchema().getName(),
636 * Add Bridge to a Node
638 private Status addBridge(Node node, String bridgeName,
639 String localPatchName, String remotePatchName) throws Exception {
640 Preconditions.checkNotNull(networkingProviderManager);
641 /* TODO SB_MIGRATION */
643 String bridgeUUID = getBridgeUuid(node, bridgeName);
644 Bridge bridge = ovsdbConfigurationService.createTypedRow(node, Bridge.class);
645 Set<String> failMode = new HashSet<>();
646 failMode.add("secure");
647 bridge.setFailMode(failMode);
649 Set<String> protocols = new HashSet<>();
651 /* ToDo: Plugin should expose an easy way to get the OVS Version or Schema Version
652 * or, alternatively it should not attempt to add set unsupported fields
656 protocols.add(Constants.OPENFLOW13);
657 bridge.setProtocols(protocols);
658 } catch (SchemaVersionMismatchException e) {
659 LOGGER.info("Failed to add protocol.", e);
662 if (bridgeUUID == null) {
663 bridge.setName(bridgeName);
665 StatusWithUuid statusWithUuid = ovsdbConfigurationService.insertRow(node,
666 bridge.getSchema().getName(),
669 if (!statusWithUuid.isSuccess()) {
670 return statusWithUuid;
672 bridgeUUID = statusWithUuid.getUuid().toString();
673 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
674 port.setName(bridgeName);
675 Status status = ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
676 LOGGER.debug("addBridge: Inserting Bridge {} {} with protocols {} and status {}",
677 bridgeName, bridgeUUID, protocols, status);
679 Status status = ovsdbConfigurationService.updateRow(node,
680 bridge.getSchema().getName(),
684 LOGGER.debug("addBridge: Updating Bridge {} {} with protocols {} and status {}",
685 bridgeName, bridgeUUID, protocols, status);
688 ovsdbConfigurationService.setOFController(node, bridgeUUID);
690 if (localPatchName != null &&
691 remotePatchName != null &&
692 networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
693 return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
695 return new Status(StatusCode.SUCCESS);