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