d44a6a35c8277bb239222be84f9c3e284dfd2ca1
[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 com.google.common.util.concurrent.FutureCallback;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.concurrent.Callable;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
21 import org.opendaylight.genius.itm.impl.ITMBatchingUtils;
22 import org.opendaylight.genius.itm.impl.ItmUtils;
23 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBase;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeLldp;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.tunnel.optional.params.TunnelOptions;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpointsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList;
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.tunnel.list.InternalTunnel;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnelKey;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class ItmInternalTunnelAddWorker {
46
47     private static final Logger LOG = LoggerFactory.getLogger(ItmInternalTunnelAddWorker.class) ;
48     private static Boolean monitorEnabled;
49     private static Integer monitorInterval;
50     private static ItmConfig itmCfg;
51     private static Class<? extends TunnelMonitoringTypeBase> monitorProtocol;
52     private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
53         @Override
54         public void onSuccess(Void result) {
55             LOG.debug("Success in Datastore operation");
56         }
57
58         @Override
59         public void onFailure(Throwable error) {
60             LOG.error("Error in Datastore operation", error);
61         }
62     };
63
64     public static List<ListenableFuture<Void>> build_all_tunnels(DataBroker dataBroker,
65                                                                  IdManagerService idManagerService,
66                                                                  IMdsalApiManager mdsalManager,
67                                                                  List<DPNTEPsInfo> cfgdDpnList,
68                                                                  List<DPNTEPsInfo> meshedDpnList,
69                                                                  ItmConfig itmConfig) {
70         LOG.trace("Building tunnels with DPN List {} " , cfgdDpnList);
71         monitorInterval = ItmUtils.determineMonitorInterval(dataBroker);
72         monitorProtocol = ItmUtils.determineMonitorProtocol(dataBroker);
73         monitorEnabled = ItmUtils.readMonitoringStateFromCache(dataBroker);
74         itmCfg = itmConfig;
75         List<ListenableFuture<Void>> futures = new ArrayList<>();
76         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
77         if (null == cfgdDpnList || cfgdDpnList.isEmpty()) {
78             LOG.error(" Build Tunnels was invoked with empty list");
79             return futures;
80         }
81
82         for (DPNTEPsInfo dpn : cfgdDpnList) {
83             //#####if dpn is not in meshedDpnList
84             build_tunnel_from(dpn, meshedDpnList, dataBroker, idManagerService, mdsalManager, transaction, futures);
85             if (null == meshedDpnList) {
86                 meshedDpnList = new ArrayList<>();
87             }
88             meshedDpnList.add(dpn);
89             // Update the operational datastore -- FIXME -- Error Handling
90             updateOperationalDatastore(dataBroker, dpn, transaction, futures);
91         }
92         futures.add(transaction.submit()) ;
93         return futures ;
94     }
95
96     private static void updateOperationalDatastore(DataBroker dataBroker, DPNTEPsInfo dpn,
97                                                    WriteTransaction transaction, List<ListenableFuture<Void>> futures) {
98         LOG.debug("Updating CONFIGURATION datastore with DPN {} ", dpn);
99         InstanceIdentifier<DpnEndpoints> dep = InstanceIdentifier.builder(DpnEndpoints.class).build() ;
100         List<DPNTEPsInfo> dpnList = new ArrayList<>() ;
101         dpnList.add(dpn) ;
102         DpnEndpoints tnlBuilder = new DpnEndpointsBuilder().setDPNTEPsInfo(dpnList).build() ;
103         ITMBatchingUtils.update(dep, tnlBuilder, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
104     }
105
106     private static void build_tunnel_from(DPNTEPsInfo srcDpn,List<DPNTEPsInfo> meshedDpnList, DataBroker dataBroker,
107                                           IdManagerService idManagerService, IMdsalApiManager mdsalManager,
108                                           WriteTransaction transaction, List<ListenableFuture<Void>> futures) {
109         LOG.trace("Building tunnels from DPN {} " , srcDpn);
110         if (null == meshedDpnList || 0 == meshedDpnList.size()) {
111             LOG.debug("No DPN in the mesh ");
112             return ;
113         }
114         for (DPNTEPsInfo dstDpn: meshedDpnList) {
115             if (!srcDpn.equals(dstDpn)) {
116                 wireUpWithinTransportZone(srcDpn, dstDpn, dataBroker, idManagerService, mdsalManager,
117                         transaction, futures);
118             }
119         }
120
121     }
122
123     private static void wireUpWithinTransportZone(DPNTEPsInfo srcDpn, DPNTEPsInfo dstDpn, DataBroker dataBroker,
124                                                   IdManagerService idManagerService, IMdsalApiManager mdsalManager,
125                                                   WriteTransaction transaction, List<ListenableFuture<Void>> futures) {
126         LOG.trace("Wiring up within Transport Zone for Dpns {}, {} " , srcDpn, dstDpn);
127         List<TunnelEndPoints> srcEndPts = srcDpn.getTunnelEndPoints();
128         List<TunnelEndPoints> dstEndPts = dstDpn.getTunnelEndPoints();
129
130         for (TunnelEndPoints srcte : srcEndPts) {
131             for (TunnelEndPoints dstte : dstEndPts) {
132                 // Compare the Transport zones
133                 if (!srcDpn.getDPNID().equals(dstDpn.getDPNID())) {
134                     if (!ItmUtils.getIntersection(srcte.getTzMembership(), dstte.getTzMembership()).isEmpty()) {
135                         // wire them up
136                         wireUpBidirectionalTunnel(srcte, dstte, srcDpn.getDPNID(), dstDpn.getDPNID(), dataBroker,
137                                 idManagerService, mdsalManager, transaction, futures);
138                         if (!ItmTunnelAggregationHelper.isTunnelAggregationEnabled()) {
139                             // CHECK THIS -- Assumption -- One end point per Dpn per transport zone
140                             break;
141                         }
142                     }
143                 }
144             }
145         }
146     }
147
148     private static void wireUpBidirectionalTunnel(TunnelEndPoints srcte, TunnelEndPoints dstte, BigInteger srcDpnId,
149                                                   BigInteger dstDpnId, DataBroker dataBroker,
150                                                   IdManagerService idManagerService, IMdsalApiManager mdsalManager,
151                                                   WriteTransaction transaction, List<ListenableFuture<Void>> futures) {
152         // Setup the flow for LLDP monitoring -- PUNT TO CONTROLLER
153
154         if (monitorProtocol.isAssignableFrom(TunnelMonitoringTypeLldp.class)) {
155             ItmUtils.setUpOrRemoveTerminatingServiceTable(srcDpnId, mdsalManager, true);
156             ItmUtils.setUpOrRemoveTerminatingServiceTable(dstDpnId, mdsalManager, true);
157         }
158         // Create the forward direction tunnel
159         if (!wireUp(srcte, dstte, srcDpnId, dstDpnId, dataBroker, idManagerService, mdsalManager,
160                     transaction, futures)) {
161             LOG.error("Could not build tunnel between end points {}, {} " , srcte, dstte);
162         }
163
164         // CHECK IF FORWARD IS NOT BUILT , REVERSE CAN BE BUILT
165         // Create the tunnel for the reverse direction
166         if (!wireUp(dstte, srcte, dstDpnId, srcDpnId, dataBroker, idManagerService, mdsalManager,
167                     transaction, futures)) {
168             LOG.error("Could not build tunnel between end points {}, {} " , dstte, srcte);
169         }
170     }
171
172     private static boolean wireUp(TunnelEndPoints srcte, TunnelEndPoints dstte,
173                                   BigInteger srcDpnId, BigInteger dstDpnId,
174                                   DataBroker dataBroker, IdManagerService idManagerService,
175                                   IMdsalApiManager mdsalManager, WriteTransaction transaction,
176                                   List<ListenableFuture<Void>> futures) {
177         // Wire Up logic
178         LOG.trace("Wiring between source tunnel end points {}, destination tunnel end points {}", srcte, dstte);
179         String interfaceName = srcte.getInterfaceName();
180         Class<? extends TunnelTypeBase> tunType = srcte.getTunnelType();
181         String tunTypeStr = srcte.getTunnelType().getName();
182         // Form the trunk Interface Name
183
184         String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName,
185                 new String(srcte.getIpAddress().getValue()),
186                 new String(dstte.getIpAddress().getValue()),
187                 tunTypeStr);
188         String parentInterfaceName = null;
189         if (tunType.isAssignableFrom(TunnelTypeVxlan.class)) {
190             parentInterfaceName = createLogicalGroupTunnel(srcDpnId, dstDpnId, dataBroker);
191         }
192         createTunnelInterface(srcte, dstte, srcDpnId, dstDpnId, tunType, trunkInterfaceName, parentInterfaceName);
193         // also update itm-state ds?
194         createInternalTunnel(srcDpnId, dstDpnId, tunType, trunkInterfaceName, transaction);
195         return true;
196     }
197
198     private static void createTunnelInterface(TunnelEndPoints srcte, TunnelEndPoints dstte,
199                                              BigInteger srcDpnId, BigInteger dstDpnId,
200                                              Class<? extends TunnelTypeBase> tunType,
201                                              String trunkInterfaceName, String parentInterfaceName) {
202         String gateway = srcte.getIpAddress().getIpv4Address() != null ? "0.0.0.0" : "::";
203         IpAddress gatewayIpObj = new IpAddress(gateway.toCharArray());
204         IpAddress gwyIpAddress =
205                 srcte.getSubnetMask().equals(dstte.getSubnetMask()) ? gatewayIpObj : srcte.getGwIpAddress() ;
206         LOG.debug(" Creating Trunk Interface with parameters trunk I/f Name - {}, parent I/f name - {}, "
207                 + "source IP - {}, destination IP - {} gateway IP - {}",
208                 trunkInterfaceName, srcte.getInterfaceName(), srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress);
209         boolean useOfTunnel = ItmUtils.falseIfNull(srcte.isOptionOfTunnel());
210         List<TunnelOptions> tunOptions = ItmUtils.buildTunnelOptions(srcte, itmCfg);
211         Interface iface = ItmUtils.buildTunnelInterface(srcDpnId, trunkInterfaceName,
212                 String.format("%s %s",ItmUtils.convertTunnelTypetoString(tunType), "Trunk Interface"),
213                 true, tunType, srcte.getIpAddress(), dstte.getIpAddress(), gwyIpAddress, srcte.getVLANID(), true,
214                 monitorEnabled, monitorProtocol, monitorInterval, useOfTunnel, parentInterfaceName, tunOptions);
215         LOG.debug(" Trunk Interface builder - {} ", iface);
216         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkInterfaceName);
217         LOG.debug(" Trunk Interface Identifier - {} ", trunkIdentifier);
218         LOG.trace(" Writing Trunk Interface to Config DS {}, {} ", trunkIdentifier, iface);
219         ITMBatchingUtils.update(trunkIdentifier, iface, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
220         ItmUtils.itmCache.addInterface(iface);
221     }
222
223     private static void createLogicalTunnelInterface(BigInteger srcDpnId, BigInteger dstDpnId,
224             Class<? extends TunnelTypeBase> tunType, String interfaceName) {
225         Interface iface = ItmUtils.buildLogicalTunnelInterface(srcDpnId, interfaceName,
226                 String.format("%s %s",ItmUtils.convertTunnelTypetoString(tunType), "Interface"), true);
227         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(interfaceName);
228         ITMBatchingUtils.update(trunkIdentifier, iface, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
229         ItmUtils.itmCache.addInterface(iface);
230     }
231
232     private static void createInternalTunnel(BigInteger srcDpnId, BigInteger dstDpnId,
233                                              Class<? extends TunnelTypeBase> tunType,
234                                              String trunkInterfaceName, WriteTransaction transaction) {
235         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
236                 .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, tunType));
237         InternalTunnel tnl = ItmUtils.buildInternalTunnel(srcDpnId, dstDpnId, tunType, trunkInterfaceName);
238         // Switching to individual transaction submit as batching latencies is causing ELAN failures.
239         // Will revert when ELAN can handle this.
240         // ITMBatchingUtils.update(path, tnl, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
241         transaction.merge(LogicalDatastoreType.CONFIGURATION,path, tnl, true) ;
242         ItmUtils.itmCache.addInternalTunnel(tnl);
243     }
244
245     private static String createLogicalGroupTunnel(BigInteger srcDpnId, BigInteger dstDpnId, DataBroker dataBroker) {
246         String logicTunnelGroupName = null;
247         boolean tunnelAggregationEnabled = ItmTunnelAggregationHelper.isTunnelAggregationEnabled();
248         if (!tunnelAggregationEnabled) {
249             return logicTunnelGroupName;
250         }
251         logicTunnelGroupName = ItmUtils.getLogicalTunnelGroupName(srcDpnId, dstDpnId);
252         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
253         ItmTunnelAggregationWorker addWorker =
254                 new ItmTunnelAggregationWorker(logicTunnelGroupName, srcDpnId, dstDpnId, dataBroker);
255         coordinator.enqueueJob(logicTunnelGroupName, addWorker);
256         return logicTunnelGroupName;
257     }
258
259     private static class ItmTunnelAggregationWorker implements Callable<List<ListenableFuture<Void>>> {
260
261         private final String logicTunnelGroupName;
262         private final BigInteger srcDpnId;
263         private final BigInteger dstDpnId;
264         private final DataBroker dataBroker;
265
266         ItmTunnelAggregationWorker(String logicGroupName, BigInteger srcDpnId, BigInteger dstDpnId, DataBroker broker) {
267             this.logicTunnelGroupName = logicGroupName;
268             this.srcDpnId = srcDpnId;
269             this.dstDpnId = dstDpnId;
270             this.dataBroker = broker;
271         }
272
273         @Override
274         public List<ListenableFuture<Void>> call() throws Exception {
275             List<ListenableFuture<Void>> futures = new ArrayList<>();
276             //The logical tunnel interface be created only when the first tunnel interface on each OVS is created
277             InternalTunnel tunnel = ItmUtils.itmCache.getInternalTunnel(logicTunnelGroupName);
278             if (tunnel == null) {
279                 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
280                 LOG.info("MULTIPLE_VxLAN_TUNNELS: add the logical tunnel group {} because a first tunnel"
281                         + " interface on srcDpnId {} dstDpnId {} is created", logicTunnelGroupName, srcDpnId, dstDpnId);
282                 createLogicalTunnelInterface(srcDpnId, dstDpnId, TunnelTypeLogicalGroup.class, logicTunnelGroupName);
283                 createInternalTunnel(srcDpnId, dstDpnId, TunnelTypeLogicalGroup.class, logicTunnelGroupName, tx);
284                 futures.add(tx.submit());
285             } else {
286                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not first tunnel on srcDpnId {} dstDpnId {}", srcDpnId, dstDpnId);
287             }
288             return futures;
289         }
290     }
291 }