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