Ethernet VPN (EVPN_RT5) Enhancement to SNAT 38/51338/45
authorkarthikeyan <karthikeyan.k@altencalsoftlabs.com>
Thu, 2 Feb 2017 10:56:51 +0000 (16:26 +0530)
committerVivekanandan Narasimhan <n.vivekanandan@ericsson.com>
Tue, 21 Mar 2017 09:46:47 +0000 (09:46 +0000)
This code review (2nd Review) is part of EVPN_RT5 enhancement to NAT Feature.

This code changes is responsible for below table flow creation and
removal.

1) Install the flow 36->44 (FIP VM on DPN1 is responding back to external fixed IP on DPN2)
   {DNAT to SNAT traffic on different Hypervisor}

2) Install the flow 19->44 (FIP VM on DPN1 is responding back to external fixed IP on DPN1 itself)
   {DNAT to SNAT traffic on Same Hypervisor}

3) Install the flow 25->44 (If there is no FIP Match on table 25 (PDNAT_TABLE) then default flow to INBOUND_NAPT_TABLE)

Change-Id: Ibb210891fe5dd8d6e18527535a7510dde0eb0273
Signed-off-by: karthikeyan <karthikeyan.k@altencalsoftlabs.com>
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnSnatFlowProgrammer.java [new file with mode: 0644]
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/NatConstants.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatEvpnUtil.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/RouterDpnChangeListener.java
vpnservice/natservice/natservice-impl/src/main/resources/org/opendaylight/blueprint/natservice.xml

diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnSnatFlowProgrammer.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnSnatFlowProgrammer.java
new file mode 100644 (file)
index 0000000..ebb9811
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * 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 java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
+import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.fibmanager.api.IFibManager;
+import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EvpnSnatFlowProgrammer {
+    private static final Logger LOG = LoggerFactory.getLogger(EvpnSnatFlowProgrammer.class);
+    private final DataBroker dataBroker;
+    private final IMdsalApiManager mdsalManager;
+    private final IBgpManager bgpManager;
+    private final IFibManager fibManager;
+    private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+
+    public EvpnSnatFlowProgrammer(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
+                           final IBgpManager bgpManager,
+                           final IFibManager fibManager) {
+        this.dataBroker = dataBroker;
+        this.mdsalManager = mdsalManager;
+        this.bgpManager = bgpManager;
+        this.fibManager = fibManager;
+    }
+
+    public void evpnAdvToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId,
+                                                    final String externalIp, final String vpnName, final String rd,
+                                                    final String nextHopIp, final WriteTransaction writeTx,
+                                                    final long routerId) {
+     /*
+      * 1) Install the flow INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44)
+      *    (FIP VM on DPN1 is responding back to external fixed IP on DPN2) {DNAT to SNAT traffic on
+      *     different Hypervisor}
+      *
+      * 2) Install the flow L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44)
+      *    (FIP VM on DPN1 is responding back to external fixed IP on DPN1 itself){DNAT to SNAT traffic on
+      *     Same Hypervisor}
+      *
+      * 3) Install the flow PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44)
+      *    (If there is no FIP Match on table 25 (PDNAT_TABLE) then default flow to INBOUND_NAPT_TABLE (table=44))
+      *
+      */
+        LOG.info("NAT Service : Handling SNAT Reverse Traffic for External Network {} ", externalIp);
+        // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
+        String gwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+        if (gwMacAddress == null) {
+            LOG.error("NAT Service : Unable to Retrieve External Gateway MAC address from Router ID {}", routerId);
+            return;
+        }
+        //get l3Vni value for external VPN
+        long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
+        if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
+            LOG.error("NAT Service : Unable to retrieve L3VNI value for External IP {}", externalIp);
+            return;
+        }
+        /* As of now neither SNAT nor DNAT will use macaddress while advertising to FIB and BGP instead
+         * use only gwMacAddress. Hence default value of macAddress is null
+         */
+        //Inform to BGP
+        NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd, externalIp,
+                nextHopIp, l3Vni, null /*InterfaceName*/, gwMacAddress, writeTx, RouteOrigin.STATIC, dpnId);
+
+        List<Instruction> customInstructions = new ArrayList<>();
+        customInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
+        /* Install the flow INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44)
+         * (SNAT to DNAT reverse Traffic: If traffic is Initiated from NAPT to FIP VM on different Hypervisor)
+         */
+        makeTunnelTableEntry(dpnId, l3Vni, customInstructions, tableId);
+        /* Install the flow L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44)
+         * (SNAT reverse traffic: If the traffic is Initiated from DC-GW to VM (SNAT Reverse traffic))
+         */
+        long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+        if (vpnId == NatConstants.INVALID_ID) {
+            LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
+        }
+        NatEvpnUtil.makeL3GwMacTableEntry(dpnId, vpnId, gwMacAddress, customInstructions, mdsalManager);
+
+        /* Install the flow PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44)
+         * If there is no FIP Match on table 25 (PDNAT_TABLE)
+         */
+        List<Instruction> preDnatToSnatInstructions = new ArrayList<>();
+        preDnatToSnatInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
+        makePreDnatToSnatTableEntry(dpnId, preDnatToSnatInstructions, tableId);
+
+    }
+
+    public void evpnDelFibTsAndReverseTraffic(final BigInteger dpnId, final long routerId, final String externalIp,
+                                              final String vpnName) {
+     /*
+      * 1) Remove the flow INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44)
+      *    (FIP VM on DPN1 is responding back to external fixed IP on DPN2) {DNAT to SNAT traffic on
+      *     different Hypervisor}
+      *
+      * 2) Remove the flow L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44)
+      *    (FIP VM on DPN1 is responding back to external fixed IP on DPN1 itself){DNAT to SNAT traffic on
+      *     Same Hypervisor}
+      *
+      * 3) Remove the flow PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44)
+      *    (If there is no FIP Match on table 25 (PDNAT_TABLE) then default flow to INBOUND_NAPT_TABLE (table=44))
+      *
+      */
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        if (rd == null) {
+            LOG.error("NAT Service : Could not retrieve RD value from VPN Name {}  ", vpnName);
+            return;
+        }
+        long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
+        if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
+            LOG.error("NAT Service : Could not retrieve L3VNI value from RD {} in ", rd);
+            return;
+        }
+        String gwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+        if (gwMacAddress == null) {
+            LOG.error("NAT Service : Unable to Get External Gateway MAC address for External Router ID {} ", routerId);
+            return;
+        }
+        long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+        if (vpnId == NatConstants.INVALID_ID) {
+            LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
+        }
+        //remove INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44) flow
+        removeTunnelTableEntry(dpnId, l3Vni);
+        //remove L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44) flow
+        removePreDnatToSnatTableEntry(dpnId);
+        //remove PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44) flow
+        NatEvpnUtil.removeL3GwMacTableEntry(dpnId, vpnId, gwMacAddress, mdsalManager);
+    }
+
+    private String getFlowRefPreDnatToSnat(BigInteger dpnId, short tableId, String uniqueId) {
+        return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
+                + NwConstants.FLOWID_SEPARATOR + uniqueId;
+    }
+
+    public void makePreDnatToSnatTableEntry(BigInteger naptDpnId, List<Instruction> preDnatToSnatInstructions,
+                                            short tableId) {
+        LOG.debug("NAT Service : Create Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ", NwConstants.PDNAT_TABLE,
+                tableId, naptDpnId);
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(MatchEthernetType.IPV4);
+        String flowRef = getFlowRefPreDnatToSnat(naptDpnId, NwConstants.PDNAT_TABLE, "PreDNATToSNAT");
+        Flow preDnatToSnatTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.PDNAT_TABLE,flowRef,
+                5, flowRef, 0, 0,  NwConstants.COOKIE_DNAT_TABLE,
+                matches, preDnatToSnatInstructions);
+
+        mdsalManager.installFlow(naptDpnId, preDnatToSnatTableFlowEntity);
+        LOG.debug("NAT Service : Successfully installed Pre-DNAT flow {} on NAPT DpnId {} ",
+                preDnatToSnatTableFlowEntity,  naptDpnId);
+    }
+
+    public void removePreDnatToSnatTableEntry(BigInteger naptDpnId) {
+        LOG.debug("NAT Service : Remove Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ", NwConstants.PDNAT_TABLE,
+                NwConstants.INBOUND_NAPT_TABLE, naptDpnId);
+        String flowRef = getFlowRefPreDnatToSnat(naptDpnId, NwConstants.PDNAT_TABLE, "PreDNATToSNAT");
+        Flow preDnatToSnatTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.PDNAT_TABLE,flowRef,
+                5, flowRef, 0, 0,  NwConstants.COOKIE_DNAT_TABLE, null, null);
+        mdsalManager.removeFlow(naptDpnId, preDnatToSnatTableFlowEntity);
+        LOG.debug("NAT Service : Successfully removed Pre-DNAT flow {} on NAPT DpnId = {}",
+                preDnatToSnatTableFlowEntity, naptDpnId);
+    }
+
+    public void makeTunnelTableEntry(BigInteger dpnId, long l3Vni, List<Instruction> customInstructions,
+                                     short tableId) {
+        LOG.debug("NAT Service : Create terminating service table {} --> table {} flow on NAPT DpnId {} with l3Vni {} "
+                + "as matching parameter", NwConstants.INTERNAL_TUNNEL_TABLE, tableId, dpnId,
+                l3Vni);
+        List<MatchInfo> mkMatches = new ArrayList<>();
+        mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
+
+        Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                NatEvpnUtil.getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, l3Vni, NatConstants.SNAT_FLOW_NAME), 5,
+                String.format("%s:%d", "TST Flow Entry ", l3Vni),
+                0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(l3Vni)), mkMatches, customInstructions);
+        mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
+        LOG.debug("NAT Service : Successfully installed terminating service table flow {} on DpnId {}",
+                terminatingServiceTableFlowEntity, dpnId);
+    }
+
+    public void removeTunnelTableEntry(BigInteger dpnId, long l3Vni) {
+        LOG.debug("NAT Service : Remove terminating service table {} --> table {} flow on NAPT DpnId {} with l3Vni {} "
+                        + "as matching parameter", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.INBOUND_NAPT_TABLE,
+                dpnId, l3Vni);
+        List<MatchInfo> mkMatches = new ArrayList<>();
+        // Matching metadata
+        mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                NatEvpnUtil.getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, l3Vni, NatConstants.SNAT_FLOW_NAME),
+                5, String.format("%s:%d", "TST Flow Entry ", l3Vni), 0, 0,
+                COOKIE_TUNNEL.add(BigInteger.valueOf(l3Vni)), mkMatches, null);
+        mdsalManager.removeFlow(dpnId, flowEntity);
+        LOG.debug("NAT Service : Successfully removed terminating service table flow {} on DpnId {}", flowEntity,
+                dpnId);
+    }
+}
index d17d740620bc2290631073664e0056295bdf3489..2f841c3cb52b003047400c65b559790038a6b0b8 100644 (file)
@@ -86,6 +86,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
@@ -140,6 +141,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     private final NaptPacketInHandler naptPacketInHandler;
     private final IFibManager fibManager;
     private final IVpnManager vpnManager;
+    private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
     private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
     static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
 
@@ -156,7 +158,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                    final NaptEventHandler naptEventHandler,
                                    final NaptPacketInHandler naptPacketInHandler,
                                    final IFibManager fibManager,
-                                   final IVpnManager vpnManager) {
+                                   final IVpnManager vpnManager,
+                                   final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer) {
         super(Routers.class, ExternalRoutersListener.class);
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalManager;
@@ -173,6 +176,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         this.naptPacketInHandler = naptPacketInHandler;
         this.fibManager = fibManager;
         this.vpnManager = vpnManager;
+        this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
     }
 
     @Override
@@ -892,7 +896,28 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                                 final IBgpManager bgpManager, final DataBroker dataBroker,
                                                 final Logger log) {
         LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} "
-            + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
+                + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
+        String routerName = NatUtil.getRouterName(dataBroker, routerId);
+        if (routerName == null) {
+            LOG.error("NAT Service : Unable to retrieve the Router Name from Router ID {}", routerId);
+            return;
+        }
+        String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        if (rd == null || rd.isEmpty()) {
+            LOG.error("NAT Service : Unable to get RD for VPN Name {}", vpnName);
+            return;
+        }
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
+        if (extNwProvType == null) {
+            return;
+        }
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+            evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
+                    nextHopIp, writeTx, routerId);
+            return;
+        }
         //Generate VPN label for the external IP
         GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
             .setIpPrefix(externalIp).build();
@@ -935,13 +960,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                             }
                         } else {
                             LOG.error("NAT Service : Failed to write label {} for externalIp {} for "
-                                    + "routerId {} in DS",
-                                label, externalIp, routerId);
+                                    + "routerId {} in DS", label, externalIp, routerId);
                         }
-
                         //Inform BGP
-                        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
-                        String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
                         NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
                             externalIp, nextHopIp, label, log, RouteOrigin.STATIC, dpnId);
 
@@ -1893,8 +1914,23 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp,
                                              final String vpnName, long tempLabel) {
-        LOG.debug("Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
-
+        LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
+        String routerName = NatUtil.getRouterName(dataBroker,routerId);
+        if (routerName == null) {
+            LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
+            return;
+        }
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
+        if (extNwProvType == null) {
+            return;
+        }
+        /*  Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
+         * external network provided type is VxLAN
+         */
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
+            return;
+        }
         if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
             LOG.error("NAT Service : Label not found for externalIp {} with router id {}", extIp, routerId);
             return;
@@ -1921,8 +1957,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     } else {
                         String errMsg =
                             String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s "
-                                    + "Failed - %s",
-                                dpnId, externalIp, result.getErrors());
+                                    + "Failed - %s", dpnId, externalIp, result.getErrors());
                         LOG.error(errMsg);
                         return Futures.immediateFailedFuture(new RuntimeException(errMsg));
                     }
@@ -1949,7 +1984,23 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     }
 
     private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
-        LOG.debug("Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
+        LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
+        String routerName = NatUtil.getRouterName(dataBroker,routerId);
+        if (routerName == null) {
+            LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
+            return;
+        }
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
+        if (extNwProvType == null) {
+            return;
+        }
+        /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
+         *  external network provided type is VxLAN
+         */
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
+            return;
+        }
         //Get IPMaps from the DB for the router ID
         List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
         if (dbIpMaps == null || dbIpMaps.isEmpty()) {
index 5ec827892e82d113e304d43ff63f6c90f907c6c0..cf8a7ab47c5ac3dee71963ad10b4323870894f47 100644 (file)
@@ -36,6 +36,8 @@ public class NatConstants {
     public static final int DEFAULT_TS_FLOW_PRIORITY = 10;
     public static final short DEFAULT_PREFIX = 32;
     public static final long DEFAULT_L3VNI_VALUE = 0;
+    public static final int DEFAULT_LABEL_VALUE = 0;
+    public static final String DNAT_FLOW_NAME = "DNAT";
 
     // Flow Actions
     public static final int ADD_FLOW = 0;
index 678bb7f4a2caa73ddaf42f11aa18700554a74b54..eeaa3cbb3d2041b63c1caa5a714947560255ca5a 100644 (file)
@@ -9,19 +9,41 @@
 package org.opendaylight.netvirt.natservice.internal;
 
 import com.google.common.base.Optional;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 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.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.fibmanager.api.IFibManager;
+import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 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.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -115,4 +137,94 @@ public class NatEvpnUtil {
     private static boolean isL3VpnOverVxLan(Long l3Vni) {
         return (l3Vni != null && l3Vni != 0);
     }
+
+    static ProviderTypes getExtNwProvTypeFromRouterName(DataBroker dataBroker, String routerName) {
+        ProviderTypes extNwProviderType = null;
+        Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
+        if (externalNetworkId == null) {
+            LOG.error("NAT Service : Could not retrieve external network UUID for router {}", routerName);
+            return extNwProviderType;
+        }
+        extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
+        if (extNwProviderType == null) {
+            LOG.error("NAT Service : Could not retrieve provider type for external network {} ", externalNetworkId);
+            return extNwProviderType;
+        }
+        return extNwProviderType;
+    }
+
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public static void addRoutesForVxLanProvType(DataBroker broker,
+                                                 IBgpManager bgpManager,
+                                                 IFibManager fibManager,
+                                                 String vpnName,
+                                                 String rd,
+                                                 String prefix,
+                                                 String nextHopIp,
+                                                 long l3Vni,
+                                                 String interfaceName,
+                                                 String gwMacAddress,
+                                                 WriteTransaction writeTx,
+                                                 RouteOrigin origin, BigInteger dpId) {
+        try {
+            LOG.info("NAT Service : ADD: Adding Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix, nextHopIp,
+                    l3Vni);
+            if (nextHopIp == null) {
+                LOG.error("NAT Service : addPrefix failed since nextHopIp cannot be null for prefix {}", prefix);
+                return;
+            }
+            NatUtil.addPrefixToInterface(broker, NatUtil.getVpnId(broker, vpnName), interfaceName, prefix, dpId,
+                    /*isNatPrefix*/ true);
+
+            fibManager.addOrUpdateFibEntry(broker, rd, null /*macAddress*/, prefix,
+                    Collections.singletonList(nextHopIp), VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE,
+                    l3Vni, gwMacAddress, origin, writeTx);
+            /* Publish to Bgp only if its an INTERNET VPN */
+            if ((rd != null) && (!rd.equalsIgnoreCase(vpnName))) {
+                bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, Collections.singletonList(nextHopIp),
+                        VrfEntry.EncapType.Vxlan, NatConstants.DEFAULT_LABEL_VALUE, l3Vni, gwMacAddress);
+            }
+            LOG.info("NAT Service : ADD: Added Fib entry rd {} prefix {} nextHop {} l3Vni {}", rd, prefix,
+                        nextHopIp, l3Vni);
+        } catch (Exception e) {
+            LOG.error("NAT Service : Exception {} in add routes for prefix {}", e, prefix);
+        }
+    }
+
+    static void makeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, String macAddress,
+                                      List<Instruction> customInstructions, IMdsalApiManager mdsalManager) {
+        List<MatchInfo> matchInfo = new ArrayList<>();
+        matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matchInfo.add(new MatchEthernetDestination(new MacAddress(macAddress)));
+        LOG.debug("NAT Service : Create flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
+                + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
+        // Install the flow entry in L3_GW_MAC_TABLE
+        String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
+        Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
+                flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, customInstructions);
+
+        mdsalManager.installFlow(dpnId, l3GwMacTableFlowEntity);
+        LOG.debug("NAT Service : Successfully created flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
+    }
+
+    static void removeL3GwMacTableEntry(final BigInteger dpnId, final long vpnId, final String macAddress,
+                                        IMdsalApiManager mdsalManager) {
+        List<MatchInfo> matchInfo = new ArrayList<>();
+        matchInfo.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matchInfo.add(new MatchEthernetSource(new MacAddress(macAddress)));
+        LOG.debug("NAT Service : Remove flow table {} -> table {} for External Vpn Id = {} and MacAddress = {} on "
+                + "DpnId = {}", NwConstants.L3_GW_MAC_TABLE, NwConstants.INBOUND_NAPT_TABLE, vpnId, macAddress, dpnId);
+        // Remove the flow entry in L3_GW_MAC_TABLE
+        String flowRef = NatUtil.getFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, vpnId, macAddress);
+        Flow l3GwMacTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_GW_MAC_TABLE,
+                flowRef, 21, flowRef, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, matchInfo, null);
+
+        mdsalManager.removeFlow(dpnId, l3GwMacTableFlowEntity);
+        LOG.debug("NAT Service : Successfully removed flow entity {} on DPN = {}", l3GwMacTableFlowEntity, dpnId);
+    }
+
+    public static String getFlowRef(BigInteger dpnId, short tableId, long l3Vni, String flowName) {
+        return flowName + NwConstants.FLOWID_SEPARATOR + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
+                .FLOWID_SEPARATOR + l3Vni;
+    }
 }
index ec5b36c8d3256c61a6dce789f6e736ba4351d5be..4ebace8fc8a759a0a2ac359a71b5486c40d1cda2 100644 (file)
@@ -664,7 +664,8 @@ public class NatUtil {
                 LOG.error("NAT Service : addPrefix prefix {} rd {} failed since nextHopIp cannot be null.", prefix, rd);
                 return;
             }
-            addPrefixToInterface(broker, getVpnId(broker, vpnName), prefix, dpId, /*isNatPrefix*/ true);
+            addPrefixToInterface(broker, getVpnId(broker, vpnName), null /*interfaceName*/,prefix, dpId,
+                    /*isNatPrefix*/ true);
             fibManager.addOrUpdateFibEntry(broker, rd, null /*macAddress*/, prefix,
                     Collections.singletonList(nextHopIp), VrfEntry.EncapType.Mplsgre, (int)label, 0 /*l3vni*/,
                     null /*gatewayMacAddress*/, origin, null /*writeTxn*/);
@@ -681,16 +682,15 @@ public class NatUtil {
         }
     }
 
-    static void addPrefixToInterface(DataBroker broker, long vpnId, String ipPrefix, BigInteger dpId,
-            boolean isNatPrefix) {
+    static void addPrefixToInterface(DataBroker broker, long vpnId, String interfaceName, String ipPrefix,
+                                     BigInteger dpId, boolean isNatPrefix) {
         InstanceIdentifier<Prefixes> prefixId = InstanceIdentifier.builder(PrefixToInterface.class)
                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
                         .VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix
                         .to._interface.VpnIdsKey(vpnId))
                 .child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
-
-        Prefixes prefix = new PrefixesBuilder().setDpnId(dpId).setIpAddress(ipPrefix).setNatPrefix(isNatPrefix)
-                .build();
+        Prefixes prefix = new PrefixesBuilder().setDpnId(dpId).setIpAddress(ipPrefix).setVpnInterfaceName(interfaceName)
+                    .setNatPrefix(isNatPrefix).build();
         try {
             SingleTransactionDataBroker.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, prefixId, prefix);
         } catch (TransactionCommitFailedException e) {
index 8284dda1aab53a18160f0b86907c4d5ca7666748..4d1a0fcf48e2affd5a887c3fb62c3e5f127e65c4 100644 (file)
@@ -27,6 +27,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Neu
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalSubnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.SubnetsKey;
@@ -36,8 +37,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class RouterDpnChangeListener
-    extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
-    implements AutoCloseable {
+        extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
+        implements AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
     private ListenerRegistration<DataChangeListener> listenerRegistration;
@@ -298,7 +299,16 @@ public class RouterDpnChangeListener
             return;
         }
         externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-        externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
+        if (extNwProvType == null) {
+            return;
+        }
+        //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            externalIpLabel = null;
+        } else {
+            externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
+        }
         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
             LOG.debug("No naptSwitch is selected for router {}", routerName);
index eff1c3323f2d8bdc63c1cd044482dbdd8a8fd666..24a3cfece674db4c5c5dd96a045b3349053b21d4 100644 (file)
     <argument ref="naptPacketInHandler" />
     <argument ref="fibManager" />
     <argument ref="vpnManager"/>
+    <argument ref="evpnSnatFlowProgrammer"/>
   </bean>
 
   <bean id="externalNetworksChangeListener"
     <argument ref="dataBroker"/>
     <argument ref="neutronvpnManager" />
   </bean>
+
   <service ref="natRpcServiceImpl"
            interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.OdlNatRpcService"/>
+
+  <bean id="evpnSnatFlowProgrammer" class="org.opendaylight.netvirt.natservice.internal.EvpnSnatFlowProgrammer">
+    <argument ref="dataBroker" />
+    <argument ref="mdsalUtils" />
+    <argument ref="bgpManager" />
+    <argument ref="fibManager" />
+  </bean>
 </blueprint>