MRI version bump for Aluminium
[genius.git] / alivenessmonitor / alivenessmonitor-impl / src / main / java / org / opendaylight / genius / alivenessmonitor / internal / HwVtepTunnelsStateHandler.java
1 /*
2  * Copyright (c) 2016, 2018 Ericsson India Global Services Pvt Ltd. 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.genius.alivenessmonitor.internal;
9
10 import static org.opendaylight.genius.alivenessmonitor.utils.AlivenessMonitorUtil.getMonitorStateId;
11 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
12 import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
13
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Optional;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Semaphore;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import java.util.concurrent.atomic.AtomicReference;
27 import javax.inject.Inject;
28 import javax.inject.Singleton;
29 import org.apache.aries.blueprint.annotation.service.Reference;
30 import org.eclipse.jdt.annotation.NonNull;
31 import org.eclipse.jdt.annotation.Nullable;
32 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandler;
33 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandlerRegistry;
34 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
35 import org.opendaylight.mdsal.binding.api.DataBroker;
36 import org.opendaylight.mdsal.binding.util.Datastore;
37 import org.opendaylight.mdsal.binding.util.InterruptibleCheckedConsumer;
38 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
39 import org.opendaylight.mdsal.binding.util.RetryingManagedNewTransactionRunner;
40 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
41 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
42 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
43 import org.opendaylight.serviceutils.tools.listener.AbstractSyncDataTreeChangeListener;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.LivenessState;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProtocolType;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.EndpointType;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.configs.MonitoringInfo;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profiles.MonitorProfile;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringState;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringStateBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdStatus;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdStatusKey;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
74 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.common.Uint32;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79
80 @Singleton
81 public class HwVtepTunnelsStateHandler extends AbstractSyncDataTreeChangeListener<Tunnels>
82         implements AlivenessProtocolHandler<Packet> {
83
84     private static final Logger LOG = LoggerFactory.getLogger(HwVtepTunnelsStateHandler.class);
85
86     private final ManagedNewTransactionRunner txRunner;
87     private final AlivenessMonitor alivenessMonitor;
88
89     @Inject
90     public HwVtepTunnelsStateHandler(@Reference final DataBroker dataBroker,
91                                      final AlivenessMonitor alivenessMonitor,
92                                      final AlivenessProtocolHandlerRegistry alivenessProtocolHandlerRegistry) {
93         super(dataBroker, LogicalDatastoreType.CONFIGURATION,
94               InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
95                       .augmentation(PhysicalSwitchAugmentation.class).child(Tunnels.class));
96         this.txRunner = new RetryingManagedNewTransactionRunner(dataBroker);
97         this.alivenessMonitor = alivenessMonitor;
98         alivenessProtocolHandlerRegistry.register(MonitorProtocolType.Bfd, this);
99     }
100
101     @Override
102     public void remove(@NonNull InstanceIdentifier<Tunnels> instanceIdentifier, @NonNull Tunnels tunnelInfo) {
103         // Do nothing
104     }
105
106     @Override
107     public void update(@NonNull InstanceIdentifier<Tunnels> instanceIdentifier, @NonNull Tunnels oldTunnelInfo,
108                        @NonNull Tunnels updatedTunnelInfo) {
109         @Nullable Map<BfdStatusKey, BfdStatus> oldBfdStatus = oldTunnelInfo.getBfdStatus();
110         @Nullable Map<BfdStatusKey, BfdStatus> newBfdStatus = updatedTunnelInfo.getBfdStatus();
111         LivenessState oldTunnelOpState = getTunnelOpState(oldBfdStatus);
112         final LivenessState newTunnelOpState = getTunnelOpState(newBfdStatus);
113         if (oldTunnelOpState == newTunnelOpState) {
114             LOG.debug("Tunnel state of old tunnel {} and update tunnel {} are same", oldTunnelInfo, updatedTunnelInfo);
115             return;
116         }
117         updatedTunnelInfo.getTunnelUuid();
118         String interfaceName = "<TODO>";
119         // TODO: find out the corresponding interface using tunnelIdentifier or
120         // any attributes of tunnelInfo object
121         final String monitorKey = getBfdMonitorKey(interfaceName);
122         LOG.debug("Processing monitorKey: {} for received Tunnels update DCN", monitorKey);
123
124         final Semaphore lock = alivenessMonitor.getLock(monitorKey);
125         LOG.debug("Acquiring lock for monitor key : {} to process monitor DCN", monitorKey);
126         alivenessMonitor.acquireLock(lock);
127
128         AtomicBoolean stateChanged = new AtomicBoolean();
129         AtomicReference<MonitoringState> currentState = new AtomicReference<>();
130         txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
131             Optional<MonitoringState> optState = tx.read(getMonitorStateId(monitorKey)).get();
132             if (optState.isPresent()) {
133                 currentState.set(optState.get());
134                 if (currentState.get().getState() == newTunnelOpState) {
135                     return;
136                 }
137                 stateChanged.set(true);
138                 final MonitoringState state = new MonitoringStateBuilder().setMonitorKey(monitorKey)
139                     .setState(newTunnelOpState).build();
140                 tx.merge(getMonitorStateId(monitorKey), state);
141             } else {
142                 LOG.warn("Monitoring State not available for key: {} to process the Packet received", monitorKey);
143             }
144         }).addCallback(new FutureCallback<Object>() {
145             @Override
146             public void onSuccess(@Nullable Object result) {
147                 alivenessMonitor.releaseLock(lock);
148                 if (stateChanged.get()) {
149                     // send notifications
150                     LOG.info("Sending notification for monitor Id : {} with Current State: {}",
151                         currentState.get().getMonitorId(), newTunnelOpState);
152                     alivenessMonitor.publishNotification(currentState.get().getMonitorId(), newTunnelOpState);
153                 } else {
154                     if (LOG.isTraceEnabled()) {
155                         LOG.trace("Successful in writing monitoring state {} to ODS", newTunnelOpState);
156                     }
157                 }
158             }
159
160             @Override
161             public void onFailure(@NonNull Throwable error) {
162                 alivenessMonitor.releaseLock(lock);
163                 LOG.warn("Error in writing monitoring state for {} to Datastore", monitorKey, error);
164             }
165         }, MoreExecutors.directExecutor());
166     }
167
168     private LivenessState getTunnelOpState(Map<BfdStatusKey, BfdStatus> tunnelBfdStatus) {
169         LivenessState livenessState = LivenessState.Unknown;
170         if (tunnelBfdStatus == null || tunnelBfdStatus.isEmpty()) {
171             return livenessState;
172         }
173         for (BfdStatus bfdState : tunnelBfdStatus.values()) {
174             if (AlivenessMonitorConstants.BFD_OP_STATE.equalsIgnoreCase(bfdState.getBfdStatusKey())) {
175                 String bfdOpState = bfdState.getBfdStatusValue();
176                 if (AlivenessMonitorConstants.BFD_STATE_UP.equalsIgnoreCase(bfdOpState)) {
177                     livenessState = LivenessState.Up;
178                 } else {
179                     livenessState = LivenessState.Down;
180                 }
181                 break;
182             }
183         }
184         return livenessState;
185     }
186
187     @Override
188     public void add(@NonNull InstanceIdentifier<Tunnels> instanceIdentifier, @NonNull Tunnels tunnelInfo) {
189         // TODO: need to add the code to enable BFD if tunnels are created
190         // dynamically by TOR switch
191     }
192
193     @Override
194     public Class<Packet> getPacketClass() {
195         return Packet.class;
196     }
197
198     @Override
199     @SuppressFBWarnings("NP_NONNULL_RETURN_VIOLATION")
200     public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
201         return null;
202     }
203
204     void resetMonitoringTask(boolean isEnable) {
205         // TODO: get the corresponding hwvtep tunnel from the sourceInterface
206         // once InterfaceMgr implements renderer for HWVTEP VXLAN tunnels
207
208         LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
209             new InterruptibleCheckedConsumer<TypedReadWriteTransaction<Datastore.Configuration>, ExecutionException>() {
210                 @Override
211                 // tunnelKey, nodeId, topologyId are initialized to null and immediately passed to
212                 // getTunnelIdentifier which FindBugs as a "Load of known null value" violation. Not sure sure what
213                 // the intent...
214                 @SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE")
215                 public void accept(TypedReadWriteTransaction<Datastore.Configuration> tx)
216                     throws ExecutionException, InterruptedException {
217                     TunnelsKey tunnelKey = null;
218                     String nodeId = null;
219                     String topologyId = null;
220                     Optional<Tunnels> tunnelsOptional =
221                         tx.read(getTunnelIdentifier(topologyId, nodeId, tunnelKey)).get();
222                     if (!tunnelsOptional.isPresent()) {
223                         LOG.warn("Tunnel {} is not present on the Node {}. So not disabling the BFD monitoring",
224                             tunnelKey,
225                             nodeId);
226                         return;
227                     }
228                     Tunnels tunnel = tunnelsOptional.get();
229                     @Nullable Map<BfdParamsKey, BfdParams> tunnelBfdParams = tunnel.getBfdParams();
230                     if (tunnelBfdParams == null || tunnelBfdParams.isEmpty()) {
231                         LOG.debug("there is no bfd params available for the tunnel {}", tunnel);
232                         return;
233                     }
234
235                     Iterator<BfdParams> tunnelBfdParamsIterator = tunnelBfdParams.values().iterator();
236                     while (tunnelBfdParamsIterator.hasNext()) {
237                         BfdParams bfdParam = tunnelBfdParamsIterator.next();
238                         if (AlivenessMonitorConstants.BFD_PARAM_ENABLE.equals(bfdParam.getBfdParamKey())) {
239                             tunnelBfdParamsIterator.remove();
240                             break;
241                         }
242                     }
243                     HwVtepTunnelsStateHandler.this.setBfdParamForEnable(tunnelBfdParams, isEnable);
244                     Tunnels tunnelWithBfdReset =
245                         new TunnelsBuilder().withKey(tunnelKey).setBfdParams(tunnelBfdParams).build();
246                     tx.mergeParentStructureMerge(
247                         getTunnelIdentifier(topologyId, nodeId, tunnelKey), tunnelWithBfdReset);
248                 }
249             }), LOG, "Error resetting monitoring task");
250     }
251
252     @Override
253     public void startMonitoringTask(MonitoringInfo monitorInfo) {
254         EndpointType source = monitorInfo.getSource().getEndpointType();
255         if (source instanceof Interface) {
256             Interface intf = (Interface) source;
257             intf.getInterfaceName();
258         } else {
259             LOG.warn("Invalid source endpoint. Could not retrieve source interface to configure BFD");
260             return;
261         }
262         MonitorProfile profile;
263         Uint32 profileId = monitorInfo.getProfileId();
264         java.util.Optional<MonitorProfile> optProfile = alivenessMonitor.getMonitorProfile(profileId);
265         if (optProfile.isPresent()) {
266             profile = optProfile.get();
267         } else {
268             LOG.warn("No monitor profile associated with id {}. " + "Could not send Monitor packet for monitor-id {}",
269                     profileId, monitorInfo);
270             return;
271         }
272         // TODO: get the corresponding hwvtep tunnel from the sourceInterface
273         // once InterfaceMgr
274         // Implements renderer for hwvtep VXLAN tunnels
275         String tunnelLocalMacAddress = "<TODO>";
276         String tunnelLocalIpAddress = "<TODO>";
277         String tunnelRemoteMacAddress = "<TODO>";
278         Map<BfdParamsKey, BfdParams> bfdParams = new HashMap<>();
279         fillBfdParams(bfdParams, profile);
280         List<BfdLocalConfigs> bfdLocalConfigs = new ArrayList<>();
281         fillBfdLocalConfigs(bfdLocalConfigs, tunnelLocalMacAddress, tunnelLocalIpAddress);
282         List<BfdRemoteConfigs> bfdRemoteConfigs = new ArrayList<>();
283         fillBfdRemoteConfigs(bfdRemoteConfigs, tunnelRemoteMacAddress);
284         // tunnelKey is initialized to null and passed to withKey which FindBugs flags as a
285         // "Load of known null value" violation. Not sure sure what the intent is...
286         //TunnelsKey tunnelKey = null;
287         Tunnels tunnelWithBfd = new TunnelsBuilder().withKey(/*tunnelKey*/ null).setBfdParams(bfdParams)
288                 .setBfdLocalConfigs(bfdLocalConfigs).setBfdRemoteConfigs(bfdRemoteConfigs).build();
289         // TODO: get the following parameters from the interface and use it to
290         // update hwvtep datastore
291         // and not sure sure tunnels are creating immediately once interface mgr
292         // writes termination point
293         // into hwvtep datastore. if tunnels are not created during that time,
294         // then start monitoring has to
295         // be done as part of tunnel add DCN handling.
296         String topologyId = "";
297         String nodeId = "";
298         LoggingFutures.addErrorLogging(
299             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.mergeParentStructureMerge(
300                 getTunnelIdentifier(topologyId, nodeId, new TunnelsKey(/*localRef*/ null, /*remoteRef*/ null)),
301                 tunnelWithBfd)), LOG, "Error starting a monitoring task");
302     }
303
304     private void fillBfdRemoteConfigs(List<BfdRemoteConfigs> bfdRemoteConfigs, String tunnelRemoteMacAddress) {
305         bfdRemoteConfigs
306                 .add(getBfdRemoteConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_MAC, tunnelRemoteMacAddress));
307     }
308
309     private BfdRemoteConfigs getBfdRemoteConfig(String key, String value) {
310         return new BfdRemoteConfigsBuilder().setBfdRemoteConfigKey(key).setBfdRemoteConfigValue(value)
311                 .withKey(new BfdRemoteConfigsKey(key)).build();
312     }
313
314     private void fillBfdLocalConfigs(List<BfdLocalConfigs> bfdLocalConfigs, String tunnelLocalMacAddress,
315             String tunnelLocalIpAddress) {
316         bfdLocalConfigs.add(getBfdLocalConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_MAC, tunnelLocalMacAddress));
317         bfdLocalConfigs.add(getBfdLocalConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_IP, tunnelLocalIpAddress));
318     }
319
320     private BfdLocalConfigs getBfdLocalConfig(String key, String value) {
321         return new BfdLocalConfigsBuilder().setBfdLocalConfigKey(key).withKey(new BfdLocalConfigsKey(key))
322                 .setBfdLocalConfigValue(value).build();
323     }
324
325     private void fillBfdParams(Map<BfdParamsKey, BfdParams> bfdParams, MonitorProfile profile) {
326         setBfdParamForEnable(bfdParams, true);
327         BfdParams bfdParams1 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_RX,
328                 Long.toString(profile.getMinRx().toJava()));
329         bfdParams.put(bfdParams1.key(),bfdParams1);
330
331         BfdParams bfdParams2 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_TX,
332                 Long.toString(profile.getMinTx().toJava()));
333         bfdParams.put(bfdParams2.key(), bfdParams2);
334
335         BfdParams bfdParams3 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_DECAY_MIN_RX,
336                 Long.toString(profile.getDecayMinRx().toJava()));
337         bfdParams.put(bfdParams3.key(), bfdParams3);
338
339         BfdParams bfdParams4 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_FORWARDING_IF_RX,
340                 profile.getForwardingIfRx());
341         bfdParams.put(bfdParams4.key(), bfdParams4);
342
343         BfdParams bfdParams5 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CPATH_DOWN, profile.getCpathDown());
344         bfdParams.put(bfdParams5.key(),bfdParams5);
345
346         BfdParams bfdParams6 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CHECK_TNL_KEY,
347                 profile.getCheckTnlKey());
348         bfdParams.put(bfdParams6.key(),bfdParams6);
349     }
350
351     private void setBfdParamForEnable(Map<BfdParamsKey, BfdParams> bfdParams, boolean isEnabled) {
352         bfdParams.put(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_ENABLE, Boolean.toString(isEnabled)).key(),
353                 getBfdParams(AlivenessMonitorConstants.BFD_PARAM_ENABLE, Boolean.toString(isEnabled)));
354     }
355
356     private BfdParams getBfdParams(String key, String value) {
357         return new BfdParamsBuilder().setBfdParamKey(key).withKey(new BfdParamsKey(key)).setBfdParamValue(value)
358                 .build();
359     }
360
361     @Override
362     public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
363         String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
364         return getBfdMonitorKey(interfaceName);
365     }
366
367     private String getBfdMonitorKey(String interfaceName) {
368         return interfaceName + "bfd";
369     }
370
371     private String getInterfaceName(EndpointType endpoint) {
372         String interfaceName = null;
373         if (endpoint instanceof Interface) {
374             interfaceName = ((Interface) endpoint).getInterfaceName();
375         }
376         return interfaceName;
377     }
378
379     private static InstanceIdentifier<Tunnels> getTunnelIdentifier(String topologyId, String nodeId,
380                                                                    TunnelsKey tunnelsKey) {
381         return InstanceIdentifier.builder(NetworkTopology.class)
382                 .child(Topology.class, new TopologyKey(new TopologyId(topologyId)))
383                 .child(Node.class, new NodeKey(new NodeId(nodeId))).augmentation(PhysicalSwitchAugmentation.class)
384                 .child(Tunnels.class, tunnelsKey).build();
385     }
386 }