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