0129993c320edfbb7b4a3b60bb89ef493e16b4db
[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*/, gwMacAddress);
187             }
188             LOG.info("NAT Service : ADD: Added Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix,
189                         nextHopIp, l3Vni);
190         } catch (Exception e) {
191             LOG.error("NAT Service : Exception {} in add routes for prefix {}", e, prefix);
192         }
193     }
194
195     static void makeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, String macAddress,
196                                       List<Instruction> customInstructions, IMdsalApiManager mdsalManager) {
197         List<MatchInfo> matchInfo = new ArrayList<>();
198         matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
199         matchInfo.add(new MatchEthernetDestination(new MacAddress(macAddress)));
200         LOG.debug("NAT Service : Create flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
201                 + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
202         // Install the flow entry in L3_GW_MAC_TABLE
203         String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
204         Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
205                 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, customInstructions);
206
207         mdsalManager.installFlow(dpnId, l3GwMacTableFlowEntity);
208         LOG.debug("NAT Service : Successfully created flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
209     }
210
211     static void removeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, final String macAddress,
212                                         IMdsalApiManager mdsalManager) {
213         List<MatchInfo> matchInfo = new ArrayList<>();
214         matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
215         matchInfo.add(new MatchEthernetSource(new MacAddress(macAddress)));
216         LOG.debug("NAT Service : Remove flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
217                 + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
218         // Remove the flow entry in L3_GW_MAC_TABLE
219         String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
220         Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
221                 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, null);
222
223         mdsalManager.removeFlow(dpnId, l3GwMacTableFlowEntity);
224         LOG.debug("NAT Service : Successfully removed flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
225     }
226
227     public static String getFlowRef(BigInteger dpnId, short tableId, long l3Vni, String flowName) {
228         return flowName + NwConstants.FLOWID_SEPARATOR + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
229                 .FLOWID_SEPARATOR + l3Vni;
230     }
231
232     public static Uuid getFloatingIpInterfaceIdFromFloatingIpId(DataBroker broker, Uuid floatingIpId) {
233         InstanceIdentifier id = NatUtil.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
234         Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping = NatUtil.read(broker, LogicalDatastoreType
235                 .CONFIGURATION, id);
236         if (optFloatingIpIdToPortMapping.isPresent()) {
237             return optFloatingIpIdToPortMapping.get().getFloatingIpPortId();
238         }
239         return null;
240     }
241 }