FIP support for Octavia VIPs
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatOverVxlanUtil.java
1 /*
2  * Copyright © 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.concurrent.ExecutionException;
13 import java.util.concurrent.Future;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
17 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolOutput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.opendaylight.yangtools.yang.common.RpcResult;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public final class NatOverVxlanUtil {
40
41     private static final Logger LOG = LoggerFactory.getLogger(NatOverVxlanUtil.class);
42
43     private NatOverVxlanUtil() { }
44
45     public static BigInteger getInternetVpnVni(IdManagerService idManager, String vpnUuid, long vpnid) {
46         BigInteger internetVpnVni = getVNI(vpnUuid, idManager);
47         if (internetVpnVni.longValue() == -1) {
48             LOG.warn("getInternetVpnVni : Unable to obtain Internet Vpn VNI from VNI POOL for Vpn {}."
49                     + "Will use tunnel_id {} as Internet VNI", vpnUuid, vpnid);
50             return BigInteger.valueOf(vpnid);
51         }
52         return internetVpnVni;
53     }
54
55     public static BigInteger getRouterVni(IdManagerService idManager, String routerName, long routerId) {
56         BigInteger routerVni = getVNI(routerName, idManager);
57         if (routerVni.longValue() == -1) {
58             LOG.warn("getRouterVni : Unable to obtain Router VNI from VNI POOL for router {}."
59                     + "Router ID will be used as tun_id", routerName);
60             return BigInteger.valueOf(routerId);
61         }
62         return routerVni;
63     }
64
65     public static BigInteger getVNI(String vniKey, IdManagerService idManager) {
66         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(NatConstants.ODL_VNI_POOL_NAME)
67                 .setIdKey(vniKey).build();
68         try {
69             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
70             RpcResult<AllocateIdOutput> rpcResult = result.get();
71             if (rpcResult.isSuccessful()) {
72                 return BigInteger.valueOf(rpcResult.getResult().getIdValue());
73             }
74         } catch (NullPointerException | InterruptedException | ExecutionException e) {
75             LOG.error("getVNI : Exception in get VNI for key {}", vniKey, e);
76         }
77         return BigInteger.valueOf(-1);
78     }
79
80     public static void releaseVNI(String vniKey, IdManagerService idManager) {
81         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(NatConstants.ODL_VNI_POOL_NAME)
82             .setIdKey(vniKey).build();
83         try {
84             RpcResult<ReleaseIdOutput> rpcResult = idManager.releaseId(releaseIdInput).get();
85             if (!rpcResult.isSuccessful()) {
86                 LOG.warn("releaseVNI : Unable to release ID {} from OpenDaylight VXLAN VNI range pool. Error {}",
87                         vniKey, rpcResult.getErrors());
88             }
89         } catch (NullPointerException | InterruptedException | ExecutionException e) {
90             LOG.error("releaseVNI : Exception in release VNI for Key {}", vniKey, e);
91         }
92     }
93
94     public static void validateAndCreateVxlanVniPool(DataBroker broker, INeutronVpnManager neutronvpnManager,
95             IdManagerService idManager, String poolName) {
96         /*
97          * 1. If a NatPool doesn't exist create it. 2. If a NatPool exists, but
98          * the range value is changed incorrectly (say some allocations exist in
99          * the old range), we should NOT honor the new range . Throw the WARN
100          * but continue running NAT Service with Old range. 3. If a NatPool
101          * exists, but the given range is wider than the earlier one, we should
102          * attempt to allocate with the new range again(TODO)
103          */
104         long lowLimit = NatConstants.VNI_DEFAULT_LOW_VALUE;
105         long highLimit = NatConstants.VNI_DEFAULT_HIGH_VALUE;
106         String configureVniRange = neutronvpnManager.getOpenDaylightVniRangesConfig();
107         if (configureVniRange != null) {
108             String[] configureVniRangeSplit = configureVniRange.split(":");
109             lowLimit = Long.parseLong(configureVniRangeSplit[0]);
110             highLimit = Long.parseLong(configureVniRangeSplit[1]);
111         }
112         Optional<IdPool> existingIdPool =
113                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
114                         LogicalDatastoreType.CONFIGURATION, getIdPoolInstance(poolName));
115         if (existingIdPool.isPresent()) {
116             IdPool odlVniIdPool = existingIdPool.get();
117             long currentStartLimit = odlVniIdPool.getAvailableIdsHolder().getStart();
118             long currentEndLimit = odlVniIdPool.getAvailableIdsHolder().getEnd();
119
120             if (lowLimit == currentStartLimit && highLimit == currentEndLimit) {
121                 LOG.debug("validateAndCreateVxlanVniPool : OpenDaylight VXLAN VNI range pool already exists "
122                         + "with configured Range");
123             } else {
124                 if (odlVniIdPool.getIdEntries() != null && odlVniIdPool.getIdEntries().size() != 0) {
125                     LOG.warn("validateAndCreateVxlanVniPool : Some Allocation already exists with old Range. "
126                             + "Cannot modify existing limit of OpenDaylight VXLAN VNI range pool");
127                 } else {
128                     LOG.debug("validateAndCreateVxlanVniPool : No VNI's allocated from OpenDaylight VXLAN VNI range "
129                             + "pool. Delete and re-create pool with new configured Range {}-{}",lowLimit, highLimit);
130                     deleteOpenDaylightVniRangesPool(idManager, poolName);
131                     createOpenDaylightVniRangesPool(idManager, poolName, lowLimit, highLimit);
132                 }
133             }
134         } else {
135             createOpenDaylightVniRangesPool(idManager, poolName, lowLimit, highLimit);
136         }
137     }
138
139     public static void createOpenDaylightVniRangesPool(IdManagerService idManager, String poolName, long lowLimit,
140             long highLimit) {
141
142         CreateIdPoolInput createPool = null;
143         createPool = new CreateIdPoolInputBuilder().setPoolName(poolName).setLow(lowLimit).setHigh(highLimit).build();
144         try {
145             Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
146             if (result != null && result.get().isSuccessful()) {
147                 LOG.debug("createOpenDaylightVniRangesPool : Created OpenDaylight VXLAN VNI range pool {} "
148                         + "with range {}-{}", poolName, lowLimit, highLimit);
149             } else {
150                 LOG.error("createOpenDaylightVniRangesPool : Failed to create OpenDaylight VXLAN VNI range pool {} "
151                         + "with range {}-{}", poolName, lowLimit, highLimit);
152             }
153         } catch (InterruptedException | ExecutionException e) {
154             LOG.error("createOpenDaylightVniRangesPool : Failed to create OpenDaylight VXLAN VNI range pool {} "
155                     + "with range {}-{}", poolName, lowLimit, highLimit);
156         }
157     }
158
159     public static void deleteOpenDaylightVniRangesPool(IdManagerService idManager, String poolName) {
160
161         DeleteIdPoolInput deletePool = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
162         Future<RpcResult<DeleteIdPoolOutput>> result = idManager.deleteIdPool(deletePool);
163         try {
164             if (result != null && result.get().isSuccessful()) {
165                 LOG.debug("deleteOpenDaylightVniRangesPool : Deleted OpenDaylight VXLAN VNI range pool {} successfully",
166                         poolName);
167             } else {
168                 LOG.error("deleteOpenDaylightVniRangesPool : Failed to delete OpenDaylight VXLAN VNI range pool {} ",
169                         poolName);
170             }
171         } catch (InterruptedException | ExecutionException e) {
172             LOG.error("deleteOpenDaylightVniRangesPool : Failed to delete OpenDaylight VXLAN VNI range pool {} ",
173                     poolName, e);
174         }
175     }
176
177     private static InstanceIdentifier<IdPool> getIdPoolInstance(String poolName) {
178         InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idPoolBuilder = InstanceIdentifier.builder(IdPools.class)
179                 .child(IdPool.class, new IdPoolKey(poolName));
180         InstanceIdentifier<IdPool> id = idPoolBuilder.build();
181         return id;
182     }
183 }