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