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