Revert "TSC-181: ITM Yang Models Cleanup"
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / confighelpers / ItmInternalTunnelAddWorker.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 static java.util.Collections.singletonList;
11 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
12 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13
14 import com.google.common.base.Optional;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.time.Duration;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Objects;
23 import java.util.concurrent.Callable;
24 import java.util.concurrent.ExecutionException;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
29 import org.opendaylight.genius.infra.Datastore.Configuration;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
31 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
32 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
33 import org.opendaylight.genius.infra.TypedWriteTransaction;
34 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
35 import org.opendaylight.genius.itm.cache.OfEndPointCache;
36 import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
37 import org.opendaylight.genius.itm.globals.ITMConstants;
38 import org.opendaylight.genius.itm.impl.ITMBatchingUtils;
39 import org.opendaylight.genius.itm.impl.ItmUtils;
40 import org.opendaylight.genius.itm.impl.TunnelMonitoringConfig;
41 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
42 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
43 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeLldp;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.tunnel.optional.params.TunnelOptions;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.OvsBridgeRefInfo;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpointsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepsState;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepsStateBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTeps;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTepsBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTepsKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpns;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnelKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.opendaylight.yangtools.yang.common.OperationFailedException;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 public final class ItmInternalTunnelAddWorker {
82
83     private static final Logger LOG = LoggerFactory.getLogger(ItmInternalTunnelAddWorker.class) ;
84
85     private final ItmConfig itmCfg;
86     private final Integer monitorInterval;
87     private final boolean isTunnelMonitoringEnabled;
88     private final Class<? extends TunnelMonitoringTypeBase> monitorProtocol;
89
90     private final DataBroker dataBroker;
91     private final ManagedNewTransactionRunner txRunner;
92     private final JobCoordinator jobCoordinator;
93     private final DirectTunnelUtils directTunnelUtils;
94     private final IInterfaceManager interfaceManager;
95     private final OvsBridgeRefEntryCache ovsBridgeRefEntryCache;
96     private final OfEndPointCache ofEndPointCache;
97     private final DataTreeEventCallbackRegistrar eventCallbacks;
98
99     public ItmInternalTunnelAddWorker(DataBroker dataBroker, JobCoordinator jobCoordinator,
100                                       TunnelMonitoringConfig tunnelMonitoringConfig, ItmConfig itmCfg,
101                                       DirectTunnelUtils directTunnelUtil,
102                                       IInterfaceManager interfaceManager,
103                                       OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
104                                       OfEndPointCache ofEndPointCache,
105                                       DataTreeEventCallbackRegistrar eventCallbacks) {
106         this.dataBroker = dataBroker;
107         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
108         this.jobCoordinator = jobCoordinator;
109         this.itmCfg = itmCfg;
110         this.directTunnelUtils = directTunnelUtil;
111         this.interfaceManager = interfaceManager;
112         this.ovsBridgeRefEntryCache = ovsBridgeRefEntryCache;
113         this.ofEndPointCache = ofEndPointCache;
114         this.eventCallbacks = eventCallbacks;
115
116         isTunnelMonitoringEnabled = tunnelMonitoringConfig.isTunnelMonitoringEnabled();
117         monitorProtocol = tunnelMonitoringConfig.getMonitorProtocol();
118         monitorInterval = tunnelMonitoringConfig.getMonitorInterval();
119     }
120
121     public List<ListenableFuture<Void>> buildAllTunnels(IMdsalApiManager mdsalManager, List<DPNTEPsInfo> cfgdDpnList,
122                                                         Collection<DPNTEPsInfo> meshedDpnList) {
123         LOG.trace("Building tunnels with DPN List {} " , cfgdDpnList);
124         if (null == cfgdDpnList || cfgdDpnList.isEmpty()) {
125             LOG.error(" Build Tunnels was invoked with empty list");
126             return Collections.emptyList();
127         }
128
129         return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
130             for (DPNTEPsInfo dpn : cfgdDpnList) {
131                 //#####if dpn is not in meshedDpnList
132                 buildTunnelFrom(tx, dpn, meshedDpnList, mdsalManager);
133                 if (meshedDpnList != null) {
134                     meshedDpnList.add(dpn);
135                 }
136                 // Update the config datastore -- FIXME -- Error Handling
137                 updateDpnTepInfoToConfig(tx, dpn, directTunnelUtils);
138             }
139         }));
140     }
141
142     private static void updateDpnTepInfoToConfig(TypedWriteTransaction<Configuration> tx, DPNTEPsInfo dpn,
143         DirectTunnelUtils directTunnelUtils) throws ExecutionException, InterruptedException, OperationFailedException {
144         LOG.debug("Updating CONFIGURATION datastore with DPN {} ", dpn);
145         InstanceIdentifier<DpnEndpoints> dep = InstanceIdentifier.builder(DpnEndpoints.class).build() ;
146         List<DPNTEPsInfo> dpnList = new ArrayList<>() ;
147         dpnList.add(new DPNTEPsInfoBuilder(dpn)
148             .setDstId(directTunnelUtils.allocateId(ITMConstants.ITM_IDPOOL_NAME, dpn.getDPNID().toString())).build());
149         DpnEndpoints tnlBuilder = new DpnEndpointsBuilder().setDPNTEPsInfo(dpnList).build() ;
150         tx.merge(dep, tnlBuilder);
151     }
152
153     private void buildTunnelFrom(TypedReadWriteTransaction<Configuration> tx, DPNTEPsInfo srcDpn,
154         Collection<DPNTEPsInfo> meshedDpnList, IMdsalApiManager mdsalManager)
155         throws ExecutionException, InterruptedException, OperationFailedException {
156         LOG.trace("Building tunnels from DPN {} " , srcDpn);
157         if (null == meshedDpnList || meshedDpnList.isEmpty()) {
158             LOG.debug("No DPN in the mesh ");
159             return ;
160         }
161         for (DPNTEPsInfo dstDpn: meshedDpnList) {
162             if (!srcDpn.equals(dstDpn)) {
163                 wireUpWithinTransportZone(tx, srcDpn, dstDpn, mdsalManager);
164             }
165         }
166
167     }
168
169     private void wireUpWithinTransportZone(TypedReadWriteTransaction<Configuration> tx, DPNTEPsInfo srcDpn,
170         DPNTEPsInfo dstDpn, IMdsalApiManager mdsalManager)
171         throws ExecutionException, InterruptedException, OperationFailedException {
172         LOG.trace("Wiring up within Transport Zone for Dpns {}, {} " , srcDpn, dstDpn);
173         List<TunnelEndPoints> srcEndPts = srcDpn.nonnullTunnelEndPoints();
174         List<TunnelEndPoints> dstEndPts = dstDpn.nonnullTunnelEndPoints();
175
176         for (TunnelEndPoints srcte : srcEndPts) {
177             for (TunnelEndPoints dstte : dstEndPts) {
178                 // Compare the Transport zones
179                 if (!Objects.equals(srcDpn.getDPNID(), dstDpn.getDPNID())) {
180                     if (!ItmUtils.getIntersection(srcte.nonnullTzMembership(),
181                             dstte.nonnullTzMembership()).isEmpty()) {
182                         // wire them up
183                         wireUpBidirectionalTunnel(tx, srcte, dstte, srcDpn.getDPNID(), dstDpn.getDPNID(),
184                                 mdsalManager);
185                         if (!ItmTunnelAggregationHelper.isTunnelAggregationEnabled()) {
186                             // CHECK THIS -- Assumption -- One end point per Dpn per transport zone
187                             break;
188                         }
189                     }
190                 }
191             }
192         }
193     }
194
195     private void wireUpBidirectionalTunnel(TypedReadWriteTransaction<Configuration> tx, TunnelEndPoints srcte,
196         TunnelEndPoints dstte, BigInteger srcDpnId, BigInteger dstDpnId, IMdsalApiManager mdsalManager)
197         throws ExecutionException, InterruptedException, OperationFailedException {
198         // Setup the flow for LLDP monitoring -- PUNT TO CONTROLLER
199
200         if (monitorProtocol.isAssignableFrom(TunnelMonitoringTypeLldp.class)) {
201             ItmUtils.addTerminatingServiceTable(tx, srcDpnId, mdsalManager);
202             ItmUtils.addTerminatingServiceTable(tx, dstDpnId, mdsalManager);
203         }
204         // Create the forward direction tunnel
205         if (!wireUp(tx, srcte, dstte, srcDpnId, dstDpnId)) {
206             LOG.error("Could not build tunnel between end points {}, {} " , srcte, dstte);
207         }
208
209         // CHECK IF FORWARD IS NOT BUILT , REVERSE CAN BE BUILT
210         // Create the tunnel for the reverse direction
211         if (!wireUp(tx, dstte, srcte, dstDpnId, srcDpnId)) {
212             LOG.error("Could not build tunnel between end points {}, {} " , dstte, srcte);
213         }
214     }
215
216     private boolean wireUp(TypedWriteTransaction<Configuration> tx, TunnelEndPoints srcte, TunnelEndPoints dstte,
217         BigInteger srcDpnId, BigInteger dstDpnId)
218         throws ExecutionException, InterruptedException, OperationFailedException {
219         // Wire Up logic
220         LOG.trace("Wiring between source tunnel end points {}, destination tunnel end points {}", srcte, dstte);
221         String interfaceName = srcte.getInterfaceName();
222         Class<? extends TunnelTypeBase> tunType = srcte.getTunnelType();
223         String tunTypeStr = srcte.getTunnelType().getName();
224         // Form the trunk Interface Name
225
226         String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(interfaceName,
227                 srcte.getIpAddress().stringValue(), dstte.getIpAddress().stringValue(), tunTypeStr);
228         String parentInterfaceName = null;
229         if (tunType.isAssignableFrom(TunnelTypeVxlan.class)) {
230             parentInterfaceName = createLogicalGroupTunnel(srcDpnId, dstDpnId);
231         }
232         if (interfaceManager.isItmDirectTunnelsEnabled()) {
233             createInternalDirectTunnels(srcte, dstte, srcDpnId, dstDpnId, tunType, trunkInterfaceName,
234                     parentInterfaceName);
235         } else {
236             createTunnelInterface(srcte, dstte, srcDpnId, tunType, trunkInterfaceName, parentInterfaceName);
237             // also update itm-state ds?
238             createInternalTunnel(tx, srcDpnId, dstDpnId, tunType, trunkInterfaceName);
239         }
240         return true;
241     }
242
243     private void createTunnelInterface(TunnelEndPoints srcte, TunnelEndPoints dstte, BigInteger srcDpnId,
244             Class<? extends TunnelTypeBase> tunType, String trunkInterfaceName, String parentInterfaceName) {
245         String gateway = srcte.getIpAddress().getIpv4Address() != null ? "0.0.0.0" : "::";
246         IpAddress gatewayIpObj = IpAddressBuilder.getDefaultInstance(gateway);
247         IpAddress gwyIpAddress =
248                 Objects.equals(srcte.getSubnetMask(), dstte.getSubnetMask()) ? gatewayIpObj : srcte.getGwIpAddress();
249         LOG.debug(" Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {}, "
250                 + "source IP - {}, destination IP - {} gateway IP - {}",
251                 trunkInterfaceName, srcte.getInterfaceName(), srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress);
252         boolean useOfTunnel = ItmUtils.falseIfNull(srcte.isOptionOfTunnel());
253
254         List<TunnelOptions> tunOptions = ItmUtils.buildTunnelOptions(srcte, itmCfg);
255         Boolean isMonitorEnabled = !tunType.isAssignableFrom(TunnelTypeLogicalGroup.class) && isTunnelMonitoringEnabled;
256         Interface iface = ItmUtils.buildTunnelInterface(srcDpnId, trunkInterfaceName,
257                 String.format("%s %s",ItmUtils.convertTunnelTypetoString(tunType), "Trunk Interface"),
258                 true, tunType, srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress, srcte.getVLANID(), true,
259                 isMonitorEnabled, monitorProtocol, monitorInterval, useOfTunnel, parentInterfaceName, tunOptions);
260         LOG.debug(" Trunk Interface builder - {} ", iface);
261         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
262         LOG.debug(" Trunk Interface Identifier - {} ", trunkIdentifier);
263         LOG.trace(" Writing Trunk Interface to Config DS {}, {} ", trunkIdentifier, iface);
264         ITMBatchingUtils.update(trunkIdentifier, iface, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
265         ItmUtils.ITM_CACHE.addInterface(iface);
266     }
267
268     private static void createLogicalTunnelInterface(BigInteger srcDpnId,
269             Class<? extends TunnelTypeBase> tunType, String interfaceName) {
270         Interface iface = ItmUtils.buildLogicalTunnelInterface(srcDpnId, interfaceName,
271                 String.format("%s %s",ItmUtils.convertTunnelTypetoString(tunType), "Interface"), true);
272         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(interfaceName);
273         ITMBatchingUtils.update(trunkIdentifier, iface, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
274         ItmUtils.ITM_CACHE.addInterface(iface);
275     }
276
277     private static void createInternalTunnel(TypedWriteTransaction<Configuration> tx, BigInteger srcDpnId,
278         BigInteger dstDpnId, Class<? extends TunnelTypeBase> tunType, String trunkInterfaceName) {
279         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
280                 .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, tunType));
281         InternalTunnel tnl = ItmUtils.buildInternalTunnel(srcDpnId, dstDpnId, tunType, trunkInterfaceName);
282         // Switching to individual transaction submit as batching latencies is causing ELAN failures.
283         // Will revert when ELAN can handle this.
284         // ITMBatchingUtils.update(path, tnl, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
285         tx.merge(path, tnl, CREATE_MISSING_PARENTS);
286         ItmUtils.ITM_CACHE.addInternalTunnel(tnl);
287     }
288
289     private String createLogicalGroupTunnel(BigInteger srcDpnId, BigInteger dstDpnId) {
290         boolean tunnelAggregationEnabled = ItmTunnelAggregationHelper.isTunnelAggregationEnabled();
291         if (!tunnelAggregationEnabled) {
292             return null;
293         }
294         String logicTunnelGroupName = ItmUtils.getLogicalTunnelGroupName(srcDpnId, dstDpnId);
295         ItmTunnelAggregationWorker addWorker =
296                 new ItmTunnelAggregationWorker(logicTunnelGroupName, srcDpnId, dstDpnId, dataBroker);
297         jobCoordinator.enqueueJob(logicTunnelGroupName, addWorker);
298         return logicTunnelGroupName;
299     }
300
301     private static class ItmTunnelAggregationWorker implements Callable<List<ListenableFuture<Void>>> {
302
303         private final String logicTunnelGroupName;
304         private final BigInteger srcDpnId;
305         private final BigInteger dstDpnId;
306         private final ManagedNewTransactionRunner txRunner;
307
308         ItmTunnelAggregationWorker(String logicGroupName, BigInteger srcDpnId, BigInteger dstDpnId, DataBroker broker) {
309             this.logicTunnelGroupName = logicGroupName;
310             this.srcDpnId = srcDpnId;
311             this.dstDpnId = dstDpnId;
312             this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
313         }
314
315         @Override
316         public List<ListenableFuture<Void>> call() {
317             return singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
318                 //The logical tunnel interface be created only when the first tunnel interface on each OVS is created
319                 InternalTunnel tunnel = ItmUtils.ITM_CACHE.getInternalTunnel(logicTunnelGroupName);
320                 if (tunnel == null) {
321                     LOG.info("MULTIPLE_VxLAN_TUNNELS: add the logical tunnel group {} because a first tunnel"
322                         + " interface on srcDpnId {} dstDpnId {} is created", logicTunnelGroupName, srcDpnId, dstDpnId);
323                     createLogicalTunnelInterface(srcDpnId, TunnelTypeLogicalGroup.class, logicTunnelGroupName);
324                     createInternalTunnel(tx, srcDpnId, dstDpnId, TunnelTypeLogicalGroup.class, logicTunnelGroupName);
325                 } else {
326                     LOG.debug("MULTIPLE_VxLAN_TUNNELS: not first tunnel on srcDpnId {} dstDpnId {}", srcDpnId,
327                             dstDpnId);
328                 }
329             }));
330         }
331     }
332
333     private void createInternalDirectTunnels(TunnelEndPoints srcte, TunnelEndPoints dstte, BigInteger srcDpnId,
334         BigInteger dstDpnId, Class<? extends TunnelTypeBase> tunType, String trunkInterfaceName,
335         String parentInterfaceName) throws ExecutionException, InterruptedException, OperationFailedException {
336         IpAddress gatewayIpObj = IpAddressBuilder.getDefaultInstance("0.0.0.0");
337         IpAddress gwyIpAddress = Objects.equals(srcte.getSubnetMask(), dstte.getSubnetMask())
338                 ? gatewayIpObj : srcte.getGwIpAddress() ;
339         LOG.debug("Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {}, source IP - {},"
340                         + " destination IP - {} gateway IP - {}", trunkInterfaceName, parentInterfaceName,
341                 srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress) ;
342
343         boolean useOfTunnel = ItmUtils.falseIfNull(srcte.isOptionOfTunnel());
344
345         List<TunnelOptions> tunOptions = ItmUtils.buildTunnelOptions(srcte, itmCfg);
346         Boolean isMonitorEnabled = !tunType.isAssignableFrom(TunnelTypeLogicalGroup.class) && isTunnelMonitoringEnabled;
347         Interface iface = ItmUtils.buildTunnelInterface(srcDpnId, trunkInterfaceName,
348                 String.format("%s %s",ItmUtils.convertTunnelTypetoString(srcte.getTunnelType()), "Trunk Interface"),
349                 true, tunType, srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress, srcte.getVLANID(),
350                 true, isMonitorEnabled, monitorProtocol, monitorInterval, useOfTunnel, parentInterfaceName, tunOptions);
351         LOG.debug("Trunk Interface builder - {} ", iface);
352
353         final DpnTepsStateBuilder dpnTepsStateBuilder = new DpnTepsStateBuilder();
354         final DpnsTepsBuilder dpnsTepsBuilder = new DpnsTepsBuilder();
355         final List<DpnsTeps> dpnTeps = new ArrayList<>();
356         final List<RemoteDpns> remoteDpns = new ArrayList<>();
357         String ofTunnelPortName = null;
358         dpnsTepsBuilder.withKey(new DpnsTepsKey(srcDpnId));
359         dpnsTepsBuilder.setTunnelType(srcte.getTunnelType());
360         dpnsTepsBuilder.setSourceDpnId(srcDpnId);
361         if (itmCfg.isUseOfTunnels()) {
362             String tunnelType = ItmUtils.convertTunnelTypetoString(srcte.getTunnelType());
363             ofTunnelPortName = directTunnelUtils.generateOfPortName(srcDpnId, tunnelType);
364             dpnsTepsBuilder.setOfTunnel(ofTunnelPortName);
365         }
366
367         RemoteDpnsBuilder remoteDpn = new RemoteDpnsBuilder();
368         remoteDpn.withKey(new RemoteDpnsKey(dstDpnId));
369         remoteDpn.setDestinationDpnId(dstDpnId);
370         remoteDpn.setTunnelName(trunkInterfaceName);
371         remoteDpn.setMonitoringEnabled(isTunnelMonitoringEnabled);
372         remoteDpn.setMonitoringInterval(monitorInterval);
373         remoteDpn.setInternal(true);
374         remoteDpns.add(remoteDpn.build());
375         dpnsTepsBuilder.setRemoteDpns(remoteDpns);
376         dpnTeps.add(dpnsTepsBuilder.build());
377         dpnTepsStateBuilder.setDpnsTeps(dpnTeps);
378         updateDpnTepInterfaceInfoToConfig(dpnTepsStateBuilder.build());
379         addTunnelConfiguration(iface, ofTunnelPortName);
380     }
381
382     private static void updateDpnTepInterfaceInfoToConfig(DpnTepsState dpnTeps) {
383         LOG.debug("Updating CONFIGURATION datastore with DPN-Teps {} ", dpnTeps);
384         InstanceIdentifier<DpnTepsState> dpnTepsII = InstanceIdentifier.builder(DpnTepsState.class).build() ;
385         ITMBatchingUtils.update(dpnTepsII, dpnTeps, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
386     }
387
388     private void addTunnelConfiguration(Interface iface, String ofTunnelPortName)
389                                                                 throws ReadFailedException {
390         // ITM Direct Tunnels This transaction is not being used -- CHECK
391         ParentRefs parentRefs = iface.augmentation(ParentRefs.class);
392         if (parentRefs == null) {
393             LOG.warn("ParentRefs for interface: {} Not Found. Creation of Tunnel OF-Port not supported"
394                     + " when dpid not provided.", iface.getName());
395             return;
396         }
397
398         BigInteger dpId = parentRefs.getDatapathNodeIdentifier();
399         if (dpId == null) {
400             LOG.warn("dpid for interface: {} Not Found. No DPID provided. Creation of OF-Port not supported.",
401                     iface.getName());
402             return;
403         }
404         String tunnelName = ofTunnelPortName != null ? ofTunnelPortName : iface.getName();
405         // create bridge on switch, if switch is connected
406         Optional<OvsBridgeRefEntry> ovsBridgeRefEntry = ovsBridgeRefEntryCache.get(dpId);
407         LOG.info("adding tunnel port configuration for tunnelName: {}", tunnelName);
408         if (createTunnelPort(dpId)) {
409             LOG.debug("creating dpn tunnel mapping  for dpn: {} tunnelName: {}", dpId, tunnelName);
410             DirectTunnelUtils.createBridgeTunnelEntryInConfigDS(dpId, tunnelName);
411             if (ofTunnelPortName != null) {
412                 ofEndPointCache.add(dpId, tunnelName);
413             }
414             if (ovsBridgeRefEntry.isPresent()) {
415                 LOG.debug("creating bridge interface on dpn {}", dpId);
416                 InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
417                         (InstanceIdentifier<OvsdbBridgeAugmentation>) ovsBridgeRefEntry.get()
418                                 .getOvsBridgeReference().getValue();
419                 LOG.debug("adding port to the bridge:{} tunnelName: {}", bridgeIid, tunnelName);
420                 addPortToBridge(bridgeIid, iface, tunnelName);
421             } else {
422                 LOG.debug("Bridge not found. Registering Eventcallback for dpid {}", dpId);
423
424                 InstanceIdentifier<OvsBridgeRefEntry> bridgeRefEntryFromDS =
425                         InstanceIdentifier.builder(OvsBridgeRefInfo.class)
426                                 .child(OvsBridgeRefEntry.class, new OvsBridgeRefEntryKey(dpId)).build();
427
428                 eventCallbacks.onAdd(LogicalDatastoreType.OPERATIONAL, bridgeRefEntryFromDS, (refEntryIid) -> {
429                     addPortToBridgeOnCallback(iface, iface.getName(), refEntryIid);
430                     return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
431                 }, Duration.ofMillis(5000), (id) -> {
432                         try {
433                             Optional<OvsBridgeRefEntry> ovsBridgeRefEntryOnCallback = ovsBridgeRefEntryCache.get(dpId);
434                             InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIidOnCallback =
435                                     (InstanceIdentifier<OvsdbBridgeAugmentation>) ovsBridgeRefEntryOnCallback.get()
436                                             .getOvsBridgeReference().getValue();
437                             addPortToBridge(bridgeIidOnCallback, iface, iface.getName());
438                         }   catch (ReadFailedException e) {
439                             LOG.error("Bridge not found in DS/cache for dpId {}", dpId);
440                         }
441                     });
442             }
443         }
444     }
445
446     private void addPortToBridge(InstanceIdentifier<?> bridgeIid, Interface iface, String portName) {
447         IfTunnel ifTunnel = iface.augmentation(IfTunnel.class);
448         if (ifTunnel != null) {
449             directTunnelUtils.addTunnelPortToBridge(ifTunnel, bridgeIid, iface, portName);
450         }
451     }
452
453     private boolean createTunnelPort(BigInteger dpId) {
454         if (!itmCfg.isUseOfTunnels()) {
455             return true;
456         }
457         return (ofEndPointCache.get(dpId) == null);
458     }
459
460     private void addPortToBridgeOnCallback(Interface iface, String portName, OvsBridgeRefEntry bridgeRefEntry) {
461         InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid =
462                 (InstanceIdentifier<OvsdbBridgeAugmentation>) bridgeRefEntry.getOvsBridgeReference().getValue();
463         addPortToBridge(bridgeIid, iface, portName);
464     }
465 }