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.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;
52 public class ItmExternalTunnelAddWorker {
53 private static final Logger LOG = LoggerFactory.getLogger(ItmExternalTunnelAddWorker.class);
55 private final DataBroker dataBroker;
56 private final ItmConfig itmConfig;
57 private final DPNTEPsInfoCache dpnTEPsInfoCache;
59 public ItmExternalTunnelAddWorker(DataBroker dataBroker, ItmConfig itmConfig, DPNTEPsInfoCache dpnTEPsInfoCache) {
60 this.dataBroker = dataBroker;
61 this.itmConfig = itmConfig;
62 this.dpnTEPsInfoCache = dpnTEPsInfoCache;
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);
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);
107 return Collections.singletonList(transaction.submit());
109 return Collections.emptyList();
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);
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;
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);
129 if (null != cfgdHwVteps && !cfgdHwVteps.isEmpty()) {
130 LOG.trace("calling tunnels from hwTep {}",cfgdHwVteps);
131 tunnelsFromhWVtep(cfgdHwVteps, writeTransaction, monitorInterval, monitorProtocol);
134 if (cfgdDpnList != null && !cfgdDpnList.isEmpty() || cfgdHwVteps != null && !cfgdHwVteps.isEmpty()) {
135 futures.add(writeTransaction.submit());
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);
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())) {
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,
182 LOG.error("Unable to build tunnel {} -- {}",
183 tep.getIpAddress(), hwVtepDS.getIpAddress());
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());
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
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());
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());
239 if (sub.getVteps() != null && !sub.getVteps().isEmpty()) {
240 for (Vteps vtep : sub.getVteps()) {
241 if (vtep.getIpAddress().equals(hwTep.getHwIp())) {
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,
251 LOG.error("Unable to build tunnel {} -- {}",
252 hwTep.getHwIp(), vtep.getIpAddress());
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");
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);
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);
338 @SuppressFBWarnings("RV_CHECK_FOR_POSITIVE_INDEXOF")
339 static String getExternalTunnelKey(String nodeid) {
340 final int index = nodeid.indexOf("physicalswitch");
342 nodeid = nodeid.substring(0, index - 1);