2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.genius.itm.confighelpers;
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;
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;
45 public class ItmInternalTunnelAddWorker {
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>() {
54 public void onSuccess(Void result) {
55 LOG.debug("Success in Datastore operation");
59 public void onFailure(Throwable error) {
60 LOG.error("Error in Datastore operation", error);
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);
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");
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<>();
88 meshedDpnList.add(dpn);
89 // Update the operational datastore -- FIXME -- Error Handling
90 updateOperationalDatastore(dataBroker, dpn, transaction, futures);
92 futures.add(transaction.submit()) ;
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<>() ;
102 DpnEndpoints tnlBuilder = new DpnEndpointsBuilder().setDPNTEPsInfo(dpnList).build() ;
103 ITMBatchingUtils.update(dep, tnlBuilder, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
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 ");
114 for (DPNTEPsInfo dstDpn: meshedDpnList) {
115 if (!srcDpn.equals(dstDpn)) {
116 wireUpWithinTransportZone(srcDpn, dstDpn, dataBroker, idManagerService, mdsalManager,
117 transaction, futures);
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();
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()) {
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
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
154 if (monitorProtocol.isAssignableFrom(TunnelMonitoringTypeLldp.class)) {
155 ItmUtils.setUpOrRemoveTerminatingServiceTable(srcDpnId, mdsalManager, true);
156 ItmUtils.setUpOrRemoveTerminatingServiceTable(dstDpnId, mdsalManager, true);
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);
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);
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) {
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
184 String trunkInterfaceName = ItmUtils.getTrunkInterfaceName(idManagerService, interfaceName,
185 new String(srcte.getIpAddress().getValue()),
186 new String(dstte.getIpAddress().getValue()),
188 String parentInterfaceName = null;
189 if (tunType.isAssignableFrom(TunnelTypeVxlan.class)) {
190 parentInterfaceName = createLogicalGroupTunnel(srcDpnId, dstDpnId, dataBroker);
192 createTunnelInterface(srcte, dstte, srcDpnId, dstDpnId, tunType, trunkInterfaceName, parentInterfaceName);
193 // also update itm-state ds?
194 createInternalTunnel(srcDpnId, dstDpnId, tunType, trunkInterfaceName, transaction);
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);
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);
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);
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;
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;
259 private static class ItmTunnelAggregationWorker implements Callable<List<ListenableFuture<Void>>> {
261 private final String logicTunnelGroupName;
262 private final BigInteger srcDpnId;
263 private final BigInteger dstDpnId;
264 private final DataBroker dataBroker;
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;
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());
286 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not first tunnel on srcDpnId {} dstDpnId {}", srcDpnId, dstDpnId);