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