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