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