Switch to JDT annotations for Nullable and NonNull
[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.eclipse.jdt.annotation.Nullable;
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.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                                                  @Nullable String interfaceName,
172                                                  String gwMacAddress,
173                                                  TypedWriteTransaction<Configuration> writeTx,
174                                                  RouteOrigin origin, BigInteger dpId,
175                                                  Uuid networkId) {
176         try {
177             LOG.info("addRoutesForVxLanProvType : Adding Fib entry rd {} prefix {} nextHop {} l3Vni {}",
178                     rd, prefix, nextHopIp, l3Vni);
179             if (nextHopIp == null) {
180                 LOG.error("addRoutesForVxLanProvType : addPrefix failed since nextHopIp cannot be null for prefix {}",
181                         prefix);
182                 return;
183             }
184             NatUtil.addPrefixToInterface(broker, NatUtil.getVpnId(broker, vpnName), interfaceName, prefix,
185                     networkId.getValue(), dpId, Prefixes.PrefixCue.Nat);
186
187             fibManager.addOrUpdateFibEntry(rd, null /*macAddress*/, prefix,
188                     Collections.singletonList(nextHopIp), VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE,
189                 l3Vni, gwMacAddress, null /* parent-vpn-rd */, origin, writeTx);
190             /* Publish to Bgp only if its an INTERNET VPN */
191             if (rd != null && !rd.equalsIgnoreCase(vpnName)) {
192                 bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, Collections.singletonList(nextHopIp),
193                         VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE, l3Vni, 0 /*l2vni*/,
194                         gwMacAddress);
195             }
196             LOG.info("addRoutesForVxLanProvType : Added Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix,
197                         nextHopIp, l3Vni);
198         } catch (Exception e) {
199             LOG.error("addRoutesForVxLanProvType : Failed while adding routes for prefix {}", prefix, e);
200         }
201     }
202
203     static void makeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, String macAddress,
204         List<Instruction> customInstructions, IMdsalApiManager mdsalManager,
205         TypedWriteTransaction<Configuration> confTx) {
206
207         List<MatchInfo> matchInfo = new ArrayList<>();
208         matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
209         matchInfo.add(new MatchEthernetDestination(new MacAddress(macAddress)));
210         LOG.debug("makeL3GwMacTableEntry : Create flow table {} -> table {} for External Vpn Id = {} "
211                 + "and MacAddress = {} on DpnId = {}",
212                 NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
213         // Install the flow entry in L3_GW_MAC_TABLE
214         String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
215         Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
216                 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, customInstructions);
217
218         mdsalManager.addFlow(confTx, dpnId, l3GwMacTableFlowEntity);
219         LOG.debug("makeL3GwMacTableEntry : Successfully created flow entity {} on DPN = {}",
220                 l3GwMacTableFlowEntity, dpnId);
221     }
222
223     static void removeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, final String macAddress,
224             IMdsalApiManager mdsalManager, TypedReadWriteTransaction<Configuration> confTx)
225             throws ExecutionException, InterruptedException {
226         List<MatchInfo> matchInfo = new ArrayList<>();
227         matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
228         matchInfo.add(new MatchEthernetSource(new MacAddress(macAddress)));
229         LOG.debug("removeL3GwMacTableEntry : Remove flow table {} -> table {} for External Vpn Id = {} "
230                 + "and MacAddress = {} on DpnId = {}",
231                 NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
232         // Remove the flow entry in L3_GW_MAC_TABLE
233         String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
234         Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
235                 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, null);
236
237         mdsalManager.removeFlow(confTx, dpnId, l3GwMacTableFlowEntity);
238         LOG.debug("removeL3GwMacTableEntry : Successfully removed flow entity {} on DPN = {}",
239                 l3GwMacTableFlowEntity, dpnId);
240     }
241
242     public static String getFlowRef(BigInteger dpnId, short tableId, long l3Vni, String flowName) {
243         return flowName + NwConstants.FLOWID_SEPARATOR + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
244                 .FLOWID_SEPARATOR + l3Vni;
245     }
246
247     @Nullable
248     public static Uuid getFloatingIpInterfaceIdFromFloatingIpId(DataBroker broker, Uuid floatingIpId) {
249         InstanceIdentifier<FloatingIpIdToPortMapping> id =
250                 NatUtil.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
251         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
252                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
253                 FloatingIpIdToPortMapping::getFloatingIpPortId).orElse(null);
254     }
255 }