Merge "IDManager fixes for restart scenario"
[vpnservice.git] / itm / itm-impl / src / main / java / org / opendaylight / vpnservice / itm / listeners / VtepConfigSchemaListener.java
1 /*
2  * Copyright (c) 2016 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.vpnservice.itm.listeners;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import org.apache.commons.lang3.StringUtils;
15 import org.apache.commons.net.util.SubnetUtils;
16 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.vpnservice.itm.cli.TepCommandHelper;
22 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
23 import org.opendaylight.vpnservice.itm.impl.ItmUtils;
24 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
25 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.VtepConfigSchemas;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.VtepConfigSchemaBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.ip.pools.VtepIpPool;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.ip.pools.VtepIpPoolBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIds;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.config.rev151102.vtep.config.schemas.vtep.config.schema.DpnIdsKey;
34 //import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.config.rev151102.VtepConfigSchemas;
35 //import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.config.rev151102.vtep.config.schemas.VtepConfigSchema;
36 //import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.config.rev151102.vtep.config.schemas.VtepConfigSchemaBuilder;
37 //import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.config.rev151102.vtep.ip.pools.VtepIpPool;
38 //import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.config.rev151102.vtep.ip.pools.VtepIpPoolBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZoneKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.SubnetsKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.Vteps;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.VtepsKey;
49 import org.opendaylight.yangtools.concepts.ListenerRegistration;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Optional;
55
56 /**
57  * The listener class interested in processing data change on
58  * {@code VtepConfigSchema} objects.
59  *
60  * @see VtepConfigSchema
61  */
62 public class VtepConfigSchemaListener extends AbstractDataChangeListener<VtepConfigSchema> implements AutoCloseable {
63
64     /** The Constant LOG. */
65     private static final Logger LOG = LoggerFactory.getLogger(VtepConfigSchemaListener.class);
66
67     /** The listener registration. */
68     private ListenerRegistration<DataChangeListener> listenerRegistration;
69
70     /** The data broker. */
71     private final DataBroker dataBroker;
72
73     /**
74      * Instantiates a new vtep config schema listener.
75      *
76      * @param db
77      *            the db
78      */
79     public VtepConfigSchemaListener(final DataBroker db) {
80         super(VtepConfigSchema.class);
81         this.dataBroker = db;
82         registerListener(db);
83     }
84
85     /*
86      * (non-Javadoc)
87      *
88      * @see java.lang.AutoCloseable#close()
89      */
90     @Override
91     public void close() throws Exception {
92         if (this.listenerRegistration != null) {
93             try {
94                 this.listenerRegistration.close();
95             } catch (final Exception e) {
96                 LOG.error("Error when cleaning up DataChangeListener.", e);
97             }
98             this.listenerRegistration = null;
99         }
100         LOG.info("VtepConfigSchemaListener Closed");
101     }
102
103     /**
104      * Register listener.
105      *
106      * @param db
107      *            the db
108      */
109     private void registerListener(final DataBroker db) {
110         try {
111             this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
112                     getWildCardPath(), VtepConfigSchemaListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
113         } catch (final Exception e) {
114             LOG.error("VtepConfigSchemaListener DataChange listener registration fail!", e);
115             throw new IllegalStateException("VtepConfigSchemaListener registration Listener failed.", e);
116         }
117     }
118
119     /**
120      * Gets the wild card path.
121      *
122      * @return the wild card path
123      */
124     private InstanceIdentifier<VtepConfigSchema> getWildCardPath() {
125         return ItmUtils.getVtepConfigSchemaIdentifier();
126     }
127
128     /*
129      * (non-Javadoc)
130      *
131      * @see
132      * org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener#remove(
133      * org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
134      * org.opendaylight.yangtools.yang.binding.DataObject)
135      */
136     @Override
137     protected void remove(InstanceIdentifier<VtepConfigSchema> identifier, VtepConfigSchema schema) {
138         LOG.trace("Received notification for VTEP config schema [{}] deleted.", schema.getSchemaName());
139         try {
140             List<BigInteger> lstDpnIds = ItmUtils.getDpnIdList(schema.getDpnIds());
141             if (lstDpnIds != null && !lstDpnIds.isEmpty()) {
142                 deleteVteps(schema, lstDpnIds);
143             }
144
145             // Delete IP pool corresponding to schema
146             // TODO: Ensure no schema exists with same subnet before deleting
147             String subnetCidr = ItmUtils.getSubnetCidrAsString(schema.getSubnet());
148             deleteVtepIpPool(subnetCidr);
149         } catch (Exception e) {
150             String error = new StringBuilder("Failed to handle DCN for delete VtepConfigSchema: ").append(schema)
151                     .toString();
152             LOG.error(error, e);
153         }
154     }
155
156     /*
157      * (non-Javadoc)
158      *
159      * @see
160      * org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener#update(
161      * org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
162      * org.opendaylight.yangtools.yang.binding.DataObject,
163      * org.opendaylight.yangtools.yang.binding.DataObject)
164      */
165     @Override
166     protected void update(InstanceIdentifier<VtepConfigSchema> identifier, VtepConfigSchema original,
167             VtepConfigSchema updated) {
168         LOG.error("Receivedn DCN for updating VTEP Original schema: {}. Updated schema: {}",
169                 original, updated);
170         //LOG.trace("Received notification for VTEP config schema [{}] updated.", original.getSchemaName());
171
172         try {
173             VtepConfigSchema orignalSchema = ItmUtils.validateVtepConfigSchema(original);
174             VtepConfigSchema updatedSchema = ItmUtils.validateVtepConfigSchema(updated);
175
176             if (doesDeleteAndAddSchemaRequired(original, updated)) {
177                 LOG.error("Failed to handle DCN for updating VTEP schema {}. Original schema: {}. Updated schema: {}",
178                         original, updated);
179                 // TODO: handle updates
180                 return;
181             }
182
183             handleUpdateOfDpnIds(orignalSchema, updatedSchema);
184
185         } catch (Exception e) {
186             String error = new StringBuilder("Failed to handle DCN for update VtepConfigSchema original:")
187                     .append(original).append(", updated: ").append(updated).toString();
188             LOG.error(error, e);
189         }
190     }
191
192     /*
193      * (non-Javadoc)
194      *
195      * @see
196      * org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener#add(org.
197      * opendaylight.yangtools.yang.binding.InstanceIdentifier,
198      * org.opendaylight.yangtools.yang.binding.DataObject)
199      */
200     @Override
201     protected void add(InstanceIdentifier<VtepConfigSchema> identifier, VtepConfigSchema schema) {
202         // Construct the transport zones from the provided schemas and push it
203         // to config DS.
204         LOG.trace("Add VtepConfigSchema: key: {} , value: {}", identifier, schema);
205
206         try {
207             VtepConfigSchema validatedSchema = ItmUtils.validateForAddVtepConfigSchema(schema,
208                     getAllVtepConfigSchemas());
209
210             VtepIpPool vtepIpPool = processAvailableIps(validatedSchema);
211             addVteps(validatedSchema, vtepIpPool);
212         } catch (Exception e) {
213             LOG.error("Failed to handle DCN for add VtepConfigSchema: {}", e);
214         }
215     }
216
217     /**
218      * Handle update of dpn ids.
219      *
220      * @param original
221      *            the original
222      * @param updated
223      *            the updated
224      */
225     private void handleUpdateOfDpnIds(VtepConfigSchema original, VtepConfigSchema updated) {
226         // Handling add/delete DPNs from schema
227         List<DpnIds> originalDpnIds = (original.getDpnIds() == null) ? new ArrayList<DpnIds>()
228                 : original.getDpnIds();
229         List<DpnIds> updatedDpnIds = (updated.getDpnIds() == null) ? new ArrayList<DpnIds>()
230                 : updated.getDpnIds();
231
232         handleDeletedDpnsFromSchema(original, originalDpnIds, updatedDpnIds);
233         handleNewlyAddedDpnsToSchema(original, originalDpnIds, updatedDpnIds);
234     }
235
236     /**
237      * Does delete and add schema required.
238      *
239      * @param original
240      *            the original
241      * @param updated
242      *            the updated
243      * @return true, if successful
244      */
245     private boolean doesDeleteAndAddSchemaRequired(VtepConfigSchema original, VtepConfigSchema updated) {
246         boolean delnAddRequired = false;
247         if (!StringUtils.equalsIgnoreCase(original.getPortName(), updated.getPortName())) {
248             delnAddRequired = true;
249         } else if (original.getVlanId() != updated.getVlanId()) {
250             delnAddRequired = true;
251         } else if (original.getSubnet() != null && !original.getSubnet().equals(updated.getSubnet())) {
252             delnAddRequired = true;
253         } else if (original.getGatewayIp() != null && !original.getGatewayIp().equals(updated.getGatewayIp())) {
254             delnAddRequired = true;
255         } else if (!StringUtils.equalsIgnoreCase(original.getTransportZoneName(), updated.getTransportZoneName())) {
256             delnAddRequired = true;
257         } else if (!(original.getTunnelType().equals(updated.getTunnelType()) )) {
258             delnAddRequired = true;
259         }
260         return delnAddRequired;
261     }
262
263     /**
264      * Handle newly added dpns to schema.
265      *
266      * @param original
267      *            the original
268      * @param originalDpnIds
269      *            the original dpn ids
270      * @param updatedDpnIds
271      *            the updated dpn ids
272      */
273     private void handleNewlyAddedDpnsToSchema(VtepConfigSchema original, List<DpnIds> originalDpnIds,
274             List<DpnIds> updatedDpnIds) {
275         LOG.trace("Handle Addition of DPNs from VTEP Original Dpn: {}. Updated Dpn: {}", originalDpnIds, updatedDpnIds) ;
276         ArrayList<DpnIds> newlyAddedDpns = new ArrayList<>(updatedDpnIds);
277         newlyAddedDpns.removeAll(originalDpnIds);
278         LOG.debug("Newly added DPNs {} to VTEP config schema [{}].", newlyAddedDpns, original.getSchemaName());
279         if (!newlyAddedDpns.isEmpty()) {
280             VtepConfigSchema diffSchema = new VtepConfigSchemaBuilder(original).setDpnIds(newlyAddedDpns).build();
281             String subnetCidr = ItmUtils.getSubnetCidrAsString(original.getSubnet());
282             VtepIpPool vtepIpPool = getVtepIpPool(subnetCidr);
283             LOG.debug("Adding of DPNs in Diff Schema: {}", diffSchema) ;
284             addVteps(diffSchema, vtepIpPool);
285         }
286     }
287
288     /**
289      * Handle deleted dpns from schema.
290      *
291      * @param original
292      *            the original
293      * @param originalDpnIds
294      *            the original dpn ids
295      * @param updatedDpnIds
296      *            the updated dpn ids
297      */
298     private void handleDeletedDpnsFromSchema(VtepConfigSchema original, List<DpnIds> originalDpnIds,
299             List<DpnIds> updatedDpnIds) {
300         ArrayList<DpnIds> deletedDpns = new ArrayList<>(originalDpnIds);
301         deletedDpns.removeAll(updatedDpnIds);
302         LOG.debug("DPNs to be removed DPNs {} from VTEP config schema [{}].", deletedDpns, original.getSchemaName());
303         if (!deletedDpns.isEmpty()) {
304             LOG.debug("Deleting of DPNs from VTEP Schema: {}. To be deleted Dpns: {}", original, deletedDpns) ;
305             deleteVteps(original, ItmUtils.getDpnIdList(deletedDpns));
306         }
307     }
308
309     /**
310      * Gets all vtep config schemas.
311      *
312      * @return the all vtep config schemas
313      */
314     private List<VtepConfigSchema> getAllVtepConfigSchemas() {
315         Optional<VtepConfigSchemas> schemas = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
316                 ItmUtils.getVtepConfigSchemasIdentifier(), this.dataBroker);
317         if (schemas.isPresent()) {
318             return schemas.get().getVtepConfigSchema();
319         }
320         return null;
321     }
322
323     /**
324      * Adds the vteps.
325      *
326      * @param schema
327      *            the schema
328      * @param vtepIpPool
329      *            the vtep ip pool
330      */
331     private void addVteps(VtepConfigSchema schema, VtepIpPool vtepIpPool) {
332         if (schema.getDpnIds() == null || schema.getDpnIds().isEmpty()) {
333             LOG.debug("DPN list is empty, skipping addVteps for schema: {}", schema);
334             return;
335         }
336
337         String subnetCidr = ItmUtils.getSubnetCidrAsString(schema.getSubnet());
338         if (vtepIpPool == null) {
339             LOG.error("VTEP config pool not found for subnetCidr {}. Failed to add VTEPs for schema {}", subnetCidr,
340                     schema);
341             return;
342         }
343         TepCommandHelper tepCommandHelper = new TepCommandHelper(this.dataBroker);
344         // Check this later
345         String tunType ;
346         Class<? extends TunnelTypeBase> tunnelType = schema.getTunnelType() ;
347         if( tunnelType.equals(TunnelTypeVxlan.class))
348             tunType = ITMConstants.TUNNEL_TYPE_VXLAN ;
349         else
350             tunType =  ITMConstants.TUNNEL_TYPE_GRE;
351         tepCommandHelper.configureTunnelType(schema.getTransportZoneName(),
352                 StringUtils.upperCase(tunType));
353
354         List<IpAddress> availableIps = vtepIpPool.getAvailableIpaddress();
355         List<IpAddress> newlyAllocatedIps = new ArrayList<>();
356         List<BigInteger> skippedDpnIds = new ArrayList<>();
357
358         String gatewayIp = handleGatewayIp(schema.getGatewayIp());
359         for (BigInteger dpnId : ItmUtils.getDpnIdList(schema.getDpnIds())) {
360             IpAddress ipAddress = getAnAvailableIP(availableIps);
361             if (ipAddress == null) {
362                 skippedDpnIds.add(dpnId);
363                 continue;
364             }
365             tepCommandHelper.createLocalCache(dpnId, schema.getPortName(), schema.getVlanId(),
366                     String.valueOf(ipAddress.getValue()), subnetCidr, gatewayIp, schema.getTransportZoneName());
367             newlyAllocatedIps.add(ipAddress);
368         }
369         if (!skippedDpnIds.isEmpty()) {
370             LOG.error("No available IP addresses in the VTEP config pool {}, skipping VTEP configurations for DPN's {}",
371                     subnetCidr, skippedDpnIds);
372         }
373
374         if (!newlyAllocatedIps.isEmpty()) {
375             LOG.debug( "Delete OnCommit and buildTeps in NewlyAddedDpns");
376             tepCommandHelper.deleteOnCommit();
377             tepCommandHelper.buildTeps();
378             allocateIpAddresses(newlyAllocatedIps, vtepIpPool, subnetCidr);
379         }
380     }
381
382     /**
383      * Handle gateway ip.
384      *
385      * @param gatewayIp
386      *            the gateway ip
387      * @return the string
388      */
389     private String handleGatewayIp(IpAddress gatewayIp) {
390         String strGatewayIp = (gatewayIp == null) ? null : String.valueOf(gatewayIp.getValue());
391         if (StringUtils.isBlank(strGatewayIp) || StringUtils.equals(ITMConstants.DUMMY_IP_ADDRESS, strGatewayIp)) {
392             // To avoid a validation exception in TepCommandHelper
393             strGatewayIp = null;
394         }
395         return strGatewayIp;
396     }
397
398     /**
399      * Delete vteps.
400      *
401      * @param schema
402      *            the schema
403      * @param lstDpnIdsToBeDeleted
404      *            the dpn ids list to be deleted
405      */
406     private void deleteVteps(VtepConfigSchema schema, List<BigInteger> lstDpnIdsToBeDeleted) {
407         TepCommandHelper tepCommandHelper = new TepCommandHelper(this.dataBroker);
408         List<IpAddress> freeIps = new ArrayList<>();
409
410         String subnetCidr = ItmUtils.getSubnetCidrAsString(schema.getSubnet());
411         String gatewayIp = handleGatewayIp(schema.getGatewayIp());
412
413         for (BigInteger dpnId : lstDpnIdsToBeDeleted) {
414             VtepsKey vtepkey = new VtepsKey(dpnId, schema.getPortName());
415
416             InstanceIdentifier<Vteps> vpath = InstanceIdentifier.builder(TransportZones.class)
417                     .child(TransportZone.class, new TransportZoneKey(schema.getTransportZoneName()))
418                     .child(Subnets.class, new SubnetsKey(schema.getSubnet())).child(Vteps.class, vtepkey).build();
419
420             Vteps vtep = null;
421             Optional<Vteps> vtepOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, vpath, dataBroker);
422             if (vtepOptional.isPresent()) {
423                 vtep = vtepOptional.get();
424             } else {
425                 LOG.warn("VTEP doesn't exist for DPN [{}] and port [{}].", dpnId, schema.getPortName());
426                 continue;
427             }
428
429             IpAddress ipAddress = vtep.getIpAddress();
430             tepCommandHelper.deleteVtep(dpnId, vtep.getPortname(), schema.getVlanId(),
431                     String.valueOf(ipAddress.getValue()), subnetCidr, gatewayIp, schema.getTransportZoneName());
432
433             freeIps.add(ipAddress);
434         }
435         LOG.debug( "Delete OnCommit in NewlyAddedDpns");
436         tepCommandHelper.deleteOnCommit();
437         deAllocateIpAddresses(freeIps, subnetCidr);
438     }
439
440     /**
441      * Calculate available IPs from the subnet mask specified in the schema.
442      * Pushes the available and allocated IP address to config DS.
443      *
444      * @param schema
445      *            the schema
446      */
447     private VtepIpPool processAvailableIps(final VtepConfigSchema schema) {
448         String subnetCidr = ItmUtils.getSubnetCidrAsString(schema.getSubnet());
449         SubnetUtils subnetUtils = new SubnetUtils(subnetCidr);
450
451         List<IpAddress> availableIps = calculateAvailableIps(subnetUtils, schema.getExcludeIpFilter(),
452                 schema.getGatewayIp());
453         VtepIpPool vtepIpPool = new VtepIpPoolBuilder().setSubnetCidr(subnetCidr).setAvailableIpaddress(availableIps)
454                 .setAllocatedIpaddress(new ArrayList<IpAddress>()).build();
455
456         MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
457                 ItmUtils.getVtepIpPoolIdentifier(subnetCidr), vtepIpPool);
458         LOG.info("Vtep IP Pool with key:{} added to config DS", subnetCidr);
459         return vtepIpPool;
460     }
461
462     /**
463      * Gets the vtep ip pool.
464      *
465      * @param subnetCidr
466      *            the subnet cidr
467      * @return the vtep ip pool
468      */
469     private VtepIpPool getVtepIpPool(final String subnetCidr) {
470         Optional<VtepIpPool> vtepIpPool = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
471                 ItmUtils.getVtepIpPoolIdentifier(subnetCidr), this.dataBroker);
472         if (vtepIpPool.isPresent()) {
473             return vtepIpPool.get();
474         }
475         return null;
476     }
477
478     /**
479      * Delete vtep ip pool.
480      *
481      * @param subnetCidr
482      *            the subnet cidr
483      */
484     private void deleteVtepIpPool(final String subnetCidr) {
485         if (StringUtils.isNotBlank(subnetCidr)) {
486             MDSALUtil.syncDelete(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
487                     ItmUtils.getVtepIpPoolIdentifier(subnetCidr));
488             LOG.debug("Deleted Vtep IP Pool with key:{}", subnetCidr);
489         }
490     }
491
492     /**
493      * Gets the an available ip.
494      *
495      * @param availableIps
496      *
497      * @return the an available ip
498      */
499     private IpAddress getAnAvailableIP(List<IpAddress> availableIps) {
500         // TODO: Sort IP Addresses, get the least value
501         IpAddress ipAddress = null;
502         if (availableIps != null && !availableIps.isEmpty()) {
503             ipAddress = availableIps.remove(0);
504         }
505         return ipAddress;
506     }
507
508     /**
509      * Allocate ip addresses.
510      *
511      * @param allocatedIps
512      *            the allocated ips
513      * @param vtepIpPool
514      *            the vtep ip pool
515      * @param subnetCidr
516      *            the subnet cidr
517      */
518     private void allocateIpAddresses(List<IpAddress> allocatedIps, VtepIpPool vtepIpPool, String subnetCidr) {
519         if (allocatedIps != null && !allocatedIps.isEmpty() && vtepIpPool != null) {
520             // Remove from the available IP address list and add to allocated IP
521             // address list.
522             VtepIpPoolBuilder builder = new VtepIpPoolBuilder(vtepIpPool);
523             if (builder.getAvailableIpaddress() != null) {
524                 builder.getAvailableIpaddress().removeAll(allocatedIps);
525             }
526             if (builder.getAllocatedIpaddress() == null) {
527                 builder.setAllocatedIpaddress(allocatedIps);
528             } else {
529                 builder.getAllocatedIpaddress().addAll(allocatedIps);
530             }
531
532             MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
533                     ItmUtils.getVtepIpPoolIdentifier(subnetCidr), builder.build());
534         }
535     }
536
537     /**
538      * De-allocate ip addresses.
539      *
540      * @param freeIps
541      *            the free ips
542      * @param subnetCidr
543      *            the subnet cidr
544      */
545     private void deAllocateIpAddresses(List<IpAddress> freeIps, String subnetCidr) {
546         VtepIpPool vtepIpPool = getVtepIpPool(subnetCidr);
547         if (freeIps != null && !freeIps.isEmpty() && vtepIpPool != null) {
548             // Remove from the allocated IP address list and add to available IP
549             // address list.
550             VtepIpPoolBuilder builder = new VtepIpPoolBuilder(vtepIpPool);
551             if (builder.getAllocatedIpaddress() != null) {
552                 builder.getAllocatedIpaddress().removeAll(freeIps);
553             }
554             if (builder.getAvailableIpaddress() == null) {
555                 builder.setAvailableIpaddress(freeIps);
556             } else {
557                 builder.getAvailableIpaddress().addAll(freeIps);
558             }
559
560             MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
561                     ItmUtils.getVtepIpPoolIdentifier(subnetCidr), builder.build());
562             LOG.debug("Vtep IP Pool with key:{} updated to config DS", subnetCidr);
563         }
564     }
565
566     /**
567      * Calculate available ips.
568      *
569      * @param subnetCidr
570      *            the subnet cidr
571      * @param excludeIpFilter
572      *            the exclude ip filter
573      * @param gatewayIp
574      *            the gateway IP
575      * @return the list
576      */
577     private List<IpAddress> calculateAvailableIps(SubnetUtils subnetUtils, String excludeIpFilter,
578             IpAddress gatewayIp) {
579         List<IpAddress> lstAvailableIps = new ArrayList<>();
580         SubnetInfo subnetInfo = subnetUtils.getInfo();
581         String[] arrIpAddresses = subnetInfo.getAllAddresses();
582
583         for (String ipAddress : arrIpAddresses) {
584             lstAvailableIps.add(new IpAddress(ipAddress.toCharArray()));
585         }
586         lstAvailableIps.remove(gatewayIp);
587         lstAvailableIps.removeAll(ItmUtils.getExcludeIpAddresses(excludeIpFilter, subnetInfo));
588
589         return lstAvailableIps;
590     }
591 }