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