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.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.BridgeConfigurationManager;
19 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
22 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
23 import org.opendaylight.ovsdb.plugin.api.Status;
24 import org.opendaylight.ovsdb.plugin.api.StatusCode;
25 import org.opendaylight.ovsdb.plugin.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;
31 import com.google.common.base.Preconditions;
32 import com.google.common.collect.Lists;
33 import com.google.common.collect.Maps;
34 import org.apache.commons.lang3.tuple.ImmutablePair;
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 Preconditions.checkNotNull(ovsdbConfigurationService);
58 Map<String, Row> bridgeTable =
59 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
60 if (bridgeTable == null) {
63 for (String key : bridgeTable.keySet()) {
64 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
65 if (bridge.getName().equals(bridgeName)) {
69 } catch (Exception e) {
70 LOGGER.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
76 public boolean isNodeNeutronReady(Node node) {
77 Preconditions.checkNotNull(configurationService);
78 return this.getBridgeUuid(node, configurationService.getIntegrationBridgeName()) != null;
82 public boolean isNodeOverlayReady(Node node) {
83 Preconditions.checkNotNull(ovsdbConfigurationService);
84 return this.isNodeNeutronReady(node)
85 && this.getBridgeUuid(node, configurationService.getNetworkBridgeName()) != null;
89 public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
90 Preconditions.checkNotNull(ovsdbConfigurationService);
91 for (UUID portsUUID : bridge.getPortsColumn().getData()) {
93 Row portRow = ovsdbConfigurationService.getRow(node,
94 ovsdbConfigurationService.getTableName(node, Port.class),
95 portsUUID.toString());
97 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
98 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
101 } catch (Exception e) {
102 LOGGER.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
110 public boolean isNodeTunnelReady(Node node) {
111 Preconditions.checkNotNull(configurationService);
112 Preconditions.checkNotNull(networkingProviderManager);
114 /* Is br-int created? */
115 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
116 if (intBridge == null) {
120 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
121 /* Is br-net created? */
122 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
123 if (netBridge == null) {
127 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
135 public boolean isNodeVlanReady(Node node, NeutronNetwork network) {
136 Preconditions.checkNotNull(ovsdbConfigurationService);
137 Preconditions.checkNotNull(networkingProviderManager);
139 /* is br-int created */
140 Bridge intBridge = this.getBridge(node, configurationService.getIntegrationBridgeName());
141 if (intBridge == null) {
142 LOGGER.trace("isNodeVlanReady: node: {}, br-int missing", node);
146 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
147 /* is br-net created? */
148 Bridge netBridge = this.getBridge(node, configurationService.getNetworkBridgeName());
150 if (netBridge == null) {
151 LOGGER.trace("isNodeVlanReady: node: {}, br-net missing", node);
155 if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
156 LOGGER.trace("isNodeVlanReady: node: {}, patch missing", node);
160 /* Check if physical device is added to br-net. */
161 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
162 if (isPortOnBridge(node, netBridge, phyNetName)) {
166 /* Check if physical device is added to br-int. */
167 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
168 if (isPortOnBridge(node, intBridge, phyNetName)) {
173 LOGGER.trace("isNodeVlanReady: node: {}, eth missing", node);
178 public void prepareNode(Node node) {
179 Preconditions.checkNotNull(networkingProviderManager);
182 this.createIntegrationBridge(node);
183 } catch (Exception e) {
184 LOGGER.error("Error creating Integration Bridge on " + node.toString(), e);
187 if (networkingProviderManager == null) {
188 LOGGER.error("Error creating internal network. Provider Network Manager unavailable");
191 networkingProviderManager.getProvider(node).initializeFlowRules(node);
195 * Check if the full network setup is available. If not, create it.
198 public boolean createLocalNetwork (Node node, NeutronNetwork network) {
199 boolean isCreated = false;
200 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
201 if (!this.isNodeVlanReady(node, network)) {
203 isCreated = this.createBridges(node, network);
204 } catch (Exception e) {
205 LOGGER.error("Error creating internal net network " + node, e);
210 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
211 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
212 if (!this.isNodeTunnelReady(node)) {
214 isCreated = this.createBridges(node, network);
215 } catch (Exception e) {
216 LOGGER.error("Error creating internal net network " + node, e);
226 public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
229 Map<String, Row> ovsTable =
230 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
232 if (ovsTable == null) {
233 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
237 // Loop through all the Open_vSwitch rows looking for the first occurrence of other_config.
238 // The specification does not restrict the number of rows so we choose the first we find.
239 for (Row row : ovsTable.values()) {
241 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
242 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
244 if (configs == null) {
245 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
249 providerMaps = configs.get(configurationService.getProviderMappingsKey());
250 if (providerMaps == null) {
251 providerMaps = configurationService.getDefaultProviderMapping();
254 if (providerMaps != null) {
255 for (String map : providerMaps.split(",")) {
256 String[] pair = map.split(":");
257 if (pair[0].equals(physicalNetwork)) {
268 } catch (Exception e) {
269 LOGGER.error("Unable to find physical interface for Node: {}, Network {}",
270 node, physicalNetwork, e);
274 LOGGER.error("Physical interface not found for Node: {}, Network {}",
275 node, physicalNetwork);
282 public List<String> getAllPhysicalInterfaceNames(Node node) {
283 List<String> phyIfName = Lists.newArrayList();
286 Map<String, Row> ovsTable =
287 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, OpenVSwitch.class));
289 if (ovsTable == null) {
290 LOGGER.error("OpenVSwitch table is null for Node {} ", node);
294 // While there is only one entry in the HashMap, we can't access it by index...
295 for (Row row : ovsTable.values()) {
297 OpenVSwitch ovsRow = ovsdbConfigurationService.getTypedRow(node, OpenVSwitch.class, row);
298 Map<String, String> configs = ovsRow.getOtherConfigColumn().getData();
300 if (configs == null) {
301 LOGGER.debug("OpenVSwitch table is null for Node {} ", node);
305 bridgeMaps = configs.get(configurationService.getProviderMappingsKey());
306 if (bridgeMaps == null) {
307 bridgeMaps = configurationService.getDefaultProviderMapping();
310 if (bridgeMaps != null) {
311 for (String map : bridgeMaps.split(",")) {
312 String[] pair = map.split(":");
313 phyIfName.add(pair[1]);
317 } catch (Exception e) {
318 LOGGER.error("Unable to find physical interface for Node: " + node, e);
321 LOGGER.debug("Physical interface for Node: {}, If: {}",
328 * Returns the Bridge for a given node and bridgeName
330 public Bridge getBridge (Node node, String bridgeName) {
331 Preconditions.checkNotNull(ovsdbConfigurationService);
333 Map<String, Row> bridgeTable =
334 ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
335 if (bridgeTable != null) {
336 for (String key : bridgeTable.keySet()) {
337 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
338 if (bridge.getName().equals(bridgeName)) {
343 } catch (Exception e) {
344 LOGGER.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
350 * Returns true if a patch port exists between the Integration Bridge and Network Bridge
352 private boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
353 Preconditions.checkNotNull(configurationService);
355 boolean isPatchCreated = false;
357 String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
358 if (isPortOnBridge(node, intBridge, portName)) {
359 portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
360 if (isPortOnBridge(node, netBridge, portName)) {
361 isPatchCreated = true;
365 return isPatchCreated;
369 * Creates the Integration Bridge
371 private void createIntegrationBridge (Node node) throws Exception {
372 Preconditions.checkNotNull(configurationService);
374 String brInt = configurationService.getIntegrationBridgeName();
376 Status status = this.addBridge(node, brInt, null, null);
377 if (!status.isSuccess()) {
378 LOGGER.debug("Integration Bridge Creation Status: {}", status);
383 * Create and configure bridges for all network types and OpenFlow versions.
390 options: {peer=patch-int}
400 options: {peer=patch-net}
410 options: {peer=patch-int}
418 options: {peer=patch-net}
437 private boolean createBridges(Node node, NeutronNetwork network) throws Exception {
438 Preconditions.checkNotNull(configurationService);
439 Preconditions.checkNotNull(networkingProviderManager);
442 LOGGER.debug("createBridges: node: {}, network type: {}", node, network.getProviderNetworkType());
444 if (networkingProviderManager.getProvider(node).hasPerTenantTunneling()) { /* indicates OF 1.0 */
445 String brInt = configurationService.getIntegrationBridgeName();
446 String brNet = configurationService.getNetworkBridgeName();
447 String patchNet = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brNet));
448 String patchInt = configurationService.getPatchPortName(new ImmutablePair<>(brNet, brInt));
450 status = this.addBridge(node, brInt, patchNet, patchInt);
451 if (!status.isSuccess()) {
452 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
455 status = this.addBridge(node, brNet, patchInt, patchNet);
456 if (!status.isSuccess()) {
457 LOGGER.debug("{} Bridge Creation Status: {}", brNet, status);
461 /* For vlan network types add physical port to br-net. */
462 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
463 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
464 status = addPortToBridge(node, brNet, phyNetName);
465 if (!status.isSuccess()) {
466 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
471 String brInt = configurationService.getIntegrationBridgeName();
472 status = this.addBridge(node, brInt, null, null);
473 if (!status.isSuccess()) {
474 LOGGER.debug("{} Bridge Creation Status: {}", brInt, status);
478 /* For vlan network types add physical port to br-int. */
479 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
480 String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
481 status = addPortToBridge(node, brInt, phyNetName);
482 if (!status.isSuccess()) {
483 LOGGER.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
489 LOGGER.debug("createNetNetwork: node: {}, status: success", node);
494 * Add a Port to a Bridge
496 private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
497 Preconditions.checkNotNull(ovsdbConfigurationService);
499 LOGGER.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
501 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
502 if (bridgeUUID == null) {
503 LOGGER.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
504 return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
507 /* Check if the port already exists. */
508 Row row = ovsdbConfigurationService
509 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
510 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
511 if (bridge != null) {
512 if (isPortOnBridge(node, bridge, portName)) {
513 LOGGER.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
514 return new Status(StatusCode.SUCCESS);
517 LOGGER.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
518 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
521 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
522 port.setName(portName);
523 StatusWithUuid statusWithUuid =
524 ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
525 if (!statusWithUuid.isSuccess()) {
526 LOGGER.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
527 return statusWithUuid;
530 String portUUID = statusWithUuid.getUuid().toString();
531 String interfaceUUID = null;
533 while ((interfaceUUID == null) && (timeout > 0)) {
534 Row portRow = ovsdbConfigurationService.getRow(node, port.getSchema().getName(), portUUID);
535 port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
536 Set<UUID> interfaces = port.getInterfacesColumn().getData();
537 if (interfaces == null || interfaces.size() == 0) {
538 // Wait for the OVSDB update to sync up the Local cache.
543 interfaceUUID = interfaces.toArray()[0].toString();
544 Row intf = ovsdbConfigurationService.getRow(node,
545 ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
547 interfaceUUID = null;
551 if (interfaceUUID == null) {
552 LOGGER.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
553 return new Status(StatusCode.INTERNALERROR);
556 return new Status(StatusCode.SUCCESS);
560 * Add a Patch Port to a Bridge
562 private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
563 Preconditions.checkNotNull(ovsdbConfigurationService);
565 LOGGER.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
566 node, bridgeUUID, portName, peerPortName);
568 /* Check if the port already exists. */
569 Row bridgeRow = ovsdbConfigurationService.getRow(node,
570 ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
571 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
572 if (bridge != null) {
573 if (isPortOnBridge(node, bridge, portName)) {
574 LOGGER.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
575 return new Status(StatusCode.SUCCESS);
578 LOGGER.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
579 return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
582 Port patchPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
583 patchPort.setName(portName);
584 // Create patch port and interface
585 StatusWithUuid statusWithUuid =
586 ovsdbConfigurationService.insertRow(node, patchPort.getSchema().getName(), bridgeUUID, patchPort.getRow());
587 if (!statusWithUuid.isSuccess()) {
588 return statusWithUuid;
591 String patchPortUUID = statusWithUuid.getUuid().toString();
593 String interfaceUUID = null;
595 while ((interfaceUUID == null) && (timeout > 0)) {
596 Row portRow = ovsdbConfigurationService.getRow(node, patchPort.getSchema().getName(), patchPortUUID);
597 patchPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
598 Set<UUID> interfaces = patchPort.getInterfacesColumn().getData();
599 if (interfaces == null || interfaces.size() == 0) {
600 // Wait for the OVSDB update to sync up the Local cache.
605 interfaceUUID = interfaces.toArray()[0].toString();
608 if (interfaceUUID == null) {
609 return new Status(StatusCode.INTERNALERROR);
612 Interface intf = ovsdbConfigurationService.createTypedRow(node, Interface.class);
613 intf.setType("patch");
614 Map<String, String> options = Maps.newHashMap();
615 options.put("peer", peerPortName);
616 intf.setOptions(options);
617 return ovsdbConfigurationService.updateRow(node,
618 intf.getSchema().getName(),
625 * Add Bridge to a Node
627 private Status addBridge(Node node, String bridgeName,
628 String localPatchName, String remotePatchName) throws Exception {
629 Preconditions.checkNotNull(ovsdbConfigurationService);
630 Preconditions.checkNotNull(networkingProviderManager);
632 String bridgeUUID = this.getBridgeUuid(node, bridgeName);
633 Bridge bridge = ovsdbConfigurationService.createTypedRow(node, Bridge.class);
634 Set<String> failMode = new HashSet<>();
635 failMode.add("secure");
636 bridge.setFailMode(failMode);
638 Set<String> protocols = new HashSet<>();
640 /* ToDo: Plugin should expose an easy way to get the OVS Version or Schema Version
641 * or, alternatively it should not attempt to add set unsupported fields
645 protocols.add(Constants.OPENFLOW13);
646 bridge.setProtocols(protocols);
647 } catch (SchemaVersionMismatchException e) {
648 LOGGER.info("Failed to add protocol.", e);
651 if (bridgeUUID == null) {
652 bridge.setName(bridgeName);
654 StatusWithUuid statusWithUuid = ovsdbConfigurationService.insertRow(node,
655 bridge.getSchema().getName(),
658 if (!statusWithUuid.isSuccess()) {
659 return statusWithUuid;
661 bridgeUUID = statusWithUuid.getUuid().toString();
662 Port port = ovsdbConfigurationService.createTypedRow(node, Port.class);
663 port.setName(bridgeName);
664 Status status = ovsdbConfigurationService.insertRow(node, port.getSchema().getName(), bridgeUUID, port.getRow());
665 LOGGER.debug("addBridge: Inserting Bridge {} {} with protocols {} and status {}",
666 bridgeName, bridgeUUID, protocols, status);
668 Status status = ovsdbConfigurationService.updateRow(node,
669 bridge.getSchema().getName(),
673 LOGGER.debug("addBridge: Updating Bridge {} {} with protocols {} and status {}",
674 bridgeName, bridgeUUID, protocols, status);
677 ovsdbConfigurationService.setOFController(node, bridgeUUID);
679 if (localPatchName != null &&
680 remotePatchName != null &&
681 networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
682 return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
684 return new Status(StatusCode.SUCCESS);