Rate limiting for controller based SNAT punts 87/72087/9
authorRavindra Thakur <ravindra.nath.thakur@ericsson.com>
Fri, 18 May 2018 09:55:28 +0000 (15:25 +0530)
committerSam Hague <shague@redhat.com>
Mon, 11 Jun 2018 20:34:18 +0000 (20:34 +0000)
spec link:
http://docs.opendaylight.org/projects/netvirt/en/latest/specs/fluorine/controller-punt-protection.html

Issue: NETVIRT-1218

Depends-On: https://git.opendaylight.org/gerrit/#/c/72006/
Depends-On: https://git.opendaylight.org/gerrit/#/c/72007/

Change-Id: Idc6e88ae8279f58eae525af95fab6f312b4d2586
Signed-off-by: Ravindra Thakur <ravindra.nath.thakur@ericsson.com>
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NaptSwitchHA.java
natservice/impl/src/main/resources/initial/netvirt-natservice-config.xml

index bd83938d187f2f1bcc8ede6363101f7049690017..4dea36762a149ef5d6c1ef7f4b35c3b91534749d 100644 (file)
@@ -17,6 +17,7 @@ import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -48,8 +49,13 @@ 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.NwConstants.NxmOfFieldType;
 import org.opendaylight.genius.mdsalutil.UpgradeState;
+import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
+import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
+import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromField;
+import org.opendaylight.genius.mdsalutil.actions.ActionLearn.MatchFromValue;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
@@ -60,6 +66,7 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
@@ -176,6 +183,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     private final JobCoordinator coordinator;
     private final UpgradeState upgradeState;
     private final IInterfaceManager interfaceManager;
+    private final int snatPuntTimeout;
 
     @Inject
     public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
@@ -226,8 +234,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         this.interfaceManager = interfaceManager;
         if (config != null) {
             this.natMode = config.getNatMode();
+            this.snatPuntTimeout = config.getSnatPuntTimeout().intValue();
         } else {
             this.natMode = NatMode.Controller;
+            this.snatPuntTimeout = 0;
         }
     }
 
@@ -595,9 +605,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
+    public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
-                .FLOWID_SEPARATOR + routerID;
+                .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
     }
 
     private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
@@ -610,21 +620,75 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             BigInteger.valueOf(routerId));
     }
 
-    protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
+    private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
+        long l4SrcPortField;
+        long l4DstPortField;
+        int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
+
+        if (protocol == NwConstants.IP_PROT_TCP) {
+            l4SrcPortField = NxmOfFieldType.NXM_OF_TCP_SRC.getType();
+            l4DstPortField = NxmOfFieldType.NXM_OF_TCP_DST.getType();
+        } else {
+            l4SrcPortField = NxmOfFieldType.NXM_OF_UDP_SRC.getType();
+            l4DstPortField = NxmOfFieldType.NXM_OF_UDP_DST.getType();
+        }
+        List<ActionLearn.FlowMod> flowMods = Arrays.asList(
+                new MatchFromValue(NwConstants.ETHTYPE_IPV4, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
+                        NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
+                new MatchFromValue(protocol, NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
+                        NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
+                new MatchFromField(NxmOfFieldType.NXM_OF_IP_SRC.getType(), NxmOfFieldType.NXM_OF_IP_SRC.getType(),
+                        NxmOfFieldType.NXM_OF_IP_SRC.getFlowModHeaderLenInt()),
+                new MatchFromField(NxmOfFieldType.NXM_OF_IP_DST.getType(), NxmOfFieldType.NXM_OF_IP_DST.getType(),
+                        NxmOfFieldType.NXM_OF_IP_DST.getFlowModHeaderLenInt()),
+                new MatchFromField(l4SrcPortField, l4SrcPortField, l4portFieldLen),
+                new MatchFromField(l4DstPortField, l4DstPortField, l4portFieldLen),
+                new MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
+                        MetaDataUtil.METADATA_VPN_ID_OFFSET,
+                        NxmOfFieldType.OXM_OF_METADATA.getType(), MetaDataUtil.METADATA_VPN_ID_OFFSET,
+                        MetaDataUtil.METADATA_VPN_ID_BITLEN));
+
+        return new ActionLearn(0, hardTimeout, 7, cookie, 0,
+                NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
+    }
+
+    private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(MatchEthernetType.IPV4);
+        matches.add(MatchIpProtocol.ICMP);
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
+
+        List<ActionInfo> actionInfos = new ArrayList<>();
+        actionInfos.add(new ActionDrop());
+
+        List<InstructionInfo> instructions = new ArrayList<>();
+        instructions.add(new InstructionApplyActions(actionInfos));
+
+        String flowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
+                NwConstants.IP_PROT_ICMP);
+        FlowEntity flow = MDSALUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
+                NwConstants.TABLE_MISS_PRIORITY, "icmp drop flow", 0, 0,
+                NwConstants.COOKIE_OUTBOUND_NAPT_TABLE, matches, instructions);
+        return flow;
+    }
+
+    protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
         LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
+        BigInteger cookie = getCookieOutboundFlow(routerId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
+        matches.add(new MatchIpProtocol((short)protocol));
         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
 
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
         actionsInfos.add(new ActionPuntToController());
+        if (snatPuntTimeout != 0) {
+            actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
+        }
         instructions.add(new InstructionApplyActions(actionsInfos));
-        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
-            MetaDataUtil.METADATA_MASK_VRFID));
 
-        String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
-        BigInteger cookie = getCookieOutboundFlow(routerId);
+        String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
             5, flowRef, 0, 0,
             cookie, matches, instructions);
@@ -634,9 +698,17 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     public void createOutboundTblEntry(BigInteger dpnId, long routerId, WriteTransaction writeFlowInvTx) {
         LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
-        FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
-        LOG.debug("createOutboundTblEntry : Installing flow {}", flowEntity);
-        mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
+        FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
+        LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
+        mdsalManager.addFlowToTx(tcpflowEntity, writeFlowInvTx);
+
+        FlowEntity udpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_UDP);
+        LOG.debug("createOutboundTblEntry : Installing udp flow {}", udpflowEntity);
+        mdsalManager.addFlowToTx(udpflowEntity, writeFlowInvTx);
+
+        FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, routerId);
+        LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
+        mdsalManager.addFlowToTx(icmpDropFlow, writeFlowInvTx);
     }
 
     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
@@ -1903,13 +1975,26 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
 
         //Remove the Outbound flow entry which forwards the packet to FIB Table
-        String outboundNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
-        FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
-            outboundNatFlowRef);
-
         LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
                 + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
-        mdsalManager.removeFlowToTx(outboundNatFlowEntity, removeFlowInvTx);
+
+        String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
+                NwConstants.IP_PROT_TCP);
+        FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
+            outboundTcpNatFlowRef);
+        mdsalManager.removeFlowToTx(outboundTcpNatFlowEntity, removeFlowInvTx);
+
+        String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
+                NwConstants.IP_PROT_UDP);
+        FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
+                outboundUdpNatFlowRef);
+        mdsalManager.removeFlowToTx(outboundUdpNatFlowEntity, removeFlowInvTx);
+
+        String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
+                NwConstants.IP_PROT_ICMP);
+        FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
+                icmpDropFlowRef);
+        mdsalManager.removeFlowToTx(icmpDropFlowEntity, removeFlowInvTx);
 
         removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, removeFlowInvTx);
         //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
@@ -2779,27 +2864,40 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                                  WriteTransaction writeFlowInvTx) {
         LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
             dpnId, routerId, changedVpnId);
-        FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
-        LOG.debug("createOutboundTblEntryWithBgpVpn : Installing flow {}", flowEntity);
-        mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
+        FlowEntity tcpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
+                NwConstants.IP_PROT_TCP);
+        LOG.debug("createOutboundTblEntryWithBgpVpn : Installing tcp flow {}", tcpFlowEntity);
+        mdsalManager.addFlowToTx(tcpFlowEntity, writeFlowInvTx);
+
+        FlowEntity udpFlowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId,
+                NwConstants.IP_PROT_UDP);
+        LOG.debug("createOutboundTblEntryWithBgpVpn : Installing udp flow {}", udpFlowEntity);
+        mdsalManager.addFlowToTx(udpFlowEntity, writeFlowInvTx);
+
+        FlowEntity icmpDropFlow = buildIcmpDropFlow(dpnId, routerId, changedVpnId);
+        LOG.debug("createOutboundTblEntry: Installing icmp drop flow {}", icmpDropFlow);
+        mdsalManager.addFlowToTx(icmpDropFlow, writeFlowInvTx);
     }
 
-    protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
+    protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
+                                                           long changedVpnId, int protocol) {
         LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
             dpId, routerId, changedVpnId);
+        BigInteger cookie = getCookieOutboundFlow(routerId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
+        matches.add(new MatchIpProtocol((short)protocol));
         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
 
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
         actionsInfos.add(new ActionPuntToController());
+        if (snatPuntTimeout != 0) {
+            actionsInfos.add(getLearnActionForPunt(protocol, snatPuntTimeout, cookie));
+        }
         instructions.add(new InstructionApplyActions(actionsInfos));
-        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
-            MetaDataUtil.METADATA_MASK_VRFID));
 
-        String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
-        BigInteger cookie = getCookieOutboundFlow(routerId);
+        String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, protocol);
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
             flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
         LOG.debug("createOutboundTblEntryWithBgpVpn : returning flowEntity {}", flowEntity);
index 519e99c26a53d15c63959fe5e0bb8956091d94ea..5a484203b2a9369f53a80d703043539b38656513 100644 (file)
@@ -213,13 +213,26 @@ public class NaptSwitchHA {
             NatUtil.removePreDnatToSnatTableEntry(mdsalManager, naptSwitch, removeFlowInvTx);
         }
         //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
-        String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
-            NwConstants.OUTBOUND_NAPT_TABLE, routerId);
-        FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
-            NwConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
-            NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
-        mdsalManager.removeFlowToTx(outboundNatFlowEntity, removeFlowInvTx);
+                NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
+
+        String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
+            NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
+        FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
+            NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
+        mdsalManager.removeFlowToTx(outboundTcpNatFlowEntity, removeFlowInvTx);
+
+        String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
+                NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
+        FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
+                NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
+        mdsalManager.removeFlowToTx(outboundUdpNatFlowEntity, removeFlowInvTx);
+
+        String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
+                NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
+        FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
+                icmpDropFlowRef);
+        mdsalManager.removeFlowToTx(icmpDropFlowEntity, removeFlowInvTx);
 
         //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
         // External Subnet Vpn Id.
index a18f35573a1f45824de5db8916c83c932bd25af3..d1bdb663f16c34b1fa7067813d1c7830141b6288 100644 (file)
@@ -1,3 +1,4 @@
 <natservice-config xmlns="urn:opendaylight:netvirt:natservice:config">
   <nat-mode>controller</nat-mode>
-</natservice-config>
\ No newline at end of file
+  <snat-punt-timeout>5</snat-punt-timeout>
+</natservice-config>