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