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.networkconfig.neutron.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.Constants;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
23 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
24 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
25 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
26 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
27 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
28 import org.opendaylight.ovsdb.schema.openvswitch.Port;
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.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import java.util.HashSet;
38 import java.util.List;
42 public class BridgeConfigurationManagerImpl implements BridgeConfigurationManager {
43 static final Logger logger = LoggerFactory.getLogger(BridgeConfigurationManagerImpl.class);
45 // The implementation for each of these services is resolved by the OSGi Service Manager
46 private volatile org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService configurationService;
47 private volatile NetworkingProviderManager networkingProviderManager;
48 private volatile OvsdbConfigurationService ovsdbConfigurationService;
50 public BridgeConfigurationManagerImpl() {
54 public String getBridgeUuid(Node node, String bridgeName) {
55 Preconditions.checkNotNull(ovsdbConfigurationService);
57 Map<String, Row> bridgeTable =
58 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
59 if (bridgeTable == null) return null;
60 for (String key : bridgeTable.keySet()) {
61 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
62 if (bridge.getName().equals(bridgeName)) return key;
64 } catch (Exception e) {
65 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
71 public boolean isNodeNeutronReady(Node node) {
72 Preconditions.checkNotNull(configurationService);
73 return this.getBridgeUuid(node, configurationService.getIntegrationBridgeName()) != null;
77 public boolean isNodeOverlayReady(Node node) {
78 Preconditions.checkNotNull(ovsdbConfigurationService);
79 return this.isNodeNeutronReady(node)
80 && this.getBridgeUuid(node, configurationService.getNetworkBridgeName()) != null;
84 public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
85 Preconditions.checkNotNull(ovsdbConfigurationService);
86 for (UUID portsUUID : bridge.getPortsColumn().getData()) {
88 Row portRow = ovsdbConfigurationService.getRow(node,
89 ovsdbConfigurationService.getTableName(node, Port.class),
90 portsUUID.toString());
92 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
93 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
96 } catch (Exception e) {
97 logger.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
105 public boolean isNodeTunnelReady(Node node) {
106 Preconditions.checkNotNull(configurationService);
107 Preconditions.checkNotNull(networkingProviderManager);
109 /* Is br-int created? */
110 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
111 if (intBridge == null) {
115 if (networkingProviderManager == null) {
116 logger.error("Provider Network Manager is not available");
119 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
120 /* Is br-net created? */
121 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
122 if (netBridge == null) {
126 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
134 public boolean isNodeVlanReady(Node node, NeutronNetwork network) {
135 Preconditions.checkNotNull(ovsdbConfigurationService);
136 Preconditions.checkNotNull(networkingProviderManager);
138 /* is br-int created */
139 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
140 if (intBridge == null) {
141 logger.trace("isNodeVlanReady: node: {}, br-int missing", node);
145 if (networkingProviderManager == null) {
146 logger.error("Provider Network Manager is not available");
149 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
150 /* is br-net created? */
151 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
153 if (netBridge == null) {
154 logger.trace("isNodeVlanReady: node: {}, br-net missing", node);
158 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
159 logger.trace("isNodeVlanReady: node: {}, patch missing", node);
163 /* Check if physical device is added to br-net. */
164 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
165 if (isPortOnBridge(node, netBridge, phyNetName)) {
169 /* Check if physical device is added to br-int. */
170 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
171 if (isPortOnBridge(node, intBridge, phyNetName)) {
176 logger.trace("isNodeVlanReady: node: {}, eth missing", node);
181 public void prepareNode(Node node) {
182 Preconditions.checkNotNull(networkingProviderManager);
185 this.createIntegrationBridge(node);
186 } catch (Exception e) {
187 logger.error("Error creating Integration Bridge on " + node.toString(), e);
190 if (networkingProviderManager == null) {
191 logger.error("Error creating internal network. Provider Network Manager unavailable");
194 networkingProviderManager.getProvider(node).initializeFlowRules(node);
198 * Check if the full network setup is available. If not, create it.
201 public boolean createLocalNetwork (Node node, NeutronNetwork network) {
202 boolean isCreated = false;
203 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
204 if (!this.isNodeVlanReady(node, network)) {
206 isCreated = this.createBridges(node, network);
207 } catch (Exception e) {
208 logger.error("Error creating internal net network ", node, e);
213 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
214 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
215 if (!this.isNodeTunnelReady(node)) {
217 isCreated = this.createBridges(node, network);
218 } catch (Exception e) {
219 logger.error("Error creating internal net network ", node, e);
229 public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
232 Map<String, Row> ovsTable =
233 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
235 if (ovsTable == null) {
236 logger.error("OpenVSwitch table is null for Node {} ", node);
240 // Loop through all the Open_vSwitch rows looking for the first occurrence of other_config.
241 // The specification does not restrict the number of rows so we choose the first we find.
242 for (Row row : ovsTable.values()) {
244 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
245 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
247 if (configs == null) {
248 logger.debug("OpenVSwitch table is null for Node {} ", node);
252 providerMaps = configs.get(configurationService.getProviderMappingsKey());
253 if (providerMaps == null) {
254 providerMaps = configurationService.getDefaultProviderMapping();
257 if (providerMaps != null) {
258 for (String map : providerMaps.split(",")) {
259 String[] pair = map.split(":");
260 if (pair[0].equals(physicalNetwork)) {
271 } catch (Exception e) {
272 logger.error("Unable to find physical interface for Node: {}, Network {}",
273 node, physicalNetwork, e);
277 logger.error("Physical interface not found for Node: {}, Network {}",
278 node, physicalNetwork);
285 public List<String> getAllPhysicalInterfaceNames(Node node) {
286 List<String> phyIfName = Lists.newArrayList();
289 Map<String, Row> ovsTable =
290 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
292 if (ovsTable == null) {
293 logger.error("OpenVSwitch table is null for Node {} ", node);
297 // While there is only one entry in the HashMap, we can't access it by index...
298 for (Row row : ovsTable.values()) {
300 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
301 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
303 if (configs == null) {
304 logger.debug("OpenVSwitch table is null for Node {} ", node);
308 bridgeMaps = configs.get(configurationService.getProviderMappingsKey());
309 if (bridgeMaps == null) {
310 bridgeMaps = configurationService.getDefaultProviderMapping();
313 if (bridgeMaps != null) {
314 for (String map : bridgeMaps.split(",")) {
315 String[] pair = map.split(":");
316 phyIfName.add(pair[1]);
320 } catch (Exception e) {
321 logger.error("Unable to find physical interface for Node: {}",
325 logger.debug("Physical interface for Node: {}, If: {}",
332 * Returns the Bridge for a given node and bridgeName
334 public Bridge getBridge (Node node, String bridgeName) {
335 Preconditions.checkNotNull(ovsdbConfigurationService);
337 Map<String, Row> bridgeTable =
338 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
339 if (bridgeTable != null) {
340 for (String key : bridgeTable.keySet()) {
341 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
342 if (bridge.getName().equals(bridgeName)) {
347 } catch (Exception e) {
348 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
354 * Returns true if a patch port exists between the Integration Bridge and Network Bridge
356 private boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
357 Preconditions.checkNotNull(ovsdbConfigurationService);
359 boolean isPatchCreated = false;
361 String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
362 if (isPortOnBridge(node, intBridge, portName)) {
363 portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
364 if (isPortOnBridge(node, netBridge, portName)) {
365 isPatchCreated = true;
369 return isPatchCreated;
373 * Creates the Integration Bridge
375 private void createIntegrationBridge (Node node) throws Exception {
376 Preconditions.checkNotNull(ovsdbConfigurationService);
378 String brInt = configurationService.getIntegrationBridgeName();
380 Status status = this.addBridge(node, brInt, null, null);
381 if (!status.isSuccess()) {
382 logger.debug("Integration Bridge Creation Status: {}", status);
387 * Create and configure bridges for all network types and OpenFlow versions.
394 options: {peer=patch-int}
404 options: {peer=patch-net}
414 options: {peer=patch-int}
422 options: {peer=patch-net}
441 private boolean createBridges(Node node, NeutronNetwork network) throws Exception {
442 Preconditions.checkNotNull(ovsdbConfigurationService);
443 Preconditions.checkNotNull(networkingProviderManager);
446 logger.debug("createBridges: node: {}, network type: {}", node, network.getProviderNetworkType());
448 if (networkingProviderManager == null) {
449 logger.error("Provider Network Manager is not available");
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 Preconditions.checkNotNull(ovsdbConfigurationService);
507 logger.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
509 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
510 if (bridgeUUID == null) {
511 logger.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
512 return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
515 /* Check if the port already exists. */
516 Row row = ovsdbConfigurationService
517 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
518 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
519 if (bridge != null) {
520 if (isPortOnBridge(node, bridge, portName)) {
521 logger.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
522 return new Status(StatusCode.SUCCESS);
525 logger.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
526 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
529 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
530 port.setName(portName);
531 StatusWithUuid statusWithUuid =
532 ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
533 if (!statusWithUuid.isSuccess()) {
534 logger.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
535 return statusWithUuid;
538 String portUUID = statusWithUuid.getUuid().toString();
539 String interfaceUUID = null;
541 while ((interfaceUUID == null) && (timeout > 0)) {
542 Row portRow = ovsdbConfigurationService.getRow(node, port.getSchema().getName(), portUUID);
543 port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
544 Set<UUID> interfaces = port.getInterfacesColumn().getData();
545 if (interfaces == null || interfaces.size() == 0) {
546 // Wait for the OVSDB update to sync up the Local cache.
551 interfaceUUID = interfaces.toArray()[0].toString();
552 Row intf = ovsdbConfigurationService.getRow(node,
553 ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
555 interfaceUUID = null;
559 if (interfaceUUID == null) {
560 logger.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
561 return new Status(StatusCode.INTERNALERROR);
564 return new Status(StatusCode.SUCCESS);
568 * Add a Patch Port to a Bridge
570 private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
571 Preconditions.checkNotNull(ovsdbConfigurationService);
573 logger.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
574 node, bridgeUUID, portName, peerPortName);
576 /* Check if the port already exists. */
577 Row bridgeRow = ovsdbConfigurationService.getRow(node,
578 ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
579 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
580 if (bridge != null) {
581 if (isPortOnBridge(node, bridge, portName)) {
582 logger.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
583 return new Status(StatusCode.SUCCESS);
586 logger.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
587 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
590 Port patchPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
591 patchPort.setName(portName);
592 // Create patch port and interface
593 StatusWithUuid statusWithUuid =
594 ovsdbConfigurationService.insertRow(node, patchPort.getSchema().getName(), bridgeUUID, patchPort.getRow());
595 if (!statusWithUuid.isSuccess()) return statusWithUuid;
597 String patchPortUUID = statusWithUuid.getUuid().toString();
599 String interfaceUUID = null;
601 while ((interfaceUUID == null) && (timeout > 0)) {
602 Row portRow = ovsdbConfigurationService.getRow(node, patchPort.getSchema().getName(), patchPortUUID);
603 patchPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
604 Set<UUID> interfaces = patchPort.getInterfacesColumn().getData();
605 if (interfaces == null || interfaces.size() == 0) {
606 // Wait for the OVSDB update to sync up the Local cache.
611 interfaceUUID = interfaces.toArray()[0].toString();
614 if (interfaceUUID == null) {
615 return new Status(StatusCode.INTERNALERROR);
618 Interface intf = ovsdbConfigurationService.createTypedRow(node, Interface.class);
619 intf.setType("patch");
620 Map<String, String> options = Maps.newHashMap();
621 options.put("peer", peerPortName);
622 intf.setOptions(options);
623 return ovsdbConfigurationService.updateRow(node,
624 intf.getSchema().getName(),
631 * Add Bridge to a Node
633 private Status addBridge(Node node, String bridgeName,
634 String localPatchName, String remotePatchName) throws Exception {
635 Preconditions.checkNotNull(ovsdbConfigurationService);
637 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
638 Bridge bridge = ovsdbConfigurationService.createTypedRow(node, Bridge.class);
639 Set<String> failMode = new HashSet<>();
640 failMode.add("secure");
641 bridge.setFailMode(failMode);
643 Set<String> protocols = new HashSet<>();
644 if (networkingProviderManager == null) {
645 logger.error("Provider Network Manager is not available");
646 return new Status(StatusCode.INTERNALERROR);
649 /* ToDo: Plugin should expose an easy way to get the OVS Version or Schema Version
650 * or, alternatively it should not attempt to add set unsupported fields
654 if (!networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
655 protocols.add(Constants.OPENFLOW13);
657 protocols.add(Constants.OPENFLOW10);
659 bridge.setProtocols(protocols);
660 } catch (SchemaVersionMismatchException e) {
661 logger.info(e.toString());
664 if (bridgeUUID == null) {
665 bridge.setName(bridgeName);
667 StatusWithUuid statusWithUuid = ovsdbConfigurationService.insertRow(node,
668 bridge.getSchema().getName(),
671 if (!statusWithUuid.isSuccess()) 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);