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