41caf64514f46f9bc8ca810a9f14ad8da9b557a7
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanBridgeManager.java
1 /*
2  * Copyright (c) 2016, 2017 Red Hat, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.elan.internal;
9
10 import com.google.common.base.Splitter;
11 import com.google.common.base.Strings;
12 import com.google.common.collect.Lists;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Optional;
21 import java.util.Random;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
30 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
31 import org.opendaylight.genius.itm.globals.ITMConstants;
32 import org.opendaylight.genius.mdsalutil.MDSALUtil;
33 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeNetdev;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.Uint64;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 /**
56  * This class provides functions for creating bridges via OVSDB, specifically the br-int bridge.
57  */
58 @Singleton
59 // Checkstyle expects the first sentence to end with a period, question marks don’t count
60 @SuppressWarnings("checkstyle:SummaryJavadoc")
61 public class ElanBridgeManager {
62     private static final Logger LOG = LoggerFactory.getLogger(ElanBridgeManager.class);
63
64     public static final String PROVIDER_MAPPINGS_KEY = "provider_mappings";
65     private static final String INTEGRATION_BRIDGE = "br-int";
66     private static final String INT_SIDE_PATCH_PORT_SUFFIX = "-patch";
67     private static final String EX_SIDE_PATCH_PORT_SUFFIX = "-int-patch";
68     private static final String OTHER_CONFIG_PARAMETERS_DELIMITER = ",";
69     private static final String OTHER_CONFIG_KEY_VALUE_DELIMITER = ":";
70     private static final int MAX_LINUX_INTERFACE_NAME_LENGTH = 15;
71     private static final String OTHER_CONFIG_DATAPATH_ID = "datapath-id";
72     private static final String OTHER_CONFIG_HWADDR = "hwaddr";
73     private static final String OTHER_CONFIG_DISABLE_IN_BAND = "disable-in-band";
74
75     private final DataBroker dataBroker;
76     private final IInterfaceManager interfaceManager;
77     private final SouthboundUtils southboundUtils;
78     private final Random random;
79     private final Long maxBackoff;
80     private final Long inactivityProbe;
81
82
83     /**
84      * Construct a new ElanBridgeManager.
85      * @param elanConfig the elan configuration
86      * @param interfaceManager InterfaceManager
87      * @param southboundUtils southboutUtils
88      * @param dataBroker DataBroker
89      */
90     @Inject
91     public ElanBridgeManager(ElanConfig elanConfig, IInterfaceManager interfaceManager,
92             SouthboundUtils southboundUtils, DataBroker dataBroker) {
93         //TODO: ClusterAware!!!??
94         this.dataBroker = dataBroker;
95         this.interfaceManager = interfaceManager;
96         this.southboundUtils = southboundUtils;
97         this.random = new Random(System.currentTimeMillis());
98         this.maxBackoff = elanConfig.getControllerMaxBackoff() != null
99                 ? elanConfig.getControllerMaxBackoff().toJava() : 1000L;
100         this.inactivityProbe = elanConfig.getControllerInactivityProbe() != null
101                 ? elanConfig.getControllerInactivityProbe().toJava() : 0L;
102     }
103
104     /**
105      * Is OVS running in userspace mode?
106      * @return true if the ovsdb.userspace.enabled variable is set to true
107      */
108     public boolean isUserSpaceEnabled() {
109         final String enabledPropertyStr = System.getProperty("ovsdb.userspace.enabled", "no");
110         return enabledPropertyStr != null && enabledPropertyStr.equalsIgnoreCase("yes");
111     }
112
113     /**
114      * Is the Node object an OVSDB node.
115      * @param node unidentified node object
116      * @return true if the Node is an OVSDB node
117      */
118     public boolean isOvsdbNode(Node node) {
119         return southboundUtils.extractNodeAugmentation(node) != null;
120     }
121
122     /**
123      * Is this Node the integration bridge (br-int).
124      * @param node unidentified noe object
125      * @return true if the Node is a bridge and it is the integration bridge
126      */
127     public boolean isIntegrationBridge(Node node) {
128         if (!isBridgeNode(node)) {
129             return false;
130         }
131
132         String bridgeName = southboundUtils.extractBridgeName(node);
133         if (bridgeName == null) {
134             return false;
135         }
136
137         return bridgeName.equals(INTEGRATION_BRIDGE);
138     }
139
140     /**
141      * Is this node a bridge.
142      * @param node unidentified node object
143      * @return true if this node is a bridge
144      */
145     public boolean isBridgeNode(Node node) {
146         return southboundUtils.extractBridgeAugmentation(node) != null;
147     }
148
149     /**
150      * Advance the "preperation" of the OVSDB node. This re-entrant method advances the state of an OVSDB
151      * node towards the prepared state where all bridges and patch ports are created and active. This method
152      * should be invoked for the OVSDB node and the integration bridge node BUT IT IS SAFE TO INVOKE IT ON ANY NODE.
153      * @param node A node
154      * @param generateIntBridgeMac whether or not the int bridge's mac should be set to a random value
155      */
156     @SuppressWarnings("checkstyle:IllegalCatch")
157     public void processNodePrep(Node node, boolean generateIntBridgeMac) {
158         if (isOvsdbNode(node)) {
159             if (southboundUtils.readBridgeNode(node, INTEGRATION_BRIDGE) == null) {
160                 LOG.debug("OVSDB node in operational does not have br-int, create one {}", node.getNodeId().getValue());
161                 try {
162                     createIntegrationBridgeConfig(node, generateIntBridgeMac);
163                 } catch (RuntimeException e) {
164                     LOG.error("Error creating bridge on {}", node, e);
165                 }
166             }
167             return;
168         }
169
170         //Assume "node" is a bridge node, extract the OVSDB node from operational
171         Node ovsdbNode = southboundUtils.readOvsdbNode(node);
172         if (ovsdbNode == null) {
173             LOG.error("Node is neither bridge nor ovsdb {}", node);
174             return;
175         }
176
177         if (isIntegrationBridge(node)) {
178             prepareIntegrationBridge(ovsdbNode, node);
179         }
180
181     }
182
183     public void handleNewProviderNetBridges(Node originalNode, Node updatedNode) {
184         if (!isOvsdbNode(updatedNode)) {
185             return;
186         }
187
188         List<ManagedNodeEntry> originalManagedNodes = new ArrayList<>(getManagedNodeEntries(originalNode));
189         List<ManagedNodeEntry> updatedManagedNodes = new ArrayList<>(getManagedNodeEntries(updatedNode));
190
191         updatedManagedNodes.removeAll(originalManagedNodes);
192         if (updatedManagedNodes.isEmpty()) {
193             return;
194         }
195         LOG.debug("handleNewProviderNetBridges checking if any of these are provider nets {}", updatedManagedNodes);
196
197         Node brInt = southboundUtils.readBridgeNode(updatedNode, INTEGRATION_BRIDGE);
198         if (brInt == null) {
199             LOG.info("handleNewProviderNetBridges, br-int not found");
200             return;
201         }
202
203         Collection<String> providerVals = getOpenvswitchOtherConfigMap(updatedNode, PROVIDER_MAPPINGS_KEY).values();
204         for (ManagedNodeEntry nodeEntry : updatedManagedNodes) {
205             String bridgeName = nodeEntry.getBridgeRef().getValue().firstKeyOf(Node.class).getNodeId().getValue();
206             bridgeName = bridgeName.substring(bridgeName.lastIndexOf('/') + 1);
207             if (bridgeName.equals(INTEGRATION_BRIDGE)) {
208                 continue;
209             }
210             if (providerVals.contains(bridgeName)) {
211                 patchBridgeToBrInt(brInt, southboundUtils.readBridgeNode(updatedNode, bridgeName), bridgeName);
212             }
213         }
214
215
216     }
217
218     @Nullable
219     private List<ManagedNodeEntry> getManagedNodeEntries(Node node) {
220         OvsdbNodeAugmentation ovsdbNode = southboundUtils.extractNodeAugmentation(node);
221         if (ovsdbNode == null) {
222             return null;
223         }
224
225         return ovsdbNode.nonnullManagedNodeEntry();
226     }
227
228     private void prepareIntegrationBridge(Node ovsdbNode, Node brIntNode) {
229         if (southboundUtils.getBridgeFromConfig(ovsdbNode, INTEGRATION_BRIDGE) == null) {
230             LOG.debug("br-int in operational but not config, copying into config");
231             copyBridgeToConfig(brIntNode);
232         }
233
234         Map<String, String> providerMappings = getOpenvswitchOtherConfigMap(ovsdbNode, PROVIDER_MAPPINGS_KEY);
235
236         for (String value : providerMappings.values()) {
237             if (southboundUtils.extractTerminationPointAugmentation(brIntNode, value) != null) {
238                 LOG.debug("prepareIntegrationBridge: port {} already exists on {}", value, INTEGRATION_BRIDGE);
239                 continue;
240             }
241
242             Node exBridgeNode = southboundUtils.readBridgeNode(ovsdbNode, value);
243             if (exBridgeNode != null) {
244                 LOG.debug("prepareIntegrationBridge: bridge {} found. Patching to {}", value, INTEGRATION_BRIDGE);
245                 patchBridgeToBrInt(brIntNode, exBridgeNode, value);
246             } else {
247                 LOG.debug("prepareIntegrationBridge: adding interface {} to {}", value, INTEGRATION_BRIDGE);
248                 if (!addPortToBridge(brIntNode, INTEGRATION_BRIDGE, value)) {
249                     LOG.error("Failed to add {} port to {}", value, brIntNode);
250                 }
251             }
252
253         }
254
255         if (!addControllerToBridge(ovsdbNode, INTEGRATION_BRIDGE)) {
256             LOG.error("Failed to set controller to existing integration bridge {}", brIntNode);
257         }
258
259     }
260
261     private void copyBridgeToConfig(Node brIntNode) {
262         NodeBuilder bridgeNodeBuilder = new NodeBuilder(brIntNode);
263         bridgeNodeBuilder.setTerminationPoint(null);
264         InstanceIdentifier<Node> brNodeIid = SouthboundUtils.createInstanceIdentifier(brIntNode.getNodeId());
265         try {
266             SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
267                 brNodeIid, bridgeNodeBuilder.build());
268         } catch (TransactionCommitFailedException e) {
269             LOG.error("Failed to copy Bridge {} to config", brNodeIid, e);
270         }
271     }
272
273     private void patchBridgeToBrInt(Node intBridgeNode, Node exBridgeNode, String physnetBridgeName) {
274
275         String portNameInt = getIntSidePatchPortName(physnetBridgeName);
276         String portNameExt = getExSidePatchPortName(physnetBridgeName);
277         if (!addPatchPort(intBridgeNode, INTEGRATION_BRIDGE, portNameInt, portNameExt)) {
278             LOG.error("Failed to add patch port {} to {}", portNameInt, intBridgeNode);
279             return;
280         }
281
282         if (!addPatchPort(exBridgeNode, physnetBridgeName, portNameExt, portNameInt)) {
283             LOG.error("Failed to add patch port {} to {}", portNameExt, exBridgeNode);
284             return;
285         }
286     }
287
288     private boolean createIntegrationBridgeConfig(Node ovsdbNode, boolean generateIntBridgeMac) {
289         // Make sure iface-type exist in Open_vSwitch table prior to br-int creation
290         // in order to allow mixed topology of both DPDK and non-DPDK OVS nodes
291         if (!ifaceTypesExist(ovsdbNode)) {
292             LOG.debug("Skipping integration bridge creation as if-types has not been initialized");
293             return false;
294         }
295
296         LOG.debug("ElanBridgeManager.createIntegrationBridgeConfig, skipping if exists");
297         if (!addBridge(ovsdbNode, INTEGRATION_BRIDGE,
298                 generateIntBridgeMac ? generateRandomMac() : null)) {
299             LOG.warn("Integration Bridge Creation failed");
300             return false;
301         }
302         return true;
303     }
304
305     private boolean ifaceTypesExist(Node ovsdbNode) {
306         OvsdbNodeAugmentation ovsdbNodeAugmentation = southboundUtils.extractNodeAugmentation(ovsdbNode);
307         return ovsdbNodeAugmentation != null && ovsdbNodeAugmentation.getInterfaceTypeEntry() != null
308                 && !ovsdbNodeAugmentation.getInterfaceTypeEntry().isEmpty();
309     }
310
311     /**
312      * Add a bridge to the OVSDB node but check that it does not exist in the
313      * CONFIGURATION. If it already exists in OPERATIONAL, update it with all
314      * configurable parameters but make sure to maintain the same datapath-id.
315      *
316      * @param ovsdbNode Which OVSDB node
317      * @param bridgeName Name of the bridge
318      * @param mac mac address to set on the bridge or null
319      * @return true if no errors occurred
320      */
321     public boolean addBridge(Node ovsdbNode, String bridgeName, @Nullable String mac) {
322         boolean rv = true;
323         if (southboundUtils.getBridgeFromConfig(ovsdbNode, bridgeName) == null) {
324             Class<? extends DatapathTypeBase> dpType = null;
325             if (isUserSpaceEnabled()) {
326                 dpType = DatapathTypeNetdev.class;
327             }
328
329             List<BridgeOtherConfigs> otherConfigs = buildBridgeOtherConfigs(ovsdbNode, bridgeName, mac);
330
331             rv = southboundUtils.addBridge(ovsdbNode, bridgeName,
332                     southboundUtils.getControllersFromOvsdbNode(ovsdbNode), dpType, otherConfigs,
333                     maxBackoff, inactivityProbe);
334         }
335         return rv;
336     }
337
338     private List<BridgeOtherConfigs> buildBridgeOtherConfigs(Node ovsdbNode, String bridgeName, String mac) {
339         // First attempt to extract the bridge augmentation from operational...
340         Node bridgeNode = southboundUtils.getBridgeNode(ovsdbNode, bridgeName);
341         OvsdbBridgeAugmentation bridgeAug = null;
342         if (bridgeNode != null) {
343             bridgeAug = southboundUtils.extractBridgeAugmentation(bridgeNode);
344         }
345
346         // ...if present, it means this bridge already exists and we need to take
347         // care not to change the datapath id. We do this by explicitly setting
348         // other_config:datapath-id to the value reported in the augmentation.
349         List<BridgeOtherConfigs> otherConfigs;
350         if (bridgeAug != null) {
351             DatapathId dpId = bridgeAug.getDatapathId();
352             if (dpId != null) {
353                 otherConfigs = bridgeAug.getBridgeOtherConfigs();
354                 if (otherConfigs == null) {
355                     otherConfigs = Lists.newArrayList();
356                 }
357
358                 if (otherConfigs.stream().noneMatch(otherConfig ->
359                             otherConfig.getBridgeOtherConfigKey().equals(OTHER_CONFIG_DATAPATH_ID))) {
360                     String dpIdVal = dpId.getValue().replace(":", "");
361                     otherConfigs.add(new BridgeOtherConfigsBuilder()
362                                     .setBridgeOtherConfigKey(OTHER_CONFIG_DATAPATH_ID)
363                                     .setBridgeOtherConfigValue(dpIdVal).build());
364                 }
365             } else {
366                 otherConfigs = Lists.newArrayList();
367             }
368         } else  {
369             otherConfigs = Lists.newArrayList();
370             if (mac != null) {
371                 otherConfigs.add(new BridgeOtherConfigsBuilder()
372                                 .setBridgeOtherConfigKey(OTHER_CONFIG_HWADDR)
373                                 .setBridgeOtherConfigValue(mac).build());
374             }
375         }
376
377         if (otherConfigs.stream().noneMatch(otherConfig ->
378                 otherConfig.getBridgeOtherConfigKey().equals(OTHER_CONFIG_DISABLE_IN_BAND))) {
379             otherConfigs.add(new BridgeOtherConfigsBuilder()
380                             .setBridgeOtherConfigKey(OTHER_CONFIG_DISABLE_IN_BAND)
381                             .setBridgeOtherConfigValue("true").build());
382         }
383
384         return otherConfigs;
385     }
386
387     private boolean addControllerToBridge(Node ovsdbNode,String bridgeName) {
388         return southboundUtils.setBridgeController(ovsdbNode,
389                 bridgeName, southboundUtils.getControllersFromOvsdbNode(ovsdbNode),
390                 maxBackoff, inactivityProbe);
391     }
392
393     /**
394      * {@inheritDoc}.
395      */
396     public Map<String, String> getOpenvswitchOtherConfigMap(Node node, String key) {
397         String otherConfigVal = southboundUtils.getOpenvswitchOtherConfig(node, key);
398         return getMultiValueMap(otherConfigVal);
399     }
400
401     /**
402      * Get the OVS node physical interface name from provider mappings.
403      * @param node OVSDB node
404      * @param physicalNetworkName name of physical network
405      * @return physical network name
406      */
407     @Nullable
408     public String getProviderMappingValue(Node node, String physicalNetworkName) {
409         Map<String, String> providerMappings = getOpenvswitchOtherConfigMap(node, PROVIDER_MAPPINGS_KEY);
410         String providerMappingValue = providerMappings.get(physicalNetworkName);
411         if (providerMappingValue == null) {
412             LOG.trace("Physical network {} not found in {}", physicalNetworkName, PROVIDER_MAPPINGS_KEY);
413         }
414
415         return providerMappingValue;
416     }
417
418     /**
419      * Get the name of the port in br-int for the given provider-mapping value. This is either a patch port to a bridge
420      * with providerMappingValue - patch-&lt;providerMappingValue&gt; or simply a port with the same name as
421      * providerMappingValue
422      * @param bridgeNode br-int Node
423      * @param providerMappingValue this is the last part of provider_mappings=net_name:THIS
424      * @return the name of the port on br-int
425      */
426     public String getIntBridgePortNameFor(Node bridgeNode, String providerMappingValue) {
427         String res = providerMappingValue;
428         Node managingNode = southboundUtils.readOvsdbNode(bridgeNode);
429         if (managingNode != null && southboundUtils.isBridgeOnOvsdbNode(managingNode, providerMappingValue)) {
430             res = getIntSidePatchPortName(providerMappingValue);
431         }
432
433         return res;
434     }
435
436     /**
437      * Get the name of the patch-port which is patched to the bridge containing
438      * interfaceName. Patch port name is truncated to the maximum allowed characters
439      *
440      * @param interfaceName The external interface
441      * @return interface name
442      */
443     public String getIntSidePatchPortName(String interfaceName) {
444         String patchPortName = interfaceName + INT_SIDE_PATCH_PORT_SUFFIX;
445         if (patchPortName.length() <= MAX_LINUX_INTERFACE_NAME_LENGTH) {
446             return patchPortName;
447         }
448
449         LOG.debug("Patch port {} exceeds maximum allowed length. Truncating to {} characters",
450                 patchPortName, MAX_LINUX_INTERFACE_NAME_LENGTH);
451         return patchPortName.substring(0, MAX_LINUX_INTERFACE_NAME_LENGTH - 1);
452     }
453
454     private static String getExSidePatchPortName(String physicalInterfaceName) {
455         return physicalInterfaceName + EX_SIDE_PATCH_PORT_SUFFIX;
456     }
457
458     /**
459      * Add a port to a bridge.
460      * @param node the bridge node
461      * @param bridgeName name of the bridge
462      * @param portName name of port to add
463      * @return true if successful in writing to mdsal
464      */
465     public boolean addPortToBridge(Node node, String bridgeName, String portName) {
466         boolean rv = true;
467
468         if (southboundUtils.extractTerminationPointAugmentation(node, portName) == null) {
469             rv = southboundUtils.addTerminationPoint(node, bridgeName, portName, null);
470
471             if (rv) {
472                 LOG.debug("addPortToBridge: node: {}, bridge: {}, portname: {} status: success",
473                         node.getNodeId().getValue(), bridgeName, portName);
474             } else {
475                 LOG.error("addPortToBridge: node: {}, bridge: {}, portname: {} status: FAILED",
476                         node.getNodeId().getValue(), bridgeName, portName);
477             }
478         } else {
479             LOG.trace("addPortToBridge: node: {}, bridge: {}, portname: {} status: not_needed",
480                     node.getNodeId().getValue(), bridgeName, portName);
481         }
482
483         return rv;
484     }
485
486     /**
487      * Add a patch port to a bridge.
488      * @param node the bridge node
489      * @param bridgeName name of the bridge
490      * @param portName name of the port
491      * @param peerPortName name of the port's peer (the other side)
492      * @return true if successful
493      */
494     public boolean addPatchPort(Node node, String bridgeName, String portName, String peerPortName) {
495         boolean rv = true;
496
497         if (southboundUtils.extractTerminationPointAugmentation(node, portName) == null) {
498             rv = southboundUtils.addPatchTerminationPoint(node, bridgeName, portName, peerPortName);
499
500             if (rv) {
501                 LOG.info("addPatchPort: node: {}, bridge: {}, portname: {} peer: {} status: success",
502                         node.getNodeId().getValue(), bridgeName, portName, peerPortName);
503             } else {
504                 LOG.error("addPatchPort: node: {}, bridge: {}, portname: {} peer: {} status: FAILED",
505                         node.getNodeId().getValue(), bridgeName, portName, peerPortName);
506             }
507         } else {
508             LOG.trace("addPatchPort: node: {}, bridge: {}, portname: {} peer: {} status: not_needed",
509                     node.getNodeId().getValue(), bridgeName, portName, peerPortName);
510         }
511
512         return rv;
513     }
514
515     public Optional<Uint64> getDpIdFromManagerNodeId(String managerNodeId) {
516         InstanceIdentifier<Node> identifier = getIntegrationBridgeIdentifier(managerNodeId);
517         OvsdbBridgeAugmentation integrationBridgeAugmentation = interfaceManager.getOvsdbBridgeForNodeIid(identifier);
518         if (integrationBridgeAugmentation == null) {
519             LOG.debug("Failed to get OvsdbBridgeAugmentation for node {}", managerNodeId);
520             return Optional.empty();
521         }
522
523         return Optional.ofNullable(integrationBridgeAugmentation.getDatapathId())
524                 .map(datapathId -> MDSALUtil.getDpnId(datapathId.getValue()));
525     }
526
527     private static InstanceIdentifier<Node> getIntegrationBridgeIdentifier(String managerNodeId) {
528         NodeId brNodeId = new NodeId(
529                 managerNodeId + "/" + ITMConstants.BRIDGE_URI_PREFIX + "/" + ITMConstants.DEFAULT_BRIDGE_NAME);
530         return InstanceIdentifier.create(NetworkTopology.class)
531                 .child(Topology.class, new TopologyKey(IfmConstants.OVSDB_TOPOLOGY_ID))
532                 .child(Node.class, new NodeKey(brNodeId));
533     }
534
535     private String generateRandomMac() {
536         byte[] macBytes = new byte[6];
537         random.nextBytes(macBytes);
538         macBytes[0] &= 0xfc; //the two low bits of the first byte need to be zero
539
540         StringBuilder stringBuilder = new StringBuilder();
541
542         int index = 0;
543         while (true) {
544             stringBuilder.append(String.format("%02x", macBytes[index++]));
545             if (index >= 6) {
546                 break;
547             }
548             stringBuilder.append(':');
549         }
550
551         return stringBuilder.toString();
552     }
553
554     private static Map<String, String> getMultiValueMap(String multiKeyValueStr) {
555         if (Strings.isNullOrEmpty(multiKeyValueStr)) {
556             return Collections.emptyMap();
557         }
558
559         Map<String, String> valueMap = new HashMap<>();
560         Splitter splitter = Splitter.on(OTHER_CONFIG_PARAMETERS_DELIMITER);
561         for (String keyValue : splitter.split(multiKeyValueStr)) {
562             String[] split = keyValue.split(OTHER_CONFIG_KEY_VALUE_DELIMITER, 2);
563             if (split.length == 2) {
564                 valueMap.put(split[0], split[1]);
565             }
566         }
567
568         return valueMap;
569     }
570
571     /**
572      * {@inheritDoc}.
573      */
574     @Nullable
575     private Node getBridgeNode(Uint64 dpId) {
576         List<Node> ovsdbNodes = southboundUtils.getOvsdbNodes();
577         if (null == ovsdbNodes) {
578             LOG.debug("Could not find any (?) ovsdb nodes");
579             return null;
580         }
581
582         for (Node node : ovsdbNodes) {
583             if (!isIntegrationBridge(node)) {
584                 continue;
585             }
586
587             long nodeDpid = southboundUtils.getDataPathId(node);
588             if (dpId.equals(Uint64.valueOf(nodeDpid))) {
589                 return node;
590             }
591         }
592
593         return null;
594     }
595
596     @Nullable
597     public String getProviderInterfaceName(Uint64 dpId, String physicalNetworkName) {
598         Node brNode;
599
600         brNode = getBridgeNode(dpId);
601         if (brNode == null) {
602             LOG.debug("Could not find bridge node for {}", dpId);
603             return null;
604         }
605
606         return getProviderInterfaceName(brNode, physicalNetworkName);
607     }
608
609     @Nullable
610     public String getProviderInterfaceName(Node bridgeNode, String physicalNetworkName) {
611         if (physicalNetworkName == null) {
612             return null;
613         }
614
615         String providerMappingValue = getProviderMappingValue(bridgeNode, physicalNetworkName);
616         if (providerMappingValue == null) {
617             LOG.trace("No provider mapping found for physicalNetworkName {} node {}", physicalNetworkName,
618                     bridgeNode.getNodeId().getValue());
619             return null;
620         }
621
622         long dataPathId = southboundUtils.getDataPathId(bridgeNode);
623         if (dataPathId < 1) {
624             LOG.info("No DatapathID for node {} with physicalNetworkName {}",
625                     bridgeNode.getNodeId().getValue(), physicalNetworkName);
626             return null;
627         }
628
629         String portName = getIntBridgePortNameFor(bridgeNode, providerMappingValue);
630         String dpIdStr = String.valueOf(dataPathId);
631         return interfaceManager.getPortNameForInterface(dpIdStr, portName);
632     }
633
634     public boolean hasDatapathID(Node node) {
635         return southboundUtils.getDataPathId(node) > 0;
636     }
637
638     public boolean isBridgeOnOvsdbNode(Node ovsdbNode, String bridgename) {
639         return southboundUtils.isBridgeOnOvsdbNode(ovsdbNode, bridgename);
640     }
641
642     public String getIntegrationBridgeName() {
643         return INTEGRATION_BRIDGE;
644     }
645
646     public Uint64 getDatapathId(Node node) {
647         return Uint64.valueOf(southboundUtils.getDataPathId(node));
648     }
649 }