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