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