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.controller.md.sal.common.api.data.LogicalDatastoreType;
13 import org.opendaylight.neutron.spi.NeutronNetwork;
14 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
15 import org.opendaylight.ovsdb.lib.notation.Row;
16 import org.opendaylight.ovsdb.lib.notation.UUID;
17 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
19 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
20 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
21 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
22 import org.opendaylight.ovsdb.schema.openvswitch.Port;
23 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
28 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
30 import com.google.common.base.Preconditions;
31 import com.google.common.collect.Lists;
32 import com.google.common.collect.Maps;
33 import org.apache.commons.lang3.tuple.ImmutablePair;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import java.util.HashSet;
39 import java.util.List;
43 public class BridgeConfigurationManagerImpl implements BridgeConfigurationManager {
44 static final Logger LOGGER = LoggerFactory.getLogger(BridgeConfigurationManagerImpl.class);
46 // The implementation for each of these services is resolved by the OSGi Service Manager
47 private volatile ConfigurationService configurationService;
48 private volatile NetworkingProviderManager networkingProviderManager;
49 private volatile OvsdbConfigurationService ovsdbConfigurationService;
51 public BridgeConfigurationManagerImpl() {
55 public String getBridgeUuid(Node node, String bridgeName) {
56 return MdsalUtils.getBridgeUuid(node, bridgeName).toString();
60 public boolean isNodeNeutronReady(Node node) {
61 Preconditions.checkNotNull(configurationService);
62 return this.getBridgeUuid(node, configurationService.getIntegrationBridgeName()) != null;
66 public boolean isNodeOverlayReady(Node node) {
67 /* TODO SB_MIGRATION */
68 Preconditions.checkNotNull(ovsdbConfigurationService);
69 return this.isNodeNeutronReady(node)
70 && this.getBridgeUuid(node, configurationService.getNetworkBridgeName()) != null;
74 public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
75 /* TODO SB_MIGRATION */
76 Preconditions.checkNotNull(ovsdbConfigurationService);
77 for (UUID portsUUID : bridge.getPortsColumn().getData()) {
79 Row portRow = ovsdbConfigurationService.getRow(node,
80 ovsdbConfigurationService.getTableName(node, Port.class),
81 portsUUID.toString());
83 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
84 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
87 } catch (Exception e) {
88 LOGGER.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
95 public boolean isNodeTunnelReady(Node node) {
96 Preconditions.checkNotNull(configurationService);
97 Preconditions.checkNotNull(networkingProviderManager);
99 /* Is br-int created? */
100 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
101 if (intBridge == null) {
105 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
106 /* Is br-net created? */
107 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
108 if (netBridge == null) {
112 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
120 public boolean isNodeVlanReady(Node node, NeutronNetwork network) {
121 /* TODO SB_MIGRATION */
122 Preconditions.checkNotNull(ovsdbConfigurationService);
123 Preconditions.checkNotNull(networkingProviderManager);
125 /* is br-int created */
126 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
127 if (intBridge == null) {
128 LOGGER.trace("isNodeVlanReady: node: {}, br-int missing", node);
132 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
133 /* is br-net created? */
134 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
136 if (netBridge == null) {
137 LOGGER.trace("isNodeVlanReady: node: {}, br-net missing", node);
141 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
142 LOGGER.trace("isNodeVlanReady: node: {}, patch missing", node);
146 /* Check if physical device is added to br-net. */
147 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
148 if (isPortOnBridge(node, netBridge, phyNetName)) {
152 /* Check if physical device is added to br-int. */
153 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
154 if (isPortOnBridge(node, intBridge, phyNetName)) {
159 LOGGER.trace("isNodeVlanReady: node: {}, eth missing", node);
164 public void prepareNode(Node node) {
165 Preconditions.checkNotNull(networkingProviderManager);
168 this.createIntegrationBridge(node);
169 } catch (Exception e) {
170 LOGGER.error("Error creating Integration Bridge on {}", node, e);
173 networkingProviderManager.getProvider(node).initializeFlowRules(node);
177 * Check if the full network setup is available. If not, create it.
180 public boolean createLocalNetwork (Node node, NeutronNetwork network) {
181 boolean isCreated = false;
182 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
183 if (!this.isNodeVlanReady(node, network)) {
185 isCreated = this.createBridges(node, network);
186 } catch (Exception e) {
187 LOGGER.error("Error creating internal net network " + node, e);
192 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
193 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
194 if (!this.isNodeTunnelReady(node)) {
196 isCreated = this.createBridges(node, network);
197 } catch (Exception e) {
198 LOGGER.error("Error creating internal net network " + node, e);
208 public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
210 /* TODO SB_MIGRATION */
212 Map<String, Row> ovsTable =
213 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
215 if (ovsTable == null) {
216 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
220 // Loop through all the Open_vSwitch rows looking for the first occurrence of other_config.
221 // The specification does not restrict the number of rows so we choose the first we find.
222 for (Row row : ovsTable.values()) {
224 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
225 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
227 if (configs == null) {
228 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
232 providerMaps = configs.get(configurationService.getProviderMappingsKey());
233 if (providerMaps == null) {
234 providerMaps = configurationService.getDefaultProviderMapping();
237 if (providerMaps != null) {
238 for (String map : providerMaps.split(",")) {
239 String[] pair = map.split(":");
240 if (pair[0].equals(physicalNetwork)) {
251 } catch (Exception e) {
252 LOGGER.error("Unable to find physical interface for Node: {}, Network {}",
253 node, physicalNetwork, e);
257 LOGGER.error("Physical interface not found for Node: {}, Network {}",
258 node, physicalNetwork);
265 public List<String> getAllPhysicalInterfaceNames(Node node) {
266 List<String> phyIfName = Lists.newArrayList();
267 /* TODO SB_MIGRATION */
269 Map<String, Row> ovsTable =
270 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
272 if (ovsTable == null) {
273 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
277 // While there is only one entry in the HashMap, we can't access it by index...
278 for (Row row : ovsTable.values()) {
280 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
281 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
283 if (configs == null) {
284 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
288 bridgeMaps = configs.get(configurationService.getProviderMappingsKey());
289 if (bridgeMaps == null) {
290 bridgeMaps = configurationService.getDefaultProviderMapping();
293 if (bridgeMaps != null) {
294 for (String map : bridgeMaps.split(",")) {
295 String[] pair = map.split(":");
296 phyIfName.add(pair[1]);
300 } catch (Exception e) {
301 LOGGER.error("Unable to find physical interface for Node: " + node, e);
304 LOGGER.debug("Physical interface for Node: {}, If: {}",
311 * Returns the Bridge for a given node and bridgeName
313 public Bridge getBridge (Node node, String bridgeName) {
314 /* TODO SB_MIGRATION */
315 Preconditions.checkNotNull(ovsdbConfigurationService);
317 Map<String, Row> bridgeTable =
318 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
319 if (bridgeTable != null) {
320 for (String key : bridgeTable.keySet()) {
321 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
322 if (bridge.getName().equals(bridgeName)) {
327 } catch (Exception e) {
328 LOGGER.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
335 * Returns true if a patch port exists between the Integration Bridge and Network Bridge
337 private boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
338 Preconditions.checkNotNull(configurationService);
340 boolean isPatchCreated = false;
342 String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
343 if (isPortOnBridge(node, intBridge, portName)) {
344 portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
345 if (isPortOnBridge(node, netBridge, portName)) {
346 isPatchCreated = true;
350 return isPatchCreated;
354 * Creates the Integration Bridge
356 private void createIntegrationBridge (Node node) throws Exception {
357 Preconditions.checkNotNull(configurationService);
359 String brIntName = configurationService.getIntegrationBridgeName();
361 Status status = addBridge(node, brIntName, null, null);
362 if (!status.isSuccess()) {
363 LOGGER.debug("Integration Bridge Creation Status: {}", status);
368 * Create and configure bridges for all network types and OpenFlow versions.
375 options: {peer=patch-int}
385 options: {peer=patch-net}
395 options: {peer=patch-int}
403 options: {peer=patch-net}
422 private boolean createBridges(Node node, NeutronNetwork network) throws Exception {
423 Preconditions.checkNotNull(configurationService);
424 Preconditions.checkNotNull(networkingProviderManager);
427 LOGGER.debug("createBridges: node: {}, network type: {}", node, network.getProviderNetworkType());
429 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) { /* indicates OF 1.0 */
430 String brInt = configurationService.getIntegrationBridgeName();
431 String brNet = configurationService.getNetworkBridgeName();
432 String patchNet = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brNet));
433 String patchInt = configurationService.getPatchPortName(new ImmutablePair<>(brNet, brInt));
435 status = this.addBridge(node, brInt, patchNet, patchInt);
436 if (!status.isSuccess()) {
437 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
440 status = this.addBridge(node, brNet, patchInt, patchNet);
441 if (!status.isSuccess()) {
442 LOGGER.debug("{} Bridge Creation Status: {}", brNet, status);
446 /* For vlan network types add physical port to br-net. */
447 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
448 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
449 status = addPortToBridge(node, brNet, phyNetName);
450 if (!status.isSuccess()) {
451 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
456 String brInt = configurationService.getIntegrationBridgeName();
457 status = this.addBridge(node, brInt, null, null);
458 if (!status.isSuccess()) {
459 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
463 /* For vlan network types add physical port to br-int. */
464 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
465 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
466 status = addPortToBridge(node, brInt, phyNetName);
467 if (!status.isSuccess()) {
468 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
474 LOGGER.debug("createNetNetwork: node: {}, status: success", node);
479 * Add a Port to a Bridge
481 private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
482 /* TODO SB_MIGRATION */
483 Preconditions.checkNotNull(ovsdbConfigurationService);
485 LOGGER.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
487 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
488 if (bridgeUUID == null) {
489 LOGGER.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
490 return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
493 /* Check if the port already exists. */
494 Row row = ovsdbConfigurationService
495 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
496 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
497 if (bridge != null) {
498 if (isPortOnBridge(node, bridge, portName)) {
499 LOGGER.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
500 return new Status(StatusCode.SUCCESS);
503 LOGGER.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
504 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
507 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
508 port.setName(portName);
509 StatusWithUuid statusWithUuid =
510 ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
511 if (!statusWithUuid.isSuccess()) {
512 LOGGER.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
513 return statusWithUuid;
516 String portUUID = statusWithUuid.getUuid().toString();
517 String interfaceUUID = null;
519 while ((interfaceUUID == null) && (timeout > 0)) {
520 Row portRow = ovsdbConfigurationService.getRow(node, port.getSchema().getName(), portUUID);
521 port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
522 Set<UUID> interfaces = port.getInterfacesColumn().getData();
523 if (interfaces == null || interfaces.size() == 0) {
524 // Wait for the OVSDB update to sync up the Local cache.
529 interfaceUUID = interfaces.toArray()[0].toString();
530 Row intf = ovsdbConfigurationService.getRow(node,
531 ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
533 interfaceUUID = null;
537 if (interfaceUUID == null) {
538 LOGGER.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
539 return new Status(StatusCode.INTERNALERROR);
542 return new Status(StatusCode.SUCCESS);
546 * Add a Patch Port to a Bridge
548 private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
549 /* TODO SB_MIGRATION */
550 Preconditions.checkNotNull(ovsdbConfigurationService);
552 LOGGER.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
553 node, bridgeUUID, portName, peerPortName);
555 /* Check if the port already exists. */
556 Row bridgeRow = ovsdbConfigurationService.getRow(node,
557 ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
558 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
559 if (bridge != null) {
560 if (isPortOnBridge(node, bridge, portName)) {
561 LOGGER.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
562 return new Status(StatusCode.SUCCESS);
565 LOGGER.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
566 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
569 Port patchPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
570 patchPort.setName(portName);
571 // Create patch port and interface
572 StatusWithUuid statusWithUuid =
573 ovsdbConfigurationService.insertRow(node, patchPort.getSchema().getName(), bridgeUUID, patchPort.getRow());
574 if (!statusWithUuid.isSuccess()) {
575 return statusWithUuid;
578 String patchPortUUID = statusWithUuid.getUuid().toString();
580 String interfaceUUID = null;
582 while ((interfaceUUID == null) && (timeout > 0)) {
583 Row portRow = ovsdbConfigurationService.getRow(node, patchPort.getSchema().getName(), patchPortUUID);
584 patchPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
585 Set<UUID> interfaces = patchPort.getInterfacesColumn().getData();
586 if (interfaces == null || interfaces.size() == 0) {
587 // Wait for the OVSDB update to sync up the Local cache.
592 interfaceUUID = interfaces.toArray()[0].toString();
595 if (interfaceUUID == null) {
596 return new Status(StatusCode.INTERNALERROR);
599 Interface intf = ovsdbConfigurationService.createTypedRow(node, Interface.class);
600 intf.setType("patch");
601 Map<String, String> options = Maps.newHashMap();
602 options.put("peer", peerPortName);
603 intf.setOptions(options);
604 return ovsdbConfigurationService.updateRow(node,
605 intf.getSchema().getName(),
613 * Add Bridge to a Node
615 private Status addBridge(Node node, String bridgeName,
616 String localPatchName, String remotePatchName) throws Exception {
617 Preconditions.checkNotNull(networkingProviderManager);
618 /* TODO SB_MIGRATION */
620 //String bridgeUUID = getBridgeUuid(node, bridgeName);
621 MdsalUtils.addBridge(node, bridgeName);//sb will also add port and interface if this is a new bridge
624 /*// TODO use the bridge it code to add bridge
625 Bridge bridge = ovsdbConfigurationService.createTypedRow(node, Bridge.class);
626 Set<String> failMode = new HashSet<>();
627 failMode.add("secure");
628 bridge.setFailMode(failMode);
630 Set<String> protocols = new HashSet<>();
632 // ToDo: Plugin should expose an easy way to get the OVS Version or Schema Version
633 // or, alternatively it should not attempt to add set unsupported fields
637 protocols.add(Constants.OPENFLOW13);
638 bridge.setProtocols(protocols);
639 } catch (SchemaVersionMismatchException e) {
640 LOGGER.info("Failed to add protocol.", e);
643 if (bridgeUUID == null) {
644 bridge.setName(bridgeName);
646 StatusWithUuid statusWithUuid = ovsdbConfigurationService.insertRow(node,
647 bridge.getSchema().getName(),
650 if (!statusWithUuid.isSuccess()) {
651 return statusWithUuid;
653 bridgeUUID = statusWithUuid.getUuid().toString();
654 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
655 port.setName(bridgeName);
656 Status status = ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
657 LOGGER.debug("addBridge: Inserting Bridge {} {} with protocols {} and status {}",
658 bridgeName, bridgeUUID, protocols, status);
660 Status status = ovsdbConfigurationService.updateRow(node,
661 bridge.getSchema().getName(),
665 LOGGER.debug("addBridge: Updating Bridge {} {} with protocols {} and status {}",
666 bridgeName, bridgeUUID, protocols, status);
669 ovsdbConfigurationService.setOFController(node, bridgeUUID);
671 if (localPatchName != null &&
672 remotePatchName != null &&
673 networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
674 return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
676 return new Status(StatusCode.SUCCESS);