9e69d307fafac821abf7b44ae2281841e4a00158
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / confighelpers / ItmExternalTunnelAddWorker.java
1 /*
2  * Copyright (c) 2016, 2017 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.itm.confighelpers;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
18 import org.apache.commons.net.util.SubnetUtils;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
23 import org.opendaylight.genius.itm.globals.ITMConstants;
24 import org.opendaylight.genius.itm.impl.ItmUtils;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.tunnel.optional.params.TunnelOptions;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVteps;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public class ItmExternalTunnelAddWorker {
53     private static final Logger LOG = LoggerFactory.getLogger(ItmExternalTunnelAddWorker.class);
54
55     private final DataBroker dataBroker;
56     private final ItmConfig itmConfig;
57     private final DPNTEPsInfoCache dpnTEPsInfoCache;
58
59     public ItmExternalTunnelAddWorker(DataBroker dataBroker, ItmConfig itmConfig, DPNTEPsInfoCache dpnTEPsInfoCache) {
60         this.dataBroker = dataBroker;
61         this.itmConfig = itmConfig;
62         this.dpnTEPsInfoCache = dpnTEPsInfoCache;
63     }
64
65     public List<ListenableFuture<Void>> buildTunnelsToExternalEndPoint(Collection<DPNTEPsInfo> cfgDpnList,
66             IpAddress extIp, Class<? extends TunnelTypeBase> tunType) {
67         if (null != cfgDpnList) {
68             WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
69             for (DPNTEPsInfo teps : cfgDpnList) {
70                 // CHECK -- Assumption -- Only one End Point / Dpn for GRE/Vxlan Tunnels
71                 TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0);
72                 String interfaceName = firstEndPt.getInterfaceName();
73                 String tunTypeStr = tunType.getName();
74                 String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(interfaceName,
75                         new String(firstEndPt.getIpAddress().getValue()),
76                         new String(extIp.getValue()), tunTypeStr);
77                 char[] subnetMaskArray = firstEndPt.getSubnetMask().getValue();
78                 boolean useOfTunnel = ItmUtils.falseIfNull(firstEndPt.isOptionOfTunnel());
79                 List<TunnelOptions> tunOptions = ItmUtils.buildTunnelOptions(firstEndPt, itmConfig);
80                 String subnetMaskStr = String.valueOf(subnetMaskArray);
81                 SubnetUtils utils = new SubnetUtils(subnetMaskStr);
82                 String dcGwyIpStr = String.valueOf(extIp.getValue());
83                 IpAddress gatewayIpObj = IpAddressBuilder.getDefaultInstance("0.0.0.0");
84                 IpAddress gwyIpAddress =
85                         utils.getInfo().isInRange(dcGwyIpStr) ? gatewayIpObj : firstEndPt.getGwIpAddress();
86                 LOG.debug(" Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {},"
87                         + " source IP - {}, DC Gateway IP - {} gateway IP - {}", trunkInterfaceName, interfaceName,
88                         firstEndPt.getIpAddress(), extIp, gwyIpAddress);
89                 Interface iface = ItmUtils.buildTunnelInterface(teps.getDPNID(), trunkInterfaceName,
90                     String.format("%s %s", ItmUtils.convertTunnelTypetoString(tunType), "Trunk Interface"), true,
91                     tunType, firstEndPt.getIpAddress(), extIp, gwyIpAddress, firstEndPt.getVLANID(), false, false,
92                     ITMConstants.DEFAULT_MONITOR_PROTOCOL, null, useOfTunnel, tunOptions);
93
94                 LOG.debug(" Trunk Interface builder - {} ", iface);
95                 InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
96                 LOG.debug(" Trunk Interface Identifier - {} ", trunkIdentifier);
97                 LOG.trace(" Writing Trunk Interface to Config DS {}, {} ", trunkIdentifier, iface);
98                 transaction.merge(LogicalDatastoreType.CONFIGURATION, trunkIdentifier, iface, true);
99                 // update external_tunnel_list ds
100                 InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(ExternalTunnelList.class)
101                         .child(ExternalTunnel.class, new ExternalTunnelKey(String.valueOf(extIp.getValue()),
102                                 teps.getDPNID().toString(), tunType));
103                 ExternalTunnel tnl = ItmUtils.buildExternalTunnel(teps.getDPNID().toString(),
104                     String.valueOf(extIp.getValue()), tunType, trunkInterfaceName);
105                 transaction.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
106             }
107             return Collections.singletonList(transaction.submit());
108         }
109         return Collections.emptyList();
110     }
111
112     public List<ListenableFuture<Void>> buildTunnelsFromDpnToExternalEndPoint(List<BigInteger> dpnId, IpAddress extIp,
113             Class<? extends TunnelTypeBase> tunType) {
114         Collection<DPNTEPsInfo> cfgDpnList = dpnId == null ? dpnTEPsInfoCache.getAllPresent()
115                         : ItmUtils.getDpnTepListFromDpnId(dpnTEPsInfoCache, dpnId);
116         return buildTunnelsToExternalEndPoint(cfgDpnList, extIp, tunType);
117     }
118
119     public List<ListenableFuture<Void>> buildHwVtepsTunnels(List<DPNTEPsInfo> cfgdDpnList, List<HwVtep> cfgdHwVteps) {
120         Integer monitorInterval = ITMConstants.BFD_DEFAULT_MONITOR_INTERVAL;
121         Class<? extends TunnelMonitoringTypeBase> monitorProtocol = ITMConstants.DEFAULT_MONITOR_PROTOCOL;
122
123         List<ListenableFuture<Void>> futures = new ArrayList<>();
124         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
125         if (null != cfgdDpnList && !cfgdDpnList.isEmpty()) {
126             LOG.trace("calling tunnels from css {}",cfgdDpnList);
127             tunnelsFromCSS(cfgdDpnList, writeTransaction, monitorInterval, monitorProtocol);
128         }
129         if (null != cfgdHwVteps && !cfgdHwVteps.isEmpty()) {
130             LOG.trace("calling tunnels from hwTep {}",cfgdHwVteps);
131             tunnelsFromhWVtep(cfgdHwVteps, writeTransaction, monitorInterval, monitorProtocol);
132         }
133
134         if (cfgdDpnList != null && !cfgdDpnList.isEmpty() || cfgdHwVteps != null && !cfgdHwVteps.isEmpty()) {
135             futures.add(writeTransaction.submit());
136         }
137         return futures;
138     }
139
140     private void tunnelsFromCSS(List<DPNTEPsInfo> cfgdDpnList, WriteTransaction transaction, Integer monitorInterval,
141             Class<? extends TunnelMonitoringTypeBase> monitorProtocol) {
142         for (DPNTEPsInfo dpn : cfgdDpnList) {
143             LOG.trace("processing dpn {}" , dpn);
144             if (dpn.getTunnelEndPoints() != null && !dpn.getTunnelEndPoints().isEmpty()) {
145                 for (TunnelEndPoints tep : dpn.getTunnelEndPoints()) {
146                     for (TzMembership zone: tep.getTzMembership()) {
147                         createTunnelsFromOVSinTransportZone(zone.getZoneName(), dpn, tep,
148                                 transaction, monitorInterval, monitorProtocol);
149                     }
150                 }
151             }
152         }
153     }
154
155     private void createTunnelsFromOVSinTransportZone(String zoneName, DPNTEPsInfo dpn, TunnelEndPoints tep,
156             WriteTransaction transaction, Integer monitorInterval,
157             Class<? extends TunnelMonitoringTypeBase> monitorProtocol) {
158         InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class)
159                 .child(TransportZone.class, new TransportZoneKey(zoneName)).build();
160         Optional<TransportZone> transportZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
161                 tzonePath, dataBroker);
162         if (transportZoneOptional.isPresent()) {
163             TransportZone transportZone = transportZoneOptional.get();
164             //do we need to check tunnel type?
165             if (transportZone.getSubnets() != null && !transportZone.getSubnets().isEmpty()) {
166                 for (Subnets sub : transportZone.getSubnets()) {
167                     if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
168                         for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
169                             //dont mesh if hwVteps and OVS-tep have same ip-address
170                             if (hwVtepDS.getIpAddress().equals(tep.getIpAddress())) {
171                                 continue;
172                             }
173                             final String cssID = dpn.getDPNID().toString();
174                             String nodeId = hwVtepDS.getNodeId();
175                             boolean useOfTunnel = ItmUtils.falseIfNull(tep.isOptionOfTunnel());
176                             LOG.trace("wire up {} and {}",tep, hwVtepDS);
177                             if (!wireUp(dpn.getDPNID(), tep.getPortname(), sub.getVlanId(),
178                                     tep.getIpAddress(), useOfTunnel, nodeId, hwVtepDS.getIpAddress(),
179                                     tep.getSubnetMask(), sub.getGatewayIp(), sub.getPrefix(),
180                                     transportZone.getTunnelType(), false, monitorInterval, monitorProtocol,
181                                     transaction)) {
182                                 LOG.error("Unable to build tunnel {} -- {}",
183                                         tep.getIpAddress(), hwVtepDS.getIpAddress());
184                             }
185                             //TOR-OVS
186                             LOG.trace("wire up {} and {}", hwVtepDS,tep);
187                             if (!wireUp(hwVtepDS.getTopologyId(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(),
188                                     cssID, tep.getIpAddress(), sub.getPrefix(), sub.getGatewayIp(),
189                                     tep.getSubnetMask(), transportZone.getTunnelType(), false, monitorInterval,
190                                     monitorProtocol, transaction)) {
191                                 LOG.error("Unable to build tunnel {} -- {}",
192                                         hwVtepDS.getIpAddress(), tep.getIpAddress());
193                             }
194
195                         }
196                     }
197                 }
198             }
199         }
200     }
201
202     private void tunnelsFromhWVtep(List<HwVtep> cfgdHwVteps, WriteTransaction transaction,
203             Integer monitorInterval, Class<? extends TunnelMonitoringTypeBase> monitorProtocol) {
204         for (HwVtep hwTep : cfgdHwVteps) {
205             InstanceIdentifier<TransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class)
206                     .child(TransportZone.class, new TransportZoneKey(hwTep.getTransportZone())).build();
207             Optional<TransportZone> transportZoneOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
208                     tzonePath, dataBroker);
209             Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
210             if (transportZoneOptional.isPresent()) {
211                 TransportZone tzone = transportZoneOptional.get();
212                 //do we need to check tunnel type?
213                 if (tzone.getSubnets() != null && !tzone.getSubnets().isEmpty()) {
214                     for (Subnets sub : tzone.getSubnets()) {
215                         if (sub.getDeviceVteps() != null && !sub.getDeviceVteps().isEmpty()) {
216                             for (DeviceVteps hwVtepDS : sub.getDeviceVteps()) {
217                                 if (hwVtepDS.getIpAddress().equals(hwTep.getHwIp())) {
218                                     continue;//dont mesh with self
219                                 }
220                                 LOG.trace("wire up {} and {}",hwTep, hwVtepDS);
221                                 if (!wireUp(hwTep.getTopoId(), hwTep.getNodeId(), hwTep.getHwIp(),
222                                         hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(), hwTep.getIpPrefix(),
223                                         hwTep.getGatewayIP(), sub.getPrefix(), tunType, false,
224                                         monitorInterval, monitorProtocol, transaction)) {
225                                     LOG.error("Unable to build tunnel {} -- {}",
226                                             hwTep.getHwIp(), hwVtepDS.getIpAddress());
227                                 }
228                                 //TOR2-TOR1
229                                 LOG.trace("wire up {} and {}", hwVtepDS,hwTep);
230                                 if (!wireUp(hwTep.getTopoId(), hwVtepDS.getNodeId(), hwVtepDS.getIpAddress(),
231                                         hwTep.getNodeId(), hwTep.getHwIp(), sub.getPrefix(), sub.getGatewayIp(),
232                                         hwTep.getIpPrefix(), tunType, false, monitorInterval,
233                                         monitorProtocol, transaction)) {
234                                     LOG.error("Unable to build tunnel {} -- {}",
235                                             hwVtepDS.getIpAddress(), hwTep.getHwIp());
236                                 }
237                             }
238                         }
239                         if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
240                             for (Vteps vtep : sub.getVteps()) {
241                                 if (vtep.getIpAddress().equals(hwTep.getHwIp())) {
242                                     continue;
243                                 }
244                                 //TOR-OVS
245                                 String cssID = vtep.getDpnId().toString();
246                                 LOG.trace("wire up {} and {}",hwTep, vtep);
247                                 if (!wireUp(hwTep.getTopoId(), hwTep.getNodeId(), hwTep.getHwIp(), cssID,
248                                         vtep.getIpAddress(), hwTep.getIpPrefix(), hwTep.getGatewayIP(),
249                                         sub.getPrefix(), tunType,false, monitorInterval, monitorProtocol,
250                                         transaction)) {
251                                     LOG.error("Unable to build tunnel {} -- {}",
252                                             hwTep.getHwIp(), vtep.getIpAddress());
253                                 }
254                                 //OVS-TOR
255                                 LOG.trace("wire up {} and {}", vtep,hwTep);
256                                 boolean useOfTunnel = ItmUtils.falseIfNull(vtep.isOptionOfTunnel());
257                                 if (!wireUp(vtep.getDpnId(), vtep.getPortname(), sub.getVlanId(), vtep.getIpAddress(),
258                                         useOfTunnel, hwTep.getNodeId(),hwTep.getHwIp(),sub.getPrefix(),
259                                         sub.getGatewayIp(),hwTep.getIpPrefix(), tunType, false,
260                                         monitorInterval, monitorProtocol, transaction)) {
261                                     LOG.debug("wireUp returned false");
262                                 }
263                             }
264
265                         }
266                     }
267                 }
268             }
269         }
270     }
271
272     //for tunnels from TOR device
273     private boolean wireUp(String topoId, String srcNodeid, IpAddress srcIp, String dstNodeId, IpAddress dstIp,
274             IpPrefix srcSubnet, IpAddress gwIp, IpPrefix dstSubnet, Class<? extends TunnelTypeBase> tunType,
275             Boolean monitorEnabled, Integer monitorInterval, Class<? extends TunnelMonitoringTypeBase> monitorProtocol,
276             WriteTransaction transaction) {
277         IpAddress gatewayIpObj = IpAddressBuilder.getDefaultInstance("0.0.0.0");
278         IpAddress gwyIpAddress = srcSubnet.equals(dstSubnet) ? gatewayIpObj : gwIp;
279         String parentIf =  ItmUtils.getHwParentIf(topoId, srcNodeid);
280         String tunTypeStr = tunType.getName();
281         String tunnelIfName = ItmUtils.getTrunkInterfaceName(parentIf,
282                 new String(srcIp.getValue()), new String(dstIp.getValue()), tunTypeStr);
283         LOG.debug(" Creating ExternalTrunk Interface with parameters Name - {}, parent I/f name - {}, "
284                 + "source IP - {}, destination IP - {} gateway IP - {}", tunnelIfName, parentIf, srcIp,
285                 dstIp, gwyIpAddress);
286         Interface hwTunnelIf = ItmUtils.buildHwTunnelInterface(tunnelIfName,
287                 String.format("%s %s", tunType.getName(), "Trunk Interface"), true, topoId, srcNodeid, tunType, srcIp,
288                 dstIp, gwyIpAddress, monitorEnabled, monitorProtocol, monitorInterval);
289         InstanceIdentifier<Interface> ifIID = InstanceIdentifier.builder(Interfaces.class)
290                 .child(Interface.class, new InterfaceKey(tunnelIfName)).build();
291         LOG.trace(" Writing Trunk Interface to Config DS {}, {} ", ifIID, hwTunnelIf);
292         ItmUtils.ITM_CACHE.addInterface(hwTunnelIf);
293         transaction.merge(LogicalDatastoreType.CONFIGURATION, ifIID, hwTunnelIf, true);
294         // also update itm-state ds?
295         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(ExternalTunnelList.class)
296                 .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId),
297                         getExternalTunnelKey(srcNodeid), tunType));
298         ExternalTunnel tnl = ItmUtils.buildExternalTunnel(getExternalTunnelKey(srcNodeid),
299                 getExternalTunnelKey(dstNodeId), tunType, tunnelIfName);
300         transaction.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
301         ItmUtils.ITM_CACHE.addExternalTunnel(tnl);
302         return true;
303     }
304
305     //for tunnels from OVS
306     private boolean wireUp(BigInteger dpnId, String portname, Integer vlanId, IpAddress srcIp, Boolean remoteIpFlow,
307             String dstNodeId, IpAddress dstIp, IpPrefix srcSubnet, IpAddress gwIp, IpPrefix dstSubnet,
308             Class<? extends TunnelTypeBase> tunType, Boolean monitorEnabled, Integer monitorInterval,
309             Class<? extends TunnelMonitoringTypeBase> monitorProtocol, WriteTransaction transaction) {
310         IpAddress gatewayIpObj = IpAddressBuilder.getDefaultInstance("0.0.0.0");
311         IpAddress gwyIpAddress = srcSubnet.equals(dstSubnet) ? gatewayIpObj : gwIp;
312         String parentIf = ItmUtils.getInterfaceName(dpnId, portname, vlanId);
313         String tunTypeStr = tunType.getName();
314         String tunnelIfName = ItmUtils.getTrunkInterfaceName(parentIf,
315                 new String(srcIp.getValue()), new String(dstIp.getValue()), tunTypeStr);
316         LOG.debug(" Creating ExternalTrunk Interface with parameters Name - {}, parent I/f name - {}, "
317                 + "source IP - {}, destination IP - {} gateway IP - {}", tunnelIfName, parentIf, srcIp,
318                 dstIp, gwyIpAddress);
319         Interface extTunnelIf = ItmUtils.buildTunnelInterface(dpnId, tunnelIfName,
320                 String.format("%s %s", tunType.getName(), "Trunk Interface"), true, tunType, srcIp, dstIp, gwyIpAddress,
321                 vlanId, false,monitorEnabled, monitorProtocol, monitorInterval, remoteIpFlow, null);
322         InstanceIdentifier<Interface> ifIID = InstanceIdentifier.builder(Interfaces.class).child(Interface.class,
323                 new InterfaceKey(tunnelIfName)).build();
324         LOG.trace(" Writing Trunk Interface to Config DS {}, {} ", ifIID, extTunnelIf);
325         transaction.merge(LogicalDatastoreType.CONFIGURATION, ifIID, extTunnelIf, true);
326         ItmUtils.ITM_CACHE.addInterface(extTunnelIf);
327         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(ExternalTunnelList.class)
328                 .child(ExternalTunnel.class, new ExternalTunnelKey(getExternalTunnelKey(dstNodeId),
329                         dpnId.toString(), tunType));
330         ExternalTunnel tnl = ItmUtils.buildExternalTunnel(dpnId.toString(),
331                 getExternalTunnelKey(dstNodeId),
332                 tunType, tunnelIfName);
333         transaction.merge(LogicalDatastoreType.CONFIGURATION, path, tnl, true);
334         ItmUtils.ITM_CACHE.addExternalTunnel(tnl);
335         return true;
336     }
337
338     @SuppressFBWarnings("RV_CHECK_FOR_POSITIVE_INDEXOF")
339     static String getExternalTunnelKey(String nodeid) {
340         final int index = nodeid.indexOf("physicalswitch");
341         if (index > 0) {
342             nodeid = nodeid.substring(0, index - 1);
343         }
344         return nodeid;
345     }
346
347 }