Handle nullable lists in natservice
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / rpcservice / NatRpcServiceImpl.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.rpcservice;
9
10 import static org.opendaylight.netvirt.natservice.internal.NatUtil.requireNonNullElse;
11
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.netvirt.natservice.internal.NatConstants;
22 import org.opendaylight.netvirt.natservice.internal.NatUtil;
23 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsForNetworkAndIpaddressInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsForNetworkAndIpaddressOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsForNetworkAndIpaddressOutputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsOnRouterInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsOnRouterOutput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsOnRouterOutputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsOnVpnInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsOnVpnOutput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.GetNatTranslationsOnVpnOutputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.OdlNatRpcService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.dnat.configuration.DnatIpMapping;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.dnat.configuration.DnatIpMappingBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.nat.output.RouterNat;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.nat.output.RouterNatBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.snat.state.SnatIpMapping;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.snat.state.SnatIpMappingBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPools;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
49 import org.opendaylight.yangtools.yang.common.RpcError;
50 import org.opendaylight.yangtools.yang.common.RpcResult;
51 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 @Singleton
56 public class NatRpcServiceImpl implements OdlNatRpcService {
57
58     private static final Logger LOG = LoggerFactory.getLogger(NatRpcServiceImpl.class);
59     private final DataBroker dataBroker;
60     private final INeutronVpnManager nvpnManager;
61
62     @Inject
63     public NatRpcServiceImpl(final DataBroker dataBroker, final INeutronVpnManager nvpnManager) {
64         this.dataBroker = dataBroker;
65         this.nvpnManager = nvpnManager;
66     }
67
68     @Override
69     public ListenableFuture<RpcResult<GetNatTranslationsOnVpnOutput>> getNatTranslationsOnVpn(
70             GetNatTranslationsOnVpnInput input) {
71         RpcResultBuilder<GetNatTranslationsOnVpnOutput> rpcResultBuilder = null;
72
73         List<Uuid> routerUuidList = NatUtil.getRouterUuIdsForVpn(dataBroker, input.getVpnUuid());
74         if (routerUuidList.isEmpty()) {
75             String errMsg = String.format("404 Not Found - Invalid external vpn {%s} provided",
76                     input.getVpnUuid().getValue());
77             rpcResultBuilder = RpcResultBuilder.<GetNatTranslationsOnVpnOutput>failed()
78                     .withError(RpcError.ErrorType.APPLICATION, errMsg);
79             return rpcResultBuilder.buildFuture();
80         }
81         List<RouterNat> natRouterList = new ArrayList<>();
82         for (Uuid routerUuid : routerUuidList) {
83             long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());
84             if (routerId == NatConstants.INVALID_ID) {
85                 LOG.warn("getNatTranslationsOnVpn : Invalid RouterID found {}", routerId);
86                 continue;
87             }
88             natRouterList.addAll(constructNatInformation(routerUuid, routerId));
89         }
90         GetNatTranslationsOnVpnOutputBuilder output = new GetNatTranslationsOnVpnOutputBuilder()
91                 .setRouterNat(natRouterList);
92         rpcResultBuilder = RpcResultBuilder.success();
93         rpcResultBuilder.withResult(output.build());
94         return Futures.immediateFuture(rpcResultBuilder.build());
95     }
96
97     @Override
98     public ListenableFuture<RpcResult<GetNatTranslationsOnRouterOutput>> getNatTranslationsOnRouter(
99             GetNatTranslationsOnRouterInput input) {
100         RpcResultBuilder<GetNatTranslationsOnRouterOutput> rpcResultBuilder = null;
101         long routerId = NatUtil.getVpnId(dataBroker, input.getRouterUuid().getValue());
102         if (routerId == NatConstants.INVALID_ID) {
103             String errMsg = String.format("404 Not Found - No Router found with UUID {%s}",
104                     input.getRouterUuid().getValue());
105             rpcResultBuilder = RpcResultBuilder.<GetNatTranslationsOnRouterOutput>failed()
106                     .withError(RpcError.ErrorType.APPLICATION, errMsg);
107             return rpcResultBuilder.buildFuture();
108         }
109
110         List<RouterNat> routerNatList = constructNatInformation(input.getRouterUuid(), routerId);
111
112         GetNatTranslationsOnRouterOutputBuilder output = new GetNatTranslationsOnRouterOutputBuilder()
113                 .setRouterNat(routerNatList);
114         rpcResultBuilder = RpcResultBuilder.success();
115         rpcResultBuilder.withResult(output.build());
116         return rpcResultBuilder.buildFuture();
117     }
118
119     @Override
120     public ListenableFuture<RpcResult<GetNatTranslationsForNetworkAndIpaddressOutput>>
121             getNatTranslationsForNetworkAndIpaddress(GetNatTranslationsForNetworkAndIpaddressInput input) {
122
123         String ipAddress = input.getIpAddress().stringValue();
124         RpcResultBuilder<GetNatTranslationsForNetworkAndIpaddressOutput> rpcResultBuilder = null;
125         GetNatTranslationsForNetworkAndIpaddressOutputBuilder output = null;
126
127         List<Uuid> subnetUuidList = NatUtil.getSubnetIdsFromNetworkId(dataBroker, input.getNetworkUuid());
128         if (subnetUuidList.isEmpty()) {
129             String errMsg = String.format("404 Not Found - Invalid Network UUID {%s} provided as no Subnetworks found",
130                     input.getNetworkUuid().getValue());
131             rpcResultBuilder = RpcResultBuilder.<GetNatTranslationsForNetworkAndIpaddressOutput>failed()
132                     .withError(RpcError.ErrorType.APPLICATION, errMsg);
133             return rpcResultBuilder.buildFuture();
134         }
135         Subnet subNet = null;
136         Boolean isIpInSubnet = Boolean.FALSE;
137         outerloop:
138         for (Uuid subnetUuid: subnetUuidList) {
139             subNet = nvpnManager.getNeutronSubnet(subnetUuid);
140             for (AllocationPools allocationPool : requireNonNullElse(subNet.getAllocationPools(),
141                     Collections.<AllocationPools>emptyList())) {
142                 if (NatUtil.isIpInSubnet(ipAddress,
143                         allocationPool.getStart().stringValue(),
144                         allocationPool.getEnd().stringValue())) {
145                     LOG.debug("getNatTranslationsForNetworkAndIpaddress : IP Adderess {} falls within the Subnet {}",
146                             ipAddress, subNet.getUuid().getValue());
147                     isIpInSubnet = Boolean.TRUE;
148                     break outerloop;
149                 }
150             }
151         }
152
153         if (!isIpInSubnet) {
154             String errMsg = String.format("404 Not Found - IP Adress {%s} does not fall within the Subnet IP range"
155                     + " of Network {%s}", ipAddress, input.getNetworkUuid().getValue());
156             rpcResultBuilder = RpcResultBuilder.<GetNatTranslationsForNetworkAndIpaddressOutput>failed()
157                     .withError(RpcError.ErrorType.APPLICATION, errMsg);
158             return rpcResultBuilder.buildFuture();
159         }
160
161         Subnetmap subnetMap = NatUtil.getSubnetMap(dataBroker, subNet.getUuid());
162         long routerId = NatUtil.getVpnId(dataBroker, subnetMap.getRouterId().getValue());
163
164         List<Ports> fipPorts = NatUtil.getFloatingIpPortsForRouter(dataBroker, subnetMap.getRouterId());
165         if (fipPorts.isEmpty()) {
166             LOG.warn("getNatTranslationsForNetworkAndIpaddress : No DNAT IP Mapping found for IP {}", ipAddress);
167         } else {
168             for (Ports fipPort : fipPorts) {
169                 for (InternalToExternalPortMap fipMap : requireNonNullElse(fipPort.getInternalToExternalPortMap(),
170                         Collections.<InternalToExternalPortMap>emptyList())) {
171                     if (fipMap.getInternalIp().equals(ipAddress)) {
172                         output = new GetNatTranslationsForNetworkAndIpaddressOutputBuilder()
173                                     .setExternalIp(fipMap.getExternalIp())
174                                     .setNatTranslation("DNAT");
175                         rpcResultBuilder = RpcResultBuilder.success();
176                         rpcResultBuilder.withResult(output.build());
177                         return rpcResultBuilder.buildFuture();
178                     }
179                 }
180             }
181         }
182
183         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
184         if (ipPortMapping == null) {
185             LOG.warn("getNatTranslationsForNetworkAndIpaddress : No SNAT IP Mapping found for IP {}", ipAddress);
186         } else {
187             for (IntextIpProtocolType protocolType : requireNonNullElse(ipPortMapping.getIntextIpProtocolType(),
188                     Collections.<IntextIpProtocolType>emptyList())) {
189                 for (IpPortMap ipPortMap : requireNonNullElse(protocolType.getIpPortMap(),
190                         Collections.<IpPortMap>emptyList())) {
191                     String[] internalIpPort = ipPortMap.getIpPortInternal().split(NwConstants.MACADDR_SEP);
192                     if (ipAddress.equals(internalIpPort[0])) {
193
194                         output = new GetNatTranslationsForNetworkAndIpaddressOutputBuilder()
195                                 .setExternalIp(ipPortMap.getIpPortExternal().getIpAddress())
196                                 .setInternalIp(internalIpPort[0])
197                                 .setNatTranslation("SNAT")
198                                 .setInternalPort(internalIpPort[1])
199                                 .setExternalPort(ipPortMap.getIpPortExternal().getPortNum().toString())
200                                 .setProtocol(protocolType.getProtocol().getName());
201                         rpcResultBuilder = RpcResultBuilder.success();
202                         rpcResultBuilder.withResult(output.build());
203                         return rpcResultBuilder.buildFuture();
204                     }
205                 }
206             }
207         }
208
209         String errMsg = String.format("404 Not Found - No NAT Translation found for IP {%s}", ipAddress);
210         rpcResultBuilder = RpcResultBuilder.<GetNatTranslationsForNetworkAndIpaddressOutput>failed()
211                 .withError(RpcError.ErrorType.APPLICATION, errMsg);
212         return rpcResultBuilder.buildFuture();
213     }
214
215     private List<RouterNat> constructNatInformation(Uuid routerUuid, long routerId) {
216
217         String neutronRouterName = NatUtil.getNeutronRouterNamebyUuid(dataBroker, routerUuid);
218
219         RouterNatBuilder natRouterBuilder = new RouterNatBuilder();
220         natRouterBuilder.setRouterUuid(routerUuid);
221         natRouterBuilder.setRouterName(neutronRouterName);
222
223         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
224         if (ipPortMapping == null) {
225             LOG.warn("constructNatInformation : No SNAT IP Mapping found for router-uuid {}", routerUuid.getValue());
226         } else {
227
228             // Capturing SNAT information
229             List<SnatIpMapping> snatIpMapping = new ArrayList<>();
230
231             for (IntextIpProtocolType protocolType : requireNonNullElse(ipPortMapping.getIntextIpProtocolType(),
232                     Collections.<IntextIpProtocolType>emptyList())) {
233                 for (IpPortMap ipPortMap : requireNonNullElse(protocolType.getIpPortMap(),
234                         Collections.<IpPortMap>emptyList())) {
235                     String[] internalPortMap = ipPortMap.getIpPortInternal().split(NwConstants.MACADDR_SEP);
236                     SnatIpMappingBuilder natIpMappingBuilder = new SnatIpMappingBuilder()
237                             .setInternalIp(internalPortMap[0]).setInternalPort(internalPortMap[1])
238                             .setExternalIp(ipPortMap.getIpPortExternal().getIpAddress())
239                             .setExternalPort(ipPortMap.getIpPortExternal().getPortNum().toString())
240                             .setProtocol(protocolType.getProtocol().getName());
241                     snatIpMapping.add(natIpMappingBuilder.build());
242                 }
243             }
244             natRouterBuilder.setSnatIpMapping(snatIpMapping);
245         }
246
247         // Capturing DNAT information
248         List<DnatIpMapping> dnatIpMapping = new ArrayList<>();
249         List<Ports> fipPorts = NatUtil.getFloatingIpPortsForRouter(dataBroker, routerUuid);
250         if (fipPorts.isEmpty()) {
251             LOG.warn("constructNatInformation : No DNAT IP Mapping found for router-uuid {}", routerUuid.getValue());
252         } else {
253             for (Ports fipPort : fipPorts) {
254                 for (InternalToExternalPortMap fipMap : requireNonNullElse(fipPort.getInternalToExternalPortMap(),
255                         Collections.<InternalToExternalPortMap>emptyList())) {
256                     DnatIpMappingBuilder natIpMappingBuilder = new DnatIpMappingBuilder()
257                             .setExternalIp(fipMap.getExternalIp()).setInternalIp(fipMap.getInternalIp());
258                     dnatIpMapping.add(natIpMappingBuilder.build());
259                 }
260             }
261             natRouterBuilder.setDnatIpMapping(dnatIpMapping);
262         }
263
264         List<RouterNat> natRouterList = new ArrayList<>();
265         natRouterList.add(natRouterBuilder.build());
266         return natRouterList;
267     }
268 }