Use documenting constants for put()
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatEvpnUtil.java
1 /*
2  * Copyright (c) 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import com.google.common.base.Optional;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.MatchInfo;
25 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
26 import org.opendaylight.genius.mdsalutil.NwConstants;
27 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
28 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
29 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
30 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
31 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
32 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
33 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.RpcResult;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 public class NatEvpnUtil {
54
55     private static final Logger LOG = LoggerFactory.getLogger(NatEvpnUtil.class);
56
57     static long getLPortTagForRouter(String routerIdKey, IdManagerService idManager) {
58         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
59                 .setPoolName(IfmConstants.IFM_IDPOOL_NAME).setIdKey(routerIdKey)
60                 .build();
61         try {
62             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
63             RpcResult<AllocateIdOutput> rpcResult = result.get();
64             return rpcResult.getResult().getIdValue();
65         } catch (NullPointerException | InterruptedException | ExecutionException e) {
66             LOG.error("NAT Service : ID manager failed while allocating lport_tag for router {}."
67                     + "Exception {}", routerIdKey, e);
68         }
69         return 0;
70     }
71
72     public static void releaseLPortTagForRouter(DataBroker dataBroker, IdManagerService idManager, String routerName) {
73
74         String rd = NatUtil.getVpnRd(dataBroker, routerName);
75         long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
76         if (!NatEvpnUtil.isL3VpnOverVxLan(l3Vni)) {
77             return;
78         }
79         ReleaseIdInput getIdInput = new ReleaseIdInputBuilder()
80                 .setPoolName(IfmConstants.IFM_IDPOOL_NAME).setIdKey(routerName)
81                 .build();
82         try {
83             Future<RpcResult<Void>> result = idManager.releaseId(getIdInput);
84             RpcResult<Void> rpcResult = result.get();
85             if (!rpcResult.isSuccessful()) {
86                 LOG.error("NAT Service : ID manager failed while releasing allocated lport_tag for router {}."
87                         + "Exception {} ", routerName, rpcResult.getErrors());
88                 return;
89             }
90         } catch (NullPointerException | InterruptedException | ExecutionException e) {
91             LOG.error("NAT Service : ID manager failed while releasing allocated lport_tag for router {}."
92                     + "Exception {}", routerName, e);
93         }
94     }
95
96     public static long getTunnelIdForRouter(IdManagerService idManager, DataBroker dataBroker, String routerName,
97                                             long routerId) {
98         /* Only if the router is part of an L3VPN-Over-VXLAN, Router_lPort_Tag which will be carved out per router
99          from 'interfaces' POOL and used as tunnel_id. Otherwise we will continue to use router-id as the tunnel-id
100          in the following Flows.
101
102          1) PSNAT_TABLE (on Non-NAPT) -> Send to Remote Group
103          2) INTERNAL_TUNNEL_TABLE (on NAPT) -> Send to OUTBOUND_NAPT_TABLE */
104         String rd = NatUtil.getVpnRd(dataBroker, routerName);
105         long l3Vni = getL3Vni(dataBroker, rd);
106         if (isL3VpnOverVxLan(l3Vni)) {
107             long routerLportTag = getLPortTagForRouter(routerName, idManager);
108             if (routerLportTag != 0) {
109                 LOG.trace("NAT Service : Successfully allocated Router_lPort_Tag = {} from ID Manager for "
110                         + "Router ID = {}", routerLportTag, routerId);
111                 return routerLportTag;
112             } else {
113                 LOG.warn("NAT Service : Failed to allocate Router_lPort_Tag from ID Manager for Router ID = {} "
114                         + "Continue to use router-id as tunnel-id", routerId);
115                 return routerId;
116             }
117         }
118         return routerId;
119     }
120
121     static long getL3Vni(DataBroker broker, String rd) {
122         VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpData(broker, rd);
123         if (vpnInstanceOpDataEntry != null && vpnInstanceOpDataEntry.getL3vni() != null) {
124             return vpnInstanceOpDataEntry.getL3vni();
125         }
126         return NatConstants.DEFAULT_L3VNI_VALUE;
127     }
128
129     private static VpnInstanceOpDataEntry getVpnInstanceOpData(DataBroker broker, String rd) {
130         InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(rd);
131         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
132         if (vpnInstanceOpData.isPresent()) {
133             return vpnInstanceOpData.get();
134         }
135         return null;
136     }
137
138     private static boolean isL3VpnOverVxLan(Long l3Vni) {
139         return (l3Vni != null && l3Vni != 0);
140     }
141
142     static ProviderTypes getExtNwProvTypeFromRouterName(DataBroker dataBroker, String routerName) {
143         ProviderTypes extNwProviderType = null;
144         Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
145         if (externalNetworkId == null) {
146             LOG.error("NAT Service : Could not retrieve external network UUID for router {}", routerName);
147             return extNwProviderType;
148         }
149         extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
150         if (extNwProviderType == null) {
151             LOG.error("NAT Service : Could not retrieve provider type for external network {} ", externalNetworkId);
152             return extNwProviderType;
153         }
154         return extNwProviderType;
155     }
156
157     @SuppressWarnings("checkstyle:IllegalCatch")
158     public static void addRoutesForVxLanProvType(DataBroker broker,
159                                                  IBgpManager bgpManager,
160                                                  IFibManager fibManager,
161                                                  String vpnName,
162                                                  String rd,
163                                                  String prefix,
164                                                  String nextHopIp,
165                                                  long l3Vni,
166                                                  String interfaceName,
167                                                  String gwMacAddress,
168                                                  WriteTransaction writeTx,
169                                                  RouteOrigin origin, BigInteger dpId) {
170         try {
171             LOG.info("NAT Service : ADD: Adding Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix, nextHopIp,
172                     l3Vni);
173             if (nextHopIp == null) {
174                 LOG.error("NAT Service : addPrefix failed since nextHopIp cannot be null for prefix {}", prefix);
175                 return;
176             }
177             NatUtil.addPrefixToInterface(broker, NatUtil.getVpnId(broker, vpnName), interfaceName, prefix, dpId,
178                     null /* subnet-id */, true /*isNatPrefix*/);
179
180             fibManager.addOrUpdateFibEntry(broker, rd, null /*macAddress*/, prefix,
181                     Collections.singletonList(nextHopIp), VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE,
182                     l3Vni, gwMacAddress, null /* parent-vpn-rd */, origin, writeTx);
183             /* Publish to Bgp only if its an INTERNET VPN */
184             if ((rd != null) && (!rd.equalsIgnoreCase(vpnName))) {
185                 bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, Collections.singletonList(nextHopIp),
186                         VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE, l3Vni, 0 /*l2vni*/,
187                         gwMacAddress);
188             }
189             LOG.info("NAT Service : ADD: Added Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix,
190                         nextHopIp, l3Vni);
191         } catch (Exception e) {
192             LOG.error("NAT Service : Exception {} in add routes for prefix {}", e, prefix);
193         }
194     }
195
196     static void makeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, String macAddress,
197                                       List<Instruction> customInstructions, IMdsalApiManager mdsalManager) {
198         List<MatchInfo> matchInfo = new ArrayList<>();
199         matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
200         matchInfo.add(new MatchEthernetDestination(new MacAddress(macAddress)));
201         LOG.debug("NAT Service : Create flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
202                 + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
203         // Install the flow entry in L3_GW_MAC_TABLE
204         String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
205         Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
206                 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, customInstructions);
207
208         mdsalManager.installFlow(dpnId, l3GwMacTableFlowEntity);
209         LOG.debug("NAT Service : Successfully created flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
210     }
211
212     static void removeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, final String macAddress,
213                                         IMdsalApiManager mdsalManager) {
214         List<MatchInfo> matchInfo = new ArrayList<>();
215         matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
216         matchInfo.add(new MatchEthernetSource(new MacAddress(macAddress)));
217         LOG.debug("NAT Service : Remove flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
218                 + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
219         // Remove the flow entry in L3_GW_MAC_TABLE
220         String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
221         Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
222                 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, null);
223
224         mdsalManager.removeFlow(dpnId, l3GwMacTableFlowEntity);
225         LOG.debug("NAT Service : Successfully removed flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
226     }
227
228     public static String getFlowRef(BigInteger dpnId, short tableId, long l3Vni, String flowName) {
229         return flowName + NwConstants.FLOWID_SEPARATOR + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
230                 .FLOWID_SEPARATOR + l3Vni;
231     }
232
233     public static Uuid getFloatingIpInterfaceIdFromFloatingIpId(DataBroker broker, Uuid floatingIpId) {
234         InstanceIdentifier id = NatUtil.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
235         Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping = NatUtil.read(broker, LogicalDatastoreType
236                 .CONFIGURATION, id);
237         if (optFloatingIpIdToPortMapping.isPresent()) {
238             return optFloatingIpIdToPortMapping.get().getFloatingIpPortId();
239         }
240         return null;
241     }
242 }