Ethernet VPN (EVPN_RT5) Enhancement to Non-NAPT to NAPT 63/52163/20
authorkarthikeyan <karthikeyan.k@altencalsoftlabs.com>
Wed, 22 Feb 2017 10:33:45 +0000 (16:03 +0530)
committerVivekanandan Narasimhan <n.vivekanandan@ericsson.com>
Wed, 8 Mar 2017 08:58:36 +0000 (08:58 +0000)
This review (1st Review) is part of EVPN_RT5 support in NAT feature.

Changes are made in the NAT code for accomplishing the below

Intra DC Communication:
=========================
For Non-NAPT to NAPT Traffic, Tunnel id will be setting with
Router lPortTag which will be carved out per router if it is part of
L3VpnOverVxlan else tunnel-id will be setting with existing router-id.

Change-Id: Idc5e8b1956311541ae7bae255d023c5f3543f9a3
Signed-off-by: karthikeyan <karthikeyan.k@altencalsoftlabs.com>
Signed-off-by: cgowdru <chetan.arakere@altencalsoftlabs.com>
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NaptSwitchHA.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatConstants.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatEvpnUtil.java [new file with mode: 0644]
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnNatManager.java

index 5264cbd3378432f6217e01f724123cbb9d00510f..d17d740620bc2290631073664e0056295bdf3489 100644 (file)
@@ -623,6 +623,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         mdsalManager.syncInstallGroup(groupEntity, 0);
         // Install miss entry pointing to group
         FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
+        if (flowEntity == null) {
+            LOG.error("NAT Service : Flow entity received as NULL. "
+                    + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
+                    + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
+            return;
+        }
         mdsalManager.installFlow(flowEntity);
     }
 
@@ -637,23 +643,23 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
-            dpId, routerName, groupId);
+                dpId, routerName, groupId);
         long routerId = NatUtil.getVpnId(dataBroker, routerName);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
 
         List<ActionInfo> actionsInfo = new ArrayList<>();
-
-        actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerId)));
+        long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
+        actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
         LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
         actionsInfo.add(new ActionGroup(groupId));
         List<InstructionInfo> instructions = new ArrayList<>();
         instructions.add(new InstructionApplyActions(actionsInfo));
         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
-            NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
-            NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+                NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
 
         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
         return flowEntity;
@@ -685,25 +691,32 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}",
             dpnId, routerName);
         FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
+        if (flowEntity == null) {
+            LOG.error("NAT Service : Flow entity received as NULL. "
+                    + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
+                    + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
+                    dpnId, routerName);
+            return;
+        }
         mdsalManager.installFlow(flowEntity);
 
     }
 
     private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
-
-        BigInteger routerId = BigInteger.valueOf(NatUtil.getVpnId(dataBroker, routerName));
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchTunnelId(routerId));
+        long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
+        matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
+        String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
 
         List<InstructionInfo> instructions = new ArrayList<>();
-        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId.longValue()),
-            MetaDataUtil.METADATA_MASK_VRFID));
+        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
+                MetaDataUtil.METADATA_MASK_VRFID));
         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
-        String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
-            NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
-            NwConstants.COOKIE_TS_TABLE, matches, instructions);
+                NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
+                instructions);
         return flowEntity;
     }
 
@@ -1562,6 +1575,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
         LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
+        NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
     }
 
     public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
@@ -1581,9 +1596,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
         //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
         // traffic which comes from the VMs of the non NAPT switches)
-        String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
+        long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
+        String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
         FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
-
         LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
             NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
         mdsalManager.removeFlow(tsNatFlowEntity);
@@ -2263,10 +2278,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 }
                 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
                 SessionAddress externalAddress =
-                    naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
+                        naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
                 long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
                 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
-                    routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
+                        routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
                 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
                         routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
             }
index 9d2ed285ef9ad654064063ce6ee023cb1756b329..c90bd7227b40a9dbc5cc16b16e4a55318352d28b 100644 (file)
@@ -159,15 +159,13 @@ public class NaptSwitchHA {
             LOG.error("Invalid routerId returned for routerName {}", routerName);
             return;
         }
-
         //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
         String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
         FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
 
         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
-            NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
+                NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
         mdsalManager.removeFlow(tsNatFlowEntity);
-
         //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
         String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
             NwConstants.OUTBOUND_NAPT_TABLE, routerId);
@@ -565,18 +563,18 @@ public class NaptSwitchHA {
                     //Install the flow in newNaptSwitch Outbound NAPT table.
                     try {
                         NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
-                                vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
+                            vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto, extGwMacAddress);
                     } catch (Exception ex) {
                         LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} "
-                                        + "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {} - {}",
-                                routerId, newNaptSwitch, internalIpAddress,
-                                intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
+                            + "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {} - {}",
+                            routerId, newNaptSwitch, internalIpAddress,
+                            intportnum, proto, externalAddress, extportNumber, bgpVpnId, ex);
                         return false;
                     }
                     LOG.debug("Successfully installed a flow in Primary switch {} Outbound NAPT table for router {} "
-                                    + "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
-                            newNaptSwitch, routerId, internalIpAddress,
-                            intportnum, proto, externalAddress, extportNumber, bgpVpnId);
+                            + "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}",
+                        newNaptSwitch, routerId, internalIpAddress,
+                        intportnum, proto, externalAddress, extportNumber, bgpVpnId);
                 } else {
                     LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
                         newNaptSwitch, oldNaptSwitch);
@@ -744,16 +742,16 @@ public class NaptSwitchHA {
 
         if (addordel == NatConstants.ADD_FLOW) {
             List<ActionInfo> actionsInfo = new ArrayList<>();
-
-            actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerVpnId)));
+            long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerVpnId);
+            actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
             LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
             actionsInfo.add(new ActionGroup(groupId));
             List<InstructionInfo> instructions = new ArrayList<>();
             instructions.add(new InstructionApplyActions(actionsInfo));
 
             flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
-                NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
-                NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+                    NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
+                    NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
         } else {
             flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
index b239f3b94a13d8a87292760d9602f83254add540..8042d8340ba4a3175645011e7498c0d64fc2de75 100644 (file)
@@ -32,6 +32,7 @@ public class NatConstants {
     public static final long SNAT_ID_HIGH_VALUE = 225000L;
     public static final int DEFAULT_TS_FLOW_PRIORITY = 10;
     public static final short DEFAULT_PREFIX = 32;
+    public static final long DEFAULT_L3VNI_VALUE = 0;
 
     // Flow Actions
     public static final int ADD_FLOW = 0;
diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatEvpnUtil.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatEvpnUtil.java
new file mode 100644 (file)
index 0000000..678bb7f
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.natservice.internal;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NatEvpnUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NatEvpnUtil.class);
+
+    static long getLPortTagForRouter(String routerIdKey, IdManagerService idManager) {
+        AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+                .setPoolName(IfmConstants.IFM_IDPOOL_NAME).setIdKey(routerIdKey)
+                .build();
+        try {
+            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+            RpcResult<AllocateIdOutput> rpcResult = result.get();
+            return rpcResult.getResult().getIdValue();
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            LOG.error("NAT Service : ID manager failed while allocating lport_tag for router {}."
+                    + "Exception {}", routerIdKey, e);
+        }
+        return 0;
+    }
+
+    public static void releaseLPortTagForRouter(DataBroker dataBroker, IdManagerService idManager, String routerName) {
+
+        String rd = NatUtil.getVpnRd(dataBroker, routerName);
+        long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
+        if (!NatEvpnUtil.isL3VpnOverVxLan(l3Vni)) {
+            return;
+        }
+        ReleaseIdInput getIdInput = new ReleaseIdInputBuilder()
+                .setPoolName(IfmConstants.IFM_IDPOOL_NAME).setIdKey(routerName)
+                .build();
+        try {
+            Future<RpcResult<Void>> result = idManager.releaseId(getIdInput);
+            RpcResult<Void> rpcResult = result.get();
+            if (!rpcResult.isSuccessful()) {
+                LOG.error("NAT Service : ID manager failed while releasing allocated lport_tag for router {}."
+                        + "Exception {} ", routerName, rpcResult.getErrors());
+                return;
+            }
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            LOG.error("NAT Service : ID manager failed while releasing allocated lport_tag for router {}."
+                    + "Exception {}", routerName, e);
+        }
+    }
+
+    public static long getTunnelIdForRouter(IdManagerService idManager, DataBroker dataBroker, String routerName,
+                                            long routerId) {
+        /* Only if the router is part of an L3VPN-Over-VXLAN, Router_lPort_Tag which will be carved out per router
+         from 'interfaces' POOL and used as tunnel_id. Otherwise we will continue to use router-id as the tunnel-id
+         in the following Flows.
+
+         1) PSNAT_TABLE (on Non-NAPT) -> Send to Remote Group
+         2) INTERNAL_TUNNEL_TABLE (on NAPT) -> Send to OUTBOUND_NAPT_TABLE */
+        String rd = NatUtil.getVpnRd(dataBroker, routerName);
+        long l3Vni = getL3Vni(dataBroker, rd);
+        if (isL3VpnOverVxLan(l3Vni)) {
+            long routerLportTag = getLPortTagForRouter(routerName, idManager);
+            if (routerLportTag != 0) {
+                LOG.trace("NAT Service : Successfully allocated Router_lPort_Tag = {} from ID Manager for "
+                        + "Router ID = {}", routerLportTag, routerId);
+                return routerLportTag;
+            } else {
+                LOG.warn("NAT Service : Failed to allocate Router_lPort_Tag from ID Manager for Router ID = {} "
+                        + "Continue to use router-id as tunnel-id", routerId);
+                return routerId;
+            }
+        }
+        return routerId;
+    }
+
+    static long getL3Vni(DataBroker broker, String rd) {
+        VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpData(broker, rd);
+        if (vpnInstanceOpDataEntry != null && vpnInstanceOpDataEntry.getL3vni() != null) {
+            return vpnInstanceOpDataEntry.getL3vni();
+        }
+        return NatConstants.DEFAULT_L3VNI_VALUE;
+    }
+
+    private static VpnInstanceOpDataEntry getVpnInstanceOpData(DataBroker broker, String rd) {
+        InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(rd);
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (vpnInstanceOpData.isPresent()) {
+            return vpnInstanceOpData.get();
+        }
+        return null;
+    }
+
+    private static boolean isL3VpnOverVxLan(Long l3Vni) {
+        return (l3Vni != null && l3Vni != 0);
+    }
+}
index 452247feafbe509efdcae21fb47b314a097dd89b..1bc68e938b40a58d37da447d13e18a722e64d8c0 100644 (file)
@@ -312,7 +312,7 @@ public class NeutronvpnNatManager implements AutoCloseable {
             }
             rtrList.add(routerId);
             builder.setRouterIds(rtrList);
-            if (providerNwType != ProviderTypes.GRE) {
+            if (NeutronvpnUtils.isFlatOrVlanNetwork(input)) {
                 builder.setVpnid(extNetId);
             }