57881fa5d62e72a41da161b6f17e886fa5df1072
[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.opendaylight.genius.itm.rev160406.NotHostedTransportZones;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZone;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZoneBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.TepsInNotHostedTransportZoneKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVteps;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVtepsBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.not.hosted.transport.zones.tepsinnothostedtransportzone.UnknownVtepsKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Vteps;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.VtepsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.VtepsKey;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 public final class OvsdbTepAddConfigHelper {
44
45     private static final Logger LOG = LoggerFactory.getLogger(OvsdbTepAddConfigHelper.class);
46
47     private OvsdbTepAddConfigHelper() { }
48
49     /**
50      * Adds the TEP into ITM configuration/operational Datastore in one of the following cases.
51      * 1) default transport zone
52      * 2) Configured transport zone
53      * 3) Unhosted transport zone
54      *
55      * @param tepIp TEP-IP address in string
56      * @param strDpnId bridge datapath ID in string
57      * @param tzName transport zone name in string
58      * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
59      * @param dataBroker data broker handle to perform operations on config/operational datastore
60      * @param txRunner ManagedTransactionRunner object
61      */
62
63     public static List<ListenableFuture<Void>> addTepReceivedFromOvsdb(String tepIp, String strDpnId, String tzName,
64                                                                        boolean ofTunnel, DataBroker dataBroker,
65                                                                        ManagedNewTransactionRunner txRunner) {
66         List<ListenableFuture<Void>> futures = new ArrayList<>();
67         BigInteger dpnId = BigInteger.valueOf(0);
68
69         if (strDpnId != null && !strDpnId.isEmpty()) {
70             dpnId = MDSALUtil.getDpnId(strDpnId);
71         }
72
73         // Get tep IP
74         IpAddress tepIpAddress = IpAddressBuilder.getDefaultInstance(tepIp);
75         TransportZone tzone = null;
76
77         // Case: TZ name is not given with OVS TEP.
78         if (tzName == null) {
79             tzName = ITMConstants.DEFAULT_TRANSPORT_ZONE;
80             // add TEP into default-TZ
81             tzone = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
82             if (tzone == null) {
83                 // Case: default-TZ is not yet created, then add TEP into "teps-in-not-hosted-transport-zone"
84                 LOG.trace("Adding TEP with default TZ into teps-in-not-hosted-transport-zone.");
85                 return addUnknownTzTepIntoTepsNotHostedAndReturnFutures(tzName, tepIpAddress, dpnId, ofTunnel,
86                         dataBroker, txRunner);
87             }
88             LOG.trace("Add TEP into default-transport-zone.");
89         } else {
90             // Case: Add TEP into corresponding TZ created from Northbound.
91             tzone = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
92             if (tzone == null) {
93                 // Case: TZ is not configured from Northbound, then add TEP into "teps-in-not-hosted-transport-zone"
94                 LOG.trace("Adding TEP with unknown TZ into teps-in-not-hosted-transport-zone.");
95                 return addUnknownTzTepIntoTepsNotHostedAndReturnFutures(tzName, tepIpAddress, dpnId, ofTunnel,
96                         dataBroker, txRunner);
97             } else {
98                 LOG.trace("Add TEP into transport-zone already configured by Northbound.");
99             }
100         }
101
102
103         final BigInteger id = dpnId;
104         final String name = tzName;
105         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION,
106             tx -> addConfig(name, id, tepIpAddress, ofTunnel, tx)));
107         return futures;
108     }
109
110     /**
111      * Adds the TEP into Vtep list in the subnet list in the transport zone list
112      * from ITM configuration Datastore by merge operation with write transaction.
113      *
114      * @param updatedVtepList updated Vteps list object which will have new TEP for addition
115      * @param tepIpAddress TEP IP address in IpAddress object
116      * @param tzName transport zone name in string
117      * @param dpid bridge datapath ID in BigInteger
118      * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
119      * @param tx TypedWriteTransaction object
120      */
121     public static void addVtepInITMConfigDS(List<Vteps> updatedVtepList, IpAddress tepIpAddress, String tzName,
122                                             BigInteger dpid, boolean ofTunnel,
123                                             TypedWriteTransaction<Datastore.Configuration> tx) {
124         //Create TZ node path
125         InstanceIdentifier<TransportZone> tranzportZonePath =
126                 InstanceIdentifier.builder(TransportZones.class)
127                         .child(TransportZone.class, new TransportZoneKey(tzName)).build();
128
129         // this check is needed to reuse same function from TransportZoneListener
130         // when VTEP is moved from TepsNotHosted list to TZ configured from Northbound.
131         if (dpid.compareTo(BigInteger.ZERO) > 0) {
132             // create vtep
133             VtepsKey vtepkey = new VtepsKey(dpid);
134             Vteps vtepObj =
135                     new VtepsBuilder().setDpnId(dpid).setIpAddress(tepIpAddress).withKey(vtepkey)
136                             .setOptionOfTunnel(ofTunnel).build();
137
138             // Add vtep obtained from bridge into list
139             updatedVtepList.add(vtepObj);
140
141             LOG.trace("Adding TEP (TZ: {} TEP IP: {} DPID: {}, of-tunnel: {}) in ITM Config DS.", tzName,
142                     tepIpAddress, dpid, ofTunnel);
143         } else {
144             // this is case when this function is called while TEPs movement from tepsNotHosted list when
145             // corresponding TZ is configured from northbound.
146             for (Vteps vtep: updatedVtepList) {
147                 LOG.trace("Moving TEP (TEP IP: {} DPID: {}, of-tunnel: {})"
148                                 + "from not-hosted-transport-zone {} into  ITM Config DS.",
149                         vtep.getIpAddress(), vtep.getDpnId(), ofTunnel, tzName);
150             }
151         }
152
153         // create TZ node with updated subnet having new vtep
154         TransportZone updatedTzone =
155                 new TransportZoneBuilder().withKey(new TransportZoneKey(tzName)).setVteps(updatedVtepList)
156                         .setZoneName(tzName).build();
157
158         // Update TZ in Config DS to add vtep in TZ
159         tx.merge(tranzportZonePath, updatedTzone, true);
160     }
161
162     /**
163      * Adds the TEP into Vtep list in the subnet list in the transport zone list
164      * from ITM operational Datastore by merge operation with write transaction.
165      *
166      * @param tzName transport zone name in string
167      * @param tepIpAddress TEP IP address in IpAddress object
168      * @param dpid bridge datapath ID in BigInteger
169      * @param ofTunnel boolean flag for TEP to enable/disable of-tunnel feature on it
170      * @param dataBroker data broker handle to perform operations on operational datastore
171      * @param tx TypedWriteTransaction object
172      */
173     protected static void addUnknownTzTepIntoTepsNotHosted(String tzName, IpAddress tepIpAddress,
174                                                            BigInteger dpid, boolean ofTunnel, DataBroker dataBroker,
175                                                            TypedWriteTransaction<Datastore.Operational> tx) {
176         List<UnknownVteps> vtepList;
177         TepsInNotHostedTransportZone tepsInNotHostedTransportZone =
178                 ItmUtils.getUnknownTransportZoneFromITMOperDS(tzName, dataBroker);
179         if (tepsInNotHostedTransportZone == null) {
180             LOG.trace("Unhosted TransportZone ({}) does not exist in OperDS.", tzName);
181             vtepList = new ArrayList<>();
182             addVtepIntoTepsNotHosted(addVtepToUnknownVtepsList(vtepList, tepIpAddress, dpid, ofTunnel), tzName, tx);
183         } else {
184             vtepList = tepsInNotHostedTransportZone.getUnknownVteps();
185             if (vtepList == null || vtepList.isEmpty()) {
186                 //  case: vtep list does not exist or it has no elements
187                 if (vtepList == null) {
188                     LOG.trace("Add TEP into unhosted TZ ({}) when no vtep-list in the TZ.", tzName);
189                     vtepList = new ArrayList<>();
190                 }
191                 LOG.trace("Add TEP into unhosted TZ ({}) when no vtep-list in the TZ.", tzName);
192                 addVtepIntoTepsNotHosted(addVtepToUnknownVtepsList(vtepList, tepIpAddress, dpid, ofTunnel), tzName, tx);
193             } else {
194                 //  case: vtep list has elements
195                 boolean vtepFound = false;
196                 UnknownVteps oldVtep = null;
197
198                 for (UnknownVteps vtep : vtepList) {
199                     if (Objects.equals(vtep.getDpnId(), dpid)) {
200                         vtepFound = true;
201                         oldVtep = vtep;
202                         break;
203                     }
204                 }
205                 if (!vtepFound) {
206                     addVtepIntoTepsNotHosted(addVtepToUnknownVtepsList(vtepList,
207                             tepIpAddress, dpid, ofTunnel), tzName, tx);
208                 } else {
209                     // vtep is found, update it with tep-ip
210                     vtepList.remove(oldVtep);
211                     addVtepIntoTepsNotHosted(addVtepToUnknownVtepsList(vtepList,
212                             tepIpAddress, dpid, ofTunnel), tzName, tx);
213                 }
214             }
215         }
216     }
217
218     /**
219      * Adds the TEP into Unknown Vtep list under the transport zone in the TepsNotHosted list
220      * from ITM operational Datastore by merge operation with write transaction.
221      *
222      * @param updatedVtepList updated UnknownVteps list object which will have new TEP for addition
223      *                        into TepsNotHosted
224      * @param tzName transport zone name in string
225      * @param tx TypedWriteTransaction object
226      */
227     protected static void addVtepIntoTepsNotHosted(List<UnknownVteps> updatedVtepList, String tzName,
228                                                    TypedWriteTransaction<Datastore.Operational> tx) {
229         //Create TZ node path
230         InstanceIdentifier<TepsInNotHostedTransportZone> tepsInNotHostedTransportZoneIid =
231                 InstanceIdentifier.builder(NotHostedTransportZones.class)
232                         .child(TepsInNotHostedTransportZone.class,
233                                 new TepsInNotHostedTransportZoneKey(tzName)).build();
234
235         // create unknown TZ node with updated vtep list
236         TepsInNotHostedTransportZone updatedTzone = new TepsInNotHostedTransportZoneBuilder()
237                 .withKey(new TepsInNotHostedTransportZoneKey(tzName)).setZoneName(tzName)
238                 .setUnknownVteps(updatedVtepList).build();
239
240         // Update TZ in Oper DS.
241         tx.merge(tepsInNotHostedTransportZoneIid, updatedTzone, true);
242     }
243
244     private static void addConfig(String tzName, BigInteger dpnId, IpAddress ipAdd,
245                                   boolean ofTunnel, TypedWriteTransaction<Datastore.Configuration> tx) {
246         List<Vteps> vtepList = new ArrayList<>();
247
248         LOG.trace("Add TEP in transport-zone when no vtep-list for specific subnet.");
249         addVtepInITMConfigDS(vtepList, ipAdd, tzName, dpnId, ofTunnel, tx);
250     }
251
252     private static List<ListenableFuture<Void>> addUnknownTzTepIntoTepsNotHostedAndReturnFutures(String tzName,
253                                                          IpAddress tepIpAddress, BigInteger id, boolean ofTunnel,
254                                                          DataBroker dataBroker, ManagedNewTransactionRunner txRunner) {
255         return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.OPERATIONAL,
256             tx -> addUnknownTzTepIntoTepsNotHosted(tzName, tepIpAddress, id, ofTunnel, dataBroker, tx)));
257     }
258
259     private static List<UnknownVteps> addVtepToUnknownVtepsList(List<UnknownVteps> updatedVtepList,
260                                                                 IpAddress tepIpAddress, BigInteger dpid,
261                                                                 boolean ofTunnel) {
262         // create vtep
263         UnknownVtepsKey vtepkey = new UnknownVtepsKey(dpid);
264         UnknownVteps vtepObj =
265                 new UnknownVtepsBuilder().setDpnId(dpid).setIpAddress(tepIpAddress).withKey(vtepkey)
266                         .setOfTunnel(ofTunnel).build();
267
268         // Add vtep obtained into unknown TZ tep list
269         updatedVtepList.add(vtepObj);
270         LOG.trace("Adding TEP  (DPID: {}, TEP IP: {}, of-tunnel: {}) into unhosted Transport Zone"
271                 + "inside ITM Oper DS.", dpid, tepIpAddress, ofTunnel);
272         return updatedVtepList;
273     }
274 }