GENIUS-185: Removing usage of databroker tx
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / confighelpers / OvsdbTepAddConfigHelper.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.ListenableFuture;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Objects;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.genius.infra.Datastore;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
19 import org.opendaylight.genius.infra.TypedWriteTransaction;
20 import org.opendaylight.genius.itm.globals.ITMConstants;
21 import org.opendaylight.genius.itm.impl.ItmUtils;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.NotHostedTransportZones;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZone;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZoneBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZoneKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVteps;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVtepsBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVtepsKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.SubnetsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.SubnetsKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.VtepsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.VtepsKey;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public final class OvsdbTepAddConfigHelper {
48
49     private static final Logger LOG = LoggerFactory.getLogger(OvsdbTepAddConfigHelper.class);
50
51     private OvsdbTepAddConfigHelper() { }
52
53     /**
54      * Adds the TEP into ITM configuration/operational Datastore in one of the following cases.
55      * 1) default transport zone
56      * 2) Configured transport zone
57      * 3) Unhosted transport zone
58      *
59      * @param tepIp TEP-IP address in string
60      * @param strDpnId bridge datapath ID in string
61      * @param tzName transport zone name in string
62      * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
63      * @param dataBroker data broker handle to perform operations on config/operational datastore
64      * @param txRunner ManagedTransactionRunner object
65      */
66
67     public static List<ListenableFuture<Void>> addTepReceivedFromOvsdb(String tepIp, String strDpnId, String tzName,
68         boolean ofTunnel, DataBroker dataBroker, ManagedNewTransactionRunner txRunner) {
69         List<ListenableFuture<Void>> futures = new ArrayList<>();
70         BigInteger dpnId = BigInteger.valueOf(0);
71
72         if (strDpnId != null && !strDpnId.isEmpty()) {
73             dpnId = MDSALUtil.getDpnId(strDpnId);
74         }
75
76         // Get tep IP
77         IpAddress tepIpAddress = IpAddressBuilder.getDefaultInstance(tepIp);
78         TransportZone tzone = null;
79
80         // Case: TZ name is not given with OVS TEP.
81         if (tzName == null) {
82             tzName = ITMConstants.DEFAULT_TRANSPORT_ZONE;
83             // add TEP into default-TZ
84             tzone = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
85             if (tzone == null) {
86                 // Case: default-TZ is not yet created, then add TEP into "teps-in-not-hosted-transport-zone"
87                 LOG.trace("Adding TEP with default TZ into teps-in-not-hosted-transport-zone.");
88                 return addUnknownTzTepIntoTepsNotHostedAndReturnFutures(tzName, tepIpAddress, dpnId, ofTunnel,
89                     dataBroker, txRunner);
90             }
91             LOG.trace("Add TEP into default-transport-zone.");
92         } else {
93             // Case: Add TEP into corresponding TZ created from Northbound.
94             tzone = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
95             if (tzone == null) {
96                 // Case: TZ is not configured from Northbound, then add TEP into "teps-in-not-hosted-transport-zone"
97                 LOG.trace("Adding TEP with unknown TZ into teps-in-not-hosted-transport-zone.");
98                 return addUnknownTzTepIntoTepsNotHostedAndReturnFutures(tzName, tepIpAddress, dpnId, ofTunnel,
99                     dataBroker, txRunner);
100             } else {
101                 LOG.trace("Add TEP into transport-zone already configured by Northbound.");
102             }
103         }
104
105         // Get subnet list of corresponding TZ created from Northbound.
106         final List<Subnets> subnetList = tzone.getSubnets();
107         final BigInteger id = dpnId;
108         final String name = tzName;
109         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION,
110             tx -> addConfig(subnetList, name, id, tepIpAddress, ofTunnel, tx)));
111         return futures;
112     }
113
114     /**
115      * Adds the TEP into Vtep list in the subnet list in the transport zone list
116      * from ITM configuration Datastore by merge operation with write transaction.
117      *
118      * @param subnetList subnets list object
119      * @param subnetMaskObj subnet mask in IpPrefix object
120      * @param updatedVtepList updated Vteps list object which will have new TEP for addition
121      * @param tepIpAddress TEP IP address in IpAddress object
122      * @param tzName transport zone name in string
123      * @param dpid bridge datapath ID in BigInteger
124      * @param portName port name as a part of VtepsKey
125      * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
126      * @param tx TypedWriteTransaction object
127      */
128     public static void addVtepInITMConfigDS(List<Subnets> subnetList, IpPrefix subnetMaskObj,
129         List<Vteps> updatedVtepList, IpAddress tepIpAddress, String tzName, BigInteger dpid,
130         String portName, boolean ofTunnel, TypedWriteTransaction<Datastore.Configuration> tx) {
131         //Create TZ node path
132         InstanceIdentifier<TransportZone> tranzportZonePath =
133             InstanceIdentifier.builder(TransportZones.class)
134                 .child(TransportZone.class, new TransportZoneKey(tzName)).build();
135
136         // this check is needed to reuse same function from TransportZoneListener
137         // when VTEP is moved from TepsNotHosted list to TZ configured from Northbound.
138         if (dpid.compareTo(BigInteger.ZERO) > 0) {
139             // create vtep
140             VtepsKey vtepkey = new VtepsKey(dpid, portName);
141             Vteps vtepObj =
142                 new VtepsBuilder().setDpnId(dpid).setIpAddress(tepIpAddress).withKey(vtepkey).setPortname(portName)
143                         .setOptionOfTunnel(ofTunnel).build();
144
145             // Add vtep obtained from bridge into list
146             updatedVtepList.add(vtepObj);
147
148             LOG.trace("Adding TEP (TZ: {} Subnet: {} TEP IP: {} DPID: {}, of-tunnel: {}) in ITM Config DS.", tzName,
149                     subnetMaskObj, tepIpAddress, dpid, ofTunnel);
150         } else {
151             // this is case when this function is called while TEPs movement from tepsNotHosted list when
152             // corresponding TZ is configured from northbound.
153             for (Vteps vtep: updatedVtepList) {
154                 LOG.trace("Moving TEP (TEP IP: {} DPID: {}, of-tunnel: {})"
155                         + "from not-hosted-transport-zone {} into  ITM Config DS.",
156                     vtep.getIpAddress(), vtep.getDpnId(), ofTunnel, tzName);
157             }
158         }
159
160         // Create subnet object
161         SubnetsKey subKey = new SubnetsKey(subnetMaskObj);
162         IpAddress gatewayIP = IpAddressBuilder.getDefaultInstance(ITMConstants.DUMMY_GATEWAY_IP);
163         int vlanID = ITMConstants.DUMMY_VLANID;
164
165         Subnets subnet =
166             new SubnetsBuilder().setGatewayIp(gatewayIP)
167                 .withKey(subKey).setPrefix(subnetMaskObj)
168                 .setVlanId(vlanID).setVteps(updatedVtepList).build();
169
170         // add subnet into subnet list
171         subnetList.add(subnet);
172
173         // create TZ node with updated subnet having new vtep
174         TransportZone updatedTzone =
175             new TransportZoneBuilder().withKey(new TransportZoneKey(tzName)).setSubnets(subnetList)
176                 .setZoneName(tzName).build();
177
178         // Update TZ in Config DS to add vtep in TZ
179         tx.merge(tranzportZonePath, updatedTzone, true);
180     }
181
182     /**
183      * Adds the TEP into Vtep list in the subnet list in the transport zone list
184      * from ITM operational Datastore by merge operation with write transaction.
185      *
186      * @param tzName transport zone name in string
187      * @param tepIpAddress TEP IP address in IpAddress object
188      * @param dpid bridge datapath ID in BigInteger
189      * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
190      * @param dataBroker data broker handle to perform operations on operational datastore
191      * @param tx TypedWriteTransaction object
192      */
193     protected static void addUnknownTzTepIntoTepsNotHosted(String tzName, IpAddress tepIpAddress,
194         BigInteger dpid, boolean ofTunnel, DataBroker dataBroker, TypedWriteTransaction<Datastore.Operational> tx) {
195         List<UnknownVteps> vtepList;
196         TepsInNotHostedTransportZone tepsInNotHostedTransportZone =
197             ItmUtils.getUnknownTransportZoneFromITMOperDS(tzName, dataBroker);
198         if (tepsInNotHostedTransportZone == null) {
199             LOG.trace("Unhosted TransportZone ({}) does not exist in OperDS.", tzName);
200             vtepList = new ArrayList<>();
201             addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
202         } else {
203             vtepList = tepsInNotHostedTransportZone.getUnknownVteps();
204             if (vtepList == null || vtepList.isEmpty()) {
205                 //  case: vtep list does not exist or it has no elements
206                 if (vtepList == null) {
207                     vtepList = new ArrayList<>();
208                 }
209                 LOG.trace("Add TEP into unhosted TZ ({}) when no vtep-list in the TZ.", tzName);
210                 addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
211             } else {
212                 //  case: vtep list has elements
213                 boolean vtepFound = false;
214                 UnknownVteps oldVtep = null;
215
216                 for (UnknownVteps vtep : vtepList) {
217                     if (Objects.equals(vtep.getDpnId(), dpid)) {
218                         vtepFound = true;
219                         oldVtep = vtep;
220                         break;
221                     }
222                 }
223                 if (!vtepFound) {
224                     addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
225                 } else {
226                     // vtep is found, update it with tep-ip
227                     vtepList.remove(oldVtep);
228                     addVtepIntoTepsNotHosted(vtepList, tepIpAddress, tzName, dpid, ofTunnel, tx);
229                 }
230             }
231         }
232     }
233
234     /**
235      * Adds the TEP into Unknown Vtep list under the transport zone in the TepsNotHosted list
236      * from ITM operational Datastore by merge operation with write transaction.
237      *
238      * @param updatedVtepList updated UnknownVteps list object which will have new TEP for addition
239      *                        into TepsNotHosted
240      * @param tepIpAddress TEP IP address in IpAddress object
241      * @param tzName transport zone name in string
242      * @param dpid bridge datapath ID in BigInteger
243      * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
244      * @param tx TypedWriteTransaction object
245      */
246     protected static void addVtepIntoTepsNotHosted(List<UnknownVteps> updatedVtepList,
247         IpAddress tepIpAddress, String tzName, BigInteger dpid, boolean ofTunnel,
248         TypedWriteTransaction<Datastore.Operational> tx) {
249         //Create TZ node path
250         InstanceIdentifier<TepsInNotHostedTransportZone> tepsInNotHostedTransportZoneIid =
251             InstanceIdentifier.builder(NotHostedTransportZones.class)
252                 .child(TepsInNotHostedTransportZone.class,
253                     new TepsInNotHostedTransportZoneKey(tzName)).build();
254
255         // create vtep
256         UnknownVtepsKey vtepkey = new UnknownVtepsKey(dpid);
257         UnknownVteps vtepObj =
258             new UnknownVtepsBuilder().setDpnId(dpid).setIpAddress(tepIpAddress).withKey(vtepkey)
259                 .setOfTunnel(ofTunnel).build();
260
261         // Add vtep obtained into unknown TZ tep list
262         updatedVtepList.add(vtepObj);
263
264         // create unknown TZ node with updated vtep list
265         TepsInNotHostedTransportZone updatedTzone = new TepsInNotHostedTransportZoneBuilder()
266             .withKey(new TepsInNotHostedTransportZoneKey(tzName)).setZoneName(tzName)
267             .setUnknownVteps(updatedVtepList).build();
268
269         LOG.trace("Adding TEP  (DPID: {}, TEP IP: {}, of-tunnel: {}) into unhosted TZ: {}"
270                 + "inside ITM Oper DS.", dpid, tepIpAddress, ofTunnel, tzName);
271
272         // Update TZ in Oper DS.
273         tx.merge(tepsInNotHostedTransportZoneIid, updatedTzone, true);
274     }
275
276     private static void addConfig(List<Subnets> subnets, String tzName, BigInteger dpnId, IpAddress ipAdd,
277                                   boolean ofTunnel, TypedWriteTransaction<Datastore.Configuration> tx) {
278         String portName = ITMConstants.DUMMY_PORT;
279         IpPrefix subnetMask = ItmUtils.getDummySubnet(); // get subnetMaskObject
280
281         if (subnets == null || subnets.isEmpty()) {
282             if (subnets == null) {
283                 subnets = new ArrayList<>();
284             }
285             List<Vteps> vtepList = new ArrayList<>();
286             LOG.trace("Add TEP in transport-zone when no subnet-list.");
287             addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
288         } else {
289             List<Vteps> vtepList = null;
290
291             // subnet list already exists case; check for dummy-subnet
292             for (Subnets subnet : subnets) {
293                 if (subnet.key().getPrefix().equals(subnetMask)) {
294                     LOG.trace("Subnet exists in the subnet list of transport-zone {}.", tzName);
295                     // get vtep list of existing subnet
296                     vtepList = subnet.getVteps();
297                     break;
298                 }
299             }
300
301             if (vtepList == null || vtepList.isEmpty()) {
302                 //  case: vtep list does not exist or it has no elements
303                 if (vtepList == null) {
304                     vtepList = new ArrayList<>();
305                 }
306                 LOG.trace("Add TEP in transport-zone when no vtep-list for specific subnet.");
307                 addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
308             } else {
309                 //  case: vtep list has elements
310                 boolean vtepFound = false;
311                 Vteps oldVtep = null;
312
313                 for (Vteps vtep : vtepList) {
314                     if (Objects.equals(vtep.getDpnId(),dpnId)) {
315                         vtepFound = true;
316                         oldVtep = vtep;
317                         // get portName of existing vtep
318                         portName = vtep.getPortname();
319                         break;
320                     }
321                 }
322                 if (!vtepFound) {
323                     addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
324                 } else {
325                     // vtep is found, update it with tep-ip
326                     vtepList.remove(oldVtep);
327                     addVtepInITMConfigDS(subnets, subnetMask, vtepList, ipAdd, tzName, dpnId, portName, ofTunnel, tx);
328                 }
329             }
330         }
331     }
332
333     private static List<ListenableFuture<Void>> addUnknownTzTepIntoTepsNotHostedAndReturnFutures(String tzName,
334         IpAddress tepIpAddress, BigInteger id, boolean ofTunnel, DataBroker dataBroker,
335         ManagedNewTransactionRunner txRunner) {
336         return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.OPERATIONAL,
337             tx -> addUnknownTzTepIntoTepsNotHosted(tzName, tepIpAddress, id, ofTunnel, dataBroker, tx)));
338     }
339 }