Bug 5510 - Modifying DataTreeChangeHandler
[groupbasedpolicy.git] / neutron-ovsdb / src / main / java / org / opendaylight / groupbasedpolicy / neutron / ovsdb / OvsdbNodeListener.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, 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.groupbasedpolicy.neutron.ovsdb;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19
20 import javax.annotation.Nonnull;
21
22 import org.opendaylight.controller.config.yang.config.neutron_ovsdb.impl.IntegrationBridgeSetting;
23 import org.opendaylight.controller.config.yang.config.neutron_ovsdb.impl.NeutronOvsdbModule;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
26 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper;
31 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.NeutronOvsdbIidFactory;
32 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper;
33 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
34 import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
35 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeSystem;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow13;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeSecure;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigsKey;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
68 import org.opendaylight.yangtools.yang.binding.DataObject;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 import com.google.common.base.Function;
75 import com.google.common.base.Predicate;
76 import com.google.common.base.Predicates;
77 import com.google.common.base.Strings;
78 import com.google.common.collect.Collections2;
79 import com.google.common.collect.ImmutableList;
80 import com.google.common.collect.Lists;
81 import com.google.common.util.concurrent.CheckedFuture;
82 import com.google.common.util.concurrent.FutureCallback;
83 import com.google.common.util.concurrent.Futures;
84
85 public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
86
87     private static final Logger LOG = LoggerFactory.getLogger(OvsdbNodeListener.class);
88     public static final String NEUTRON_PROVIDER_MAPPINGS_KEY = "provider_mappings";
89     private static final String OF_SEPARATOR = ":";
90     private static final String OF_INVENTORY_PREFIX = "openflow";
91     private static final String BRIDGE_SEPARATOR = "/bridge/";
92     private static IntegrationBridgeSetting intBrSettings;
93
94     private final Map<OvsdbBridgeRef, String> providerPortNameByBridgeRef = new HashMap<>();
95     private final Map<InstanceIdentifier<Node>, NeutronBridgeWithExtPort> bridgeByNodeIid = new HashMap<>();
96
97     public OvsdbNodeListener(DataBroker dataProvider, IntegrationBridgeSetting brSettings) {
98         super(dataProvider);
99         intBrSettings = brSettings;
100         this.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
101                 InstanceIdentifier.create(NetworkTopology.class)
102                     .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
103                     .child(Node.class)));
104     }
105
106     @Override
107     protected void onWrite(DataObjectModification<Node> rootNode, InstanceIdentifier<Node> rootIdentifier) {
108         Node node = rootNode.getDataAfter();
109         OvsdbNodeAugmentation ovsdbNode = node.getAugmentation(OvsdbNodeAugmentation.class);
110         if (ovsdbNode != null) {
111             LOG.trace("OVSDB node created: {} \n {}", rootIdentifier, node);
112             DataObjectModification<OpenvswitchOtherConfigs> ovsOtherConfigModification = getProviderMappingsModification(rootNode);
113             boolean integrationBridgePresent = false;
114             if (isProviderPortNameChanged(ovsOtherConfigModification) && ovsdbNode.getManagedNodeEntry() != null) {
115                 String newProviderPortName = getProviderPortName(ovsOtherConfigModification.getDataAfter());
116                 LOG.debug("provider_mappings created {} on node {}", newProviderPortName, node.getNodeId().getValue());
117                 for (ManagedNodeEntry mngdNodeEntry : ovsdbNode.getManagedNodeEntry()) {
118                     OvsdbBridgeRef bridgeRef = mngdNodeEntry.getBridgeRef();
119                     providerPortNameByBridgeRef.put(bridgeRef, newProviderPortName);
120                     LOG.trace("Added Provider port name {} by OVSDB bridge ref {}", newProviderPortName,
121                             mngdNodeEntry.getBridgeRef());
122                     NodeKey managedNodeKey = bridgeRef.getValue().firstKeyOf(Node.class);
123                     if (intBrSettings != null && managedNodeKey.getNodeId().getValue().equals(intBrSettings.getName())) {
124                         integrationBridgePresent = true;
125                     }
126                 }
127             }
128             if (intBrSettings != null && integrationBridgePresent == false) {
129                 final Node bridge = createBridge(rootIdentifier,
130                         managerToControllerEntries(ovsdbNode.getManagerEntry()), intBrSettings.getName());
131                 InstanceIdentifier<Node> bridgeNodeIid = NeutronOvsdbIidFactory.nodeIid(
132                         rootIdentifier.firstKeyOf(Topology.class).getTopologyId(), bridge.getNodeId());
133                 WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
134                 wTx.merge(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid, bridge, true);
135                 Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
136
137                     @Override
138                     public void onSuccess(Void result) {
139                         LOG.info("Bridge {} written to datastore." + bridge.getNodeId().getValue());
140                     }
141
142                     @Override
143                     public void onFailure(Throwable t) {
144                         LOG.error("Failed to write bridge {}. Message: {}" + bridge.getNodeId().getValue(),
145                                 t.getMessage());
146                     }
147                 });
148             }
149         }
150         OvsdbBridgeAugmentation ovsdbBridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
151         if (ovsdbBridge != null) {
152             LOG.trace("OVSDB bridge created: {} \n {}", rootIdentifier, node);
153             Set<DataObjectModification<OvsdbTerminationPointAugmentation>> ovsdbTpModifications =
154                     getOvsdbTpModifications(rootNode);
155             NodeId ofNodeId = buildOfNodeId(ovsdbBridge);
156             if (!ovsdbTpModifications.isEmpty() && ofNodeId != null) {
157                 NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
158                 bridge.ofNodeId = ofNodeId;
159                 LOG.trace("OF node {} representing OVSDB bridge {}", ofNodeId.getValue(), node.getNodeId().getValue());
160             }
161             for (DataObjectModification<OvsdbTerminationPointAugmentation> ovsdbTpModification : ovsdbTpModifications) {
162                 OvsdbTerminationPointAugmentation newOvsdbTp = ovsdbTpModification.getDataAfter();
163                 if (ovsdbBridge.getBridgeName().getValue().equals(newOvsdbTp.getName())) {
164                     LOG.trace("Termination Point {} same as Bridge {}. Not processing", newOvsdbTp.getName(),
165                             ovsdbBridge.getBridgeName().getValue());
166                     continue;
167                 }
168                 String portName = newOvsdbTp.getName();
169                 Long ofport = newOvsdbTp.getOfport();
170                 if (isOfportOrNameChanged(ovsdbTpModification) && portName != null && ofport != null) {
171                     NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
172                     bridge.ofportByName.put(ofport, portName);
173                     LOG.trace("OVSDB termination point with ofport {} and port-name {} created.", ofport, portName);
174                     // port name is same as provider port name so the termination point represents
175                     // external port
176                     if (portName.equals(providerPortNameByBridgeRef.get(new OvsdbBridgeRef(rootIdentifier)))) {
177                         NodeConnectorId ofNcId = buildOfNodeConnectorId(newOvsdbTp, ofNodeId);
178                         bridge.externalIfaces.add(ofNcId);
179                         InventoryHelper.addOfOverlayExternalPort(bridge.ofNodeId, ofNcId, dataProvider);
180                         LOG.debug("Added of-overlay external-interface {} to node {}", ofNcId.getValue(),
181                                 bridge.ofNodeId);
182                         traceBridge(rootIdentifier);
183                     }
184                 }
185             }
186         }
187     }
188
189     @Override
190     protected void onDelete(DataObjectModification<Node> rootNode, InstanceIdentifier<Node> rootIdentifier) {
191         LOG.trace("Not implemented - OVSDB element deleted: {} \n {}", rootIdentifier, rootNode.getDataBefore());
192     }
193
194     @Override
195     protected void onSubtreeModified(DataObjectModification<Node> rootNode, InstanceIdentifier<Node> rootIdentifier) {
196         Node node = rootNode.getDataAfter();
197         OvsdbBridgeAugmentation ovsdbBridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
198         if (ovsdbBridge != null) {
199             LOG.trace("OVSDB bridge updated: {} \n before {} \n after {}", rootIdentifier, rootNode.getDataBefore(),
200                     rootNode.getDataAfter());
201             Set<DataObjectModification<OvsdbTerminationPointAugmentation>> ovsdbTpModifications =
202                     getOvsdbTpModifications(rootNode);
203             NodeId ofNodeId = buildOfNodeId(ovsdbBridge);
204             if (!ovsdbTpModifications.isEmpty() && ofNodeId != null) {
205                 NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
206                 if (bridge.ofNodeId != null && !bridge.ofNodeId.equals(ofNodeId)) {
207                     LOG.debug("OVSDB bridge {} has changed datapath-id. \n  Old: {} \n  New: {}",
208                             node.getNodeId().getValue(), bridge.ofNodeId.getValue(), ofNodeId.getValue());
209                     bridge.ofNodeId = ofNodeId;
210                 }
211             }
212             for (DataObjectModification<OvsdbTerminationPointAugmentation> ovsdbTpModification : ovsdbTpModifications) {
213                 OvsdbTerminationPointAugmentation newOvsdbTp = ovsdbTpModification.getDataAfter();
214
215                 if (newOvsdbTp == null) {
216                     LOG.trace("Termination Point is null. Not processing");
217                     continue;
218                 }
219
220                 if (ovsdbBridge.getBridgeName().getValue().equals(newOvsdbTp.getName())) {
221                     LOG.trace("Termination Point {} same as Bridge {}. Not processing", newOvsdbTp.getName(),
222                             ovsdbBridge.getBridgeName().getValue());
223                     continue;
224                 }
225                 String portName = newOvsdbTp.getName();
226                 Long ofport = newOvsdbTp.getOfport();
227                 if (isOfportOrNameChanged(ovsdbTpModification) && portName != null && ofport != null) {
228                     NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
229                     bridge.ofportByName.put(ofport, portName);
230                     LOG.trace("OVSDB termination point with ofport {} and port-name {} created.", ofport, portName);
231                     // port name is same as provider port name so the termination point represents
232                     // external port
233                     if (portName.equals(providerPortNameByBridgeRef.get(new OvsdbBridgeRef(rootIdentifier)))) {
234                         NodeConnectorId ofNcId = buildOfNodeConnectorId(newOvsdbTp, ofNodeId);
235                         bridge.externalIfaces.add(ofNcId);
236                         InventoryHelper.addOfOverlayExternalPort(bridge.ofNodeId, ofNcId, dataProvider);
237                         LOG.debug("Added of-overlay external-interface {} to node {}", ofNcId.getValue(),
238                                 bridge.ofNodeId);
239                         traceBridge(rootIdentifier);
240                     }
241                 }
242             }
243         }
244     }
245
246     private NeutronBridgeWithExtPort getBridge(InstanceIdentifier<Node> nodeIid) {
247         NeutronBridgeWithExtPort bridge = bridgeByNodeIid.get(nodeIid);
248         if (bridge == null) {
249             bridge = new NeutronBridgeWithExtPort();
250             bridgeByNodeIid.put(nodeIid, bridge);
251         }
252         return bridge;
253     }
254
255     @SuppressWarnings("unchecked")
256     private static Set<DataObjectModification<OvsdbTerminationPointAugmentation>> getOvsdbTpModifications(
257             DataObjectModification<Node> rootNode) {
258         Set<DataObjectModification<OvsdbTerminationPointAugmentation>> modifications = new HashSet<>();
259         for (DataObjectModification<? extends DataObject> modifiedChild : rootNode.getModifiedChildren()) {
260             if (TerminationPoint.class.isAssignableFrom(modifiedChild.getDataType())) {
261                 DataObjectModification<OvsdbTerminationPointAugmentation> modifiedAugmentation =
262                         ((DataObjectModification<TerminationPoint>) modifiedChild)
263                             .getModifiedAugmentation(OvsdbTerminationPointAugmentation.class);
264                 if (modifiedAugmentation != null) {
265                     modifications.add(modifiedAugmentation);
266                 }
267             }
268         }
269         return modifications;
270     }
271
272     private static boolean isOfportOrNameChanged(
273             DataObjectModification<OvsdbTerminationPointAugmentation> ovsdbTpModification) {
274         if (ovsdbTpModification == null) {
275             return false;
276         }
277         OvsdbTerminationPointAugmentation oldTp = ovsdbTpModification.getDataBefore();
278         OvsdbTerminationPointAugmentation newTp = ovsdbTpModification.getDataAfter();
279         if (oldTp != null && newTp != null) {
280             if (oldTp.getOfport() != null && newTp.getOfport() != null && oldTp.getOfport() != newTp.getOfport()) {
281                 return true;
282             }
283             if (!(Strings.nullToEmpty(oldTp.getName())).equals(Strings.nullToEmpty(newTp.getName()))) {
284                 return true;
285             }
286         }
287         if (isOfportOrNameNotNull(oldTp)) {
288             return true;
289         }
290         if (isOfportOrNameNotNull(newTp)) {
291             return true;
292         }
293         return false;
294     }
295
296     private static boolean isOfportOrNameNotNull(OvsdbTerminationPointAugmentation tp) {
297         if (tp != null) {
298             if (tp.getOfport() != null) {
299                 return true;
300             }
301             if (tp.getName() != null) {
302                 return true;
303             }
304         }
305         return false;
306     }
307
308     private static DataObjectModification<OpenvswitchOtherConfigs> getProviderMappingsModification(
309             DataObjectModification<Node> rootNode) {
310         DataObjectModification<OvsdbNodeAugmentation> modifiedOvsdbNode =
311                 rootNode.getModifiedAugmentation(OvsdbNodeAugmentation.class);
312         if (modifiedOvsdbNode == null) {
313             return null;
314         }
315         return modifiedOvsdbNode.getModifiedChildListItem(OpenvswitchOtherConfigs.class,
316                 new OpenvswitchOtherConfigsKey(NEUTRON_PROVIDER_MAPPINGS_KEY));
317     }
318
319     private static boolean isProviderPortNameChanged(DataObjectModification<OpenvswitchOtherConfigs> ovsConfig) {
320         if (ovsConfig == null) {
321             return false;
322         }
323         OpenvswitchOtherConfigs oldConfig = ovsConfig.getDataBefore();
324         OpenvswitchOtherConfigs newConfig = ovsConfig.getDataAfter();
325         if (oldConfig != null && newConfig != null) {
326             if (!(Strings.nullToEmpty(oldConfig.getOtherConfigValue())
327                 .equals(Strings.nullToEmpty(newConfig.getOtherConfigValue())))) {
328                 return true;
329             }
330         } else if (oldConfig != null && !Strings.isNullOrEmpty(oldConfig.getOtherConfigValue())) {
331             return true;
332         } else if (newConfig != null && !Strings.isNullOrEmpty(newConfig.getOtherConfigValue())) {
333             return true;
334         }
335         return false;
336     }
337
338     private static @Nonnull String getProviderPortName(OpenvswitchOtherConfigs config) {
339         if (NEUTRON_PROVIDER_MAPPINGS_KEY.equals(config.getOtherConfigKey()) && config.getOtherConfigValue() != null) {
340             String otherConfig = config.getOtherConfigValue();
341             String[] elements = otherConfig.split(":");
342             if (elements.length == 2) {
343                 return elements[1];
344             }
345         }
346         return "";
347     }
348
349     /**
350      * Extracts IP address from URI
351      *
352      * @param uri in format protocol:ip:port
353      * @return IPv4 or IPv6 address as {@link String}.
354      */
355     private static @Nonnull String getIpAddrFromUri(Uri uri) {
356         String otherConfig = uri.getValue();
357         String[] elements = otherConfig.split(":");
358         // IPv6 expression also contains colons
359         if (elements.length < 3) {
360             return "";
361         }
362         StringBuilder sb = new StringBuilder();
363         // first (protocol) and last (port) elements are filtered
364         for (int i = 1; i < elements.length - 1; i++) {
365             sb.append(elements[i]);
366         }
367         return sb.toString();
368     }
369
370     private List<ControllerEntry> managerToControllerEntries(List<ManagerEntry> managerEntries) {
371         return Lists.transform(managerEntries, new Function<ManagerEntry, ControllerEntry>() {
372
373             @Override
374             public ControllerEntry apply(ManagerEntry managerEntry) {
375                 String ipAddr = getIpAddrFromUri(managerEntry.getTarget());
376                 Uri uri = new Uri(intBrSettings.getOpenflowProtocol() + OF_SEPARATOR + ipAddr + OF_SEPARATOR
377                         + intBrSettings.getOpenflowPort());
378                 return new ControllerEntryBuilder().setTarget(new Uri(uri)).build();
379             }
380         });
381     }
382
383     private Node createBridge(InstanceIdentifier<Node> managedByIid, List<ControllerEntry> controllerEntries,
384             String bridgeName) {
385         OvsdbBridgeAugmentation br = new OvsdbBridgeAugmentationBuilder()
386             .setBridgeName(new OvsdbBridgeName(bridgeName))
387             .setManagedBy(new OvsdbNodeRef(managedByIid))
388             .setControllerEntry(controllerEntries)
389             .setDatapathType(DatapathTypeSystem.class)
390             .setProtocolEntry(
391                     ImmutableList.<ProtocolEntry>of(new ProtocolEntryBuilder().setProtocol(
392                             OvsdbBridgeProtocolOpenflow13.class).build()))
393             .build();
394         NodeKey managerNodeKey = managedByIid.firstKeyOf(Node.class);
395         return new NodeBuilder().setNodeId(
396                 new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(
397                         managerNodeKey.getNodeId().getValue() + BRIDGE_SEPARATOR + bridgeName))
398             .addAugmentation(OvsdbBridgeAugmentation.class, br)
399             .build();
400     }
401
402     private static NodeId buildOfNodeId(OvsdbBridgeAugmentation ovsdbBridge) {
403         if (ovsdbBridge.getDatapathId() == null) {
404             return null;
405         }
406         Long macLong = InventoryHelper.getLongFromDpid(ovsdbBridge.getDatapathId().getValue());
407         return new NodeId(OF_INVENTORY_PREFIX + OF_SEPARATOR + String.valueOf(macLong));
408     }
409
410     private static NodeConnectorId buildOfNodeConnectorId(OvsdbTerminationPointAugmentation terminationPoint,
411             NodeId nodeId) {
412         if (terminationPoint.getOfport() == null) {
413             return null;
414         }
415         return new NodeConnectorId(nodeId.getValue() + OF_SEPARATOR + String.valueOf(terminationPoint.getOfport()));
416     }
417
418     private void traceBridge(InstanceIdentifier<Node> identifier) {
419         if (LOG.isTraceEnabled()) {
420             NeutronBridgeWithExtPort bridge = bridgeByNodeIid.get(identifier);
421             if (bridge == null) {
422                 LOG.trace("Bridge does not exist: {}", identifier);
423                 return;
424             }
425             String providerPortName = providerPortNameByBridgeRef.get(new OvsdbBridgeRef(identifier));
426             LOG.trace("State of bridge:\n  ID: {} \n  providerPortName: {} \n  {}", identifier, providerPortName,
427                     bridge);
428         }
429     }
430
431     private class NeutronBridgeWithExtPort {
432
433         NodeId ofNodeId;
434         Set<NodeConnectorId> externalIfaces = new HashSet<>();
435         Map<Long, String> ofportByName = new HashMap<>();
436
437         @Override
438         public String toString() {
439             return "NeutronBridgeWithExtPort:\n  ofNodeId=" + ofNodeId + "\n  externalIfaces=" + externalIfaces
440                     + ",\n  ofportByName=" + ofportByName;
441         }
442     }
443
444 }