NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / dhcpservice / impl / src / main / java / org / opendaylight / netvirt / dhcpservice / DhcpAllocationPoolManager.java
1 /*
2  * Copyright (c) 2017 Hewlett Packard Enterprise, Co. 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.dhcpservice;
9
10 import java.util.Collections;
11 import java.util.EventListener;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Optional;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.Future;
17 import java.util.stream.Collectors;
18 import javax.annotation.PostConstruct;
19 import javax.annotation.PreDestroy;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
25 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
26 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
27 import org.opendaylight.mdsal.binding.api.DataBroker;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp_allocation_pool.rev161214.DhcpAllocationPool;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp_allocation_pool.rev161214.dhcp_allocation_pool.Network;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp_allocation_pool.rev161214.dhcp_allocation_pool.NetworkKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp_allocation_pool.rev161214.dhcp_allocation_pool.network.AllocationPool;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.config.rev150710.DhcpserviceConfig;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.common.RpcResult;
56 import org.opendaylight.yangtools.yang.common.Uint64;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 @Singleton
61 public class DhcpAllocationPoolManager implements AutoCloseable, EventListener {
62     private static final Logger LOG = LoggerFactory.getLogger(DhcpAllocationPoolManager.class);
63
64     private DhcpAllocationPoolListener dhcpAllocationPoolListener;
65
66     private final DataBroker dataBroker;
67     private final IdManagerService idManager;
68     private final DhcpserviceConfig config;
69     private final JobCoordinator jobCoordinator;
70
71     @Inject
72     public DhcpAllocationPoolManager(final DataBroker dataBroker, final IdManagerService idManager,
73             final DhcpserviceConfig config, final JobCoordinator jobCoordinator) {
74         this.dataBroker = dataBroker;
75         this.idManager = idManager;
76         this.config = config;
77         this.jobCoordinator = jobCoordinator;
78     }
79
80     @PostConstruct
81     public void init() {
82         if (config.isDhcpDynamicAllocationPoolEnabled()) {
83             dhcpAllocationPoolListener = new DhcpAllocationPoolListener(this, dataBroker, jobCoordinator);
84             LOG.info("DHCP Allocation Pool Service initialized");
85         }
86     }
87
88     @Override
89     @PreDestroy
90     public void close() {
91         LOG.info("{} close", getClass().getSimpleName());
92         if (dhcpAllocationPoolListener != null) {
93             dhcpAllocationPoolListener.close();
94         }
95     }
96
97     @Nullable
98     public IpAddress getIpAllocation(String networkId, AllocationPool pool, String macAddress) {
99         String poolIdKey = getPoolKeyIdByAllocationPool(networkId, pool);
100         long allocatedIpLong = createIdAllocation(poolIdKey, macAddress);
101         LOG.debug("allocated id {} for mac {}, from pool {}", allocatedIpLong, macAddress, poolIdKey);
102         return allocatedIpLong != 0 ? DhcpServiceUtils.convertLongToIp(allocatedIpLong) : null;
103     }
104
105     public void releaseIpAllocation(String networkId, AllocationPool pool, String macAddress) {
106         String poolIdKey = getPoolKeyIdByAllocationPool(networkId, pool);
107         LOG.debug("going to release id for mac {}, from pool {}", macAddress, poolIdKey);
108         releaseIdAllocation(poolIdKey, macAddress);
109     }
110
111     @Nullable
112     public AllocationPool getAllocationPoolByNetwork(String networkId) throws ExecutionException, InterruptedException {
113         InstanceIdentifier<Network> network = InstanceIdentifier.builder(DhcpAllocationPool.class)
114                 .child(Network.class, new NetworkKey(networkId)).build();
115         Optional<Network> optionalNetworkConfData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
116                 LogicalDatastoreType.CONFIGURATION, network);
117         if (!optionalNetworkConfData.isPresent()) {
118             LOG.info("No network configuration data for network {}", networkId);
119             return null;
120         }
121         Network networkConfData = optionalNetworkConfData.get();
122         List<AllocationPool> allocationPoolList = networkConfData.getAllocationPool();
123         // if network has allocation pool list - get the first element
124         // as we have no info about a specific subnet
125         if (allocationPoolList != null && !allocationPoolList.isEmpty()) {
126             return allocationPoolList.get(0);
127         } else {
128             LOG.warn("No allocation pools for network {}", networkId);
129             return null;
130         }
131     }
132
133     @NonNull
134     public Map<Uint64, List<String>> getElanDpnInterfacesByName(DataBroker broker, String elanInstanceName) {
135         InstanceIdentifier<ElanDpnInterfacesList> elanDpnIfacesIid = InstanceIdentifier.builder(ElanDpnInterfaces.class)
136                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
137         Optional<ElanDpnInterfacesList> elanDpnIfacesOpc;
138         try {
139             elanDpnIfacesOpc = SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.OPERATIONAL,
140                     elanDpnIfacesIid);
141         } catch (ExecutionException | InterruptedException e) {
142             LOG.error("getElanDpnInterfacesByName: Exception while reading the ElanDpnInterfacesList DS for the "
143                     + "elan-instance {}", elanInstanceName, e);
144             return Collections.emptyMap();
145         }
146         if (!elanDpnIfacesOpc.isPresent()) {
147             LOG.warn("Could not find DpnInterfaces for elan {}", elanInstanceName);
148             return Collections.emptyMap();
149         }
150
151         return elanDpnIfacesOpc.get().nonnullDpnInterfaces().stream()
152             .collect(Collectors.toMap(DpnInterfaces::getDpId,
153                 value -> value.getInterfaces() != null ? value.getInterfaces() : Collections.emptyList()));
154     }
155
156     @Nullable
157     public String getNetworkByPort(String portUuid) throws ExecutionException, InterruptedException {
158         InstanceIdentifier<ElanInterface> elanInterfaceName = InstanceIdentifier.builder(ElanInterfaces.class)
159                 .child(ElanInterface.class, new ElanInterfaceKey(portUuid)).build();
160         Optional<ElanInterface> optionalElanInterface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
161                 LogicalDatastoreType.CONFIGURATION, elanInterfaceName);
162         if (!optionalElanInterface.isPresent()) {
163             LOG.info("No elan interface data for port {}", portUuid);
164             return null;
165         }
166         ElanInterface elanInterface = optionalElanInterface.get();
167         return elanInterface.getElanInstanceName();
168     }
169
170     private static String getPoolKeyIdByAllocationPool(String networkId, AllocationPool pool) {
171         return "dhcpAllocationPool." + networkId + "." + pool.getSubnet().stringValue();
172     }
173
174     private long createIdAllocation(String groupIdKey, String idKey) {
175         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(groupIdKey).setIdKey(idKey).build();
176         try {
177             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
178             RpcResult<AllocateIdOutput> rpcResult = result.get();
179             return rpcResult.getResult().getIdValue().toJava();
180         } catch (NullPointerException | InterruptedException | ExecutionException e) {
181             LOG.trace("Failed to allocate id for DHCP Allocation Pool Service", e);
182         }
183         return 0;
184     }
185
186     private void releaseIdAllocation(String groupIdKey, String idKey) {
187         ReleaseIdInput getIdInput = new ReleaseIdInputBuilder().setPoolName(groupIdKey).setIdKey(idKey).build();
188         JdkFutures.addErrorLogging(idManager.releaseId(getIdInput), LOG, "Release Id");
189     }
190
191     protected void createIdAllocationPool(String networkId, AllocationPool pool) {
192         String poolName = getPoolKeyIdByAllocationPool(networkId, pool);
193         long low = DhcpServiceUtils.convertIpToLong(pool.getAllocateFrom());
194         long high = DhcpServiceUtils.convertIpToLong(pool.getAllocateTo());
195         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(poolName).setLow(low).setHigh(high)
196                 .build();
197         try {
198             Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
199             if (result != null && result.get().isSuccessful()) {
200                 LOG.info("DHCP Allocation Pool Service : Created IdPool name {}", poolName);
201             } else {
202                 LOG.error("DHCP Allocation Pool Service : Unable to create IdPool name {}", poolName);
203             }
204         } catch (InterruptedException | ExecutionException e) {
205             LOG.error("Failed to create Pool for DHCP Allocation Pool Service", e);
206         }
207     }
208
209     protected void releaseIdAllocationPool(String networkId, AllocationPool pool) {
210         String poolName = getPoolKeyIdByAllocationPool(networkId, pool);
211         DeleteIdPoolInput deletePool = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
212         try {
213             Future<RpcResult<DeleteIdPoolOutput>> result = idManager.deleteIdPool(deletePool);
214             if (result != null && result.get().isSuccessful()) {
215                 LOG.info("DHCP Allocation Pool Service : Deleted IdPool name {}", poolName);
216             } else {
217                 LOG.error("DHCP Allocation Pool Service : Unable to delete IdPool name {}", poolName);
218             }
219         } catch (InterruptedException | ExecutionException e) {
220             LOG.error("Failed to delete Pool for DHCP Allocation Pool Service", e);
221         }
222     }
223 }