2 * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.netvirt.natservice.internal;
11 import com.google.common.base.Optional;
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;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.MatchInfo;
25 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
26 import org.opendaylight.genius.mdsalutil.NwConstants;
27 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
28 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
29 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
30 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
31 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
32 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
33 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.RpcResult;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public class NatEvpnUtil {
55 private static final Logger LOG = LoggerFactory.getLogger(NatEvpnUtil.class);
57 static long getLPortTagForRouter(String routerIdKey, IdManagerService idManager) {
58 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
59 .setPoolName(IfmConstants.IFM_IDPOOL_NAME).setIdKey(routerIdKey)
62 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
63 RpcResult<AllocateIdOutput> rpcResult = result.get();
64 return rpcResult.getResult().getIdValue();
65 } catch (NullPointerException | InterruptedException | ExecutionException e) {
66 LOG.error("NAT Service : ID manager failed while allocating lport_tag for router {}."
67 + "Exception {}", routerIdKey, e);
72 public static void releaseLPortTagForRouter(DataBroker dataBroker, IdManagerService idManager, String routerName) {
74 String rd = NatUtil.getVpnRd(dataBroker, routerName);
75 long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
76 if (!NatEvpnUtil.isL3VpnOverVxLan(l3Vni)) {
79 ReleaseIdInput getIdInput = new ReleaseIdInputBuilder()
80 .setPoolName(IfmConstants.IFM_IDPOOL_NAME).setIdKey(routerName)
83 Future<RpcResult<Void>> result = idManager.releaseId(getIdInput);
84 RpcResult<Void> rpcResult = result.get();
85 if (!rpcResult.isSuccessful()) {
86 LOG.error("NAT Service : ID manager failed while releasing allocated lport_tag for router {}."
87 + "Exception {} ", routerName, rpcResult.getErrors());
90 } catch (NullPointerException | InterruptedException | ExecutionException e) {
91 LOG.error("NAT Service : ID manager failed while releasing allocated lport_tag for router {}."
92 + "Exception {}", routerName, e);
96 public static long getTunnelIdForRouter(IdManagerService idManager, DataBroker dataBroker, String routerName,
98 /* Only if the router is part of an L3VPN-Over-VXLAN, Router_lPort_Tag which will be carved out per router
99 from 'interfaces' POOL and used as tunnel_id. Otherwise we will continue to use router-id as the tunnel-id
100 in the following Flows.
102 1) PSNAT_TABLE (on Non-NAPT) -> Send to Remote Group
103 2) INTERNAL_TUNNEL_TABLE (on NAPT) -> Send to OUTBOUND_NAPT_TABLE */
104 String rd = NatUtil.getVpnRd(dataBroker, routerName);
105 long l3Vni = getL3Vni(dataBroker, rd);
106 if (isL3VpnOverVxLan(l3Vni)) {
107 long routerLportTag = getLPortTagForRouter(routerName, idManager);
108 if (routerLportTag != 0) {
109 LOG.trace("NAT Service : Successfully allocated Router_lPort_Tag = {} from ID Manager for "
110 + "Router ID = {}", routerLportTag, routerId);
111 return routerLportTag;
113 LOG.warn("NAT Service : Failed to allocate Router_lPort_Tag from ID Manager for Router ID = {} "
114 + "Continue to use router-id as tunnel-id", routerId);
121 static long getL3Vni(DataBroker broker, String rd) {
122 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpData(broker, rd);
123 if (vpnInstanceOpDataEntry != null && vpnInstanceOpDataEntry.getL3vni() != null) {
124 return vpnInstanceOpDataEntry.getL3vni();
126 return NatConstants.DEFAULT_L3VNI_VALUE;
129 private static VpnInstanceOpDataEntry getVpnInstanceOpData(DataBroker broker, String rd) {
130 InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(rd);
131 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
132 if (vpnInstanceOpData.isPresent()) {
133 return vpnInstanceOpData.get();
138 private static boolean isL3VpnOverVxLan(Long l3Vni) {
139 return (l3Vni != null && l3Vni != 0);
142 static ProviderTypes getExtNwProvTypeFromRouterName(DataBroker dataBroker, String routerName) {
143 ProviderTypes extNwProviderType = null;
144 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
145 if (externalNetworkId == null) {
146 LOG.error("NAT Service : Could not retrieve external network UUID for router {}", routerName);
147 return extNwProviderType;
149 extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
150 if (extNwProviderType == null) {
151 LOG.error("NAT Service : Could not retrieve provider type for external network {} ", externalNetworkId);
152 return extNwProviderType;
154 return extNwProviderType;
157 @SuppressWarnings("checkstyle:IllegalCatch")
158 public static void addRoutesForVxLanProvType(DataBroker broker,
159 IBgpManager bgpManager,
160 IFibManager fibManager,
166 String interfaceName,
168 WriteTransaction writeTx,
169 RouteOrigin origin, BigInteger dpId) {
171 LOG.info("NAT Service : ADD: Adding Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix, nextHopIp,
173 if (nextHopIp == null) {
174 LOG.error("NAT Service : addPrefix failed since nextHopIp cannot be null for prefix {}", prefix);
177 NatUtil.addPrefixToInterface(broker, NatUtil.getVpnId(broker, vpnName), interfaceName, prefix, dpId,
178 null /* subnet-id */, true /*isNatPrefix*/);
180 fibManager.addOrUpdateFibEntry(broker, rd, null /*macAddress*/, prefix,
181 Collections.singletonList(nextHopIp), VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE,
182 l3Vni, gwMacAddress, null /* parent-vpn-rd */, origin, writeTx);
183 /* Publish to Bgp only if its an INTERNET VPN */
184 if ((rd != null) && (!rd.equalsIgnoreCase(vpnName))) {
185 bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, Collections.singletonList(nextHopIp),
186 VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE, l3Vni, 0 /*l2vni*/,
189 LOG.info("NAT Service : ADD: Added Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix,
191 } catch (Exception e) {
192 LOG.error("NAT Service : Exception {} in add routes for prefix {}", e, prefix);
196 static void makeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, String macAddress,
197 List<Instruction> customInstructions, IMdsalApiManager mdsalManager) {
198 List<MatchInfo> matchInfo = new ArrayList<>();
199 matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
200 matchInfo.add(new MatchEthernetDestination(new MacAddress(macAddress)));
201 LOG.debug("NAT Service : Create flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
202 + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
203 // Install the flow entry in L3_GW_MAC_TABLE
204 String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
205 Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
206 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, customInstructions);
208 mdsalManager.installFlow(dpnId, l3GwMacTableFlowEntity);
209 LOG.debug("NAT Service : Successfully created flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
212 static void removeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, final String macAddress,
213 IMdsalApiManager mdsalManager) {
214 List<MatchInfo> matchInfo = new ArrayList<>();
215 matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
216 matchInfo.add(new MatchEthernetSource(new MacAddress(macAddress)));
217 LOG.debug("NAT Service : Remove flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
218 + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
219 // Remove the flow entry in L3_GW_MAC_TABLE
220 String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
221 Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
222 flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, null);
224 mdsalManager.removeFlow(dpnId, l3GwMacTableFlowEntity);
225 LOG.debug("NAT Service : Successfully removed flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
228 public static String getFlowRef(BigInteger dpnId, short tableId, long l3Vni, String flowName) {
229 return flowName + NwConstants.FLOWID_SEPARATOR + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
230 .FLOWID_SEPARATOR + l3Vni;
233 public static Uuid getFloatingIpInterfaceIdFromFloatingIpId(DataBroker broker, Uuid floatingIpId) {
234 InstanceIdentifier id = NatUtil.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
235 Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping = NatUtil.read(broker, LogicalDatastoreType
237 if (optFloatingIpIdToPortMapping.isPresent()) {
238 return optFloatingIpIdToPortMapping.get().getFloatingIpPortId();