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