Rate limit for IPv6 NS punt packets. 85/77185/7
authorSomashekar Byrappa <somashekar.b@altencalsoftlabs.com>
Tue, 23 Oct 2018 06:53:08 +0000 (12:23 +0530)
committerSam Hague <shague@redhat.com>
Mon, 29 Oct 2018 12:18:02 +0000 (12:18 +0000)
+ NS punt controller flow is updated with learn action which adds NS
  drop flow per port for a specific ND target.
+ The drop flow will have higher priority (60) than the punt controller
  flow (50) to make sure subsequent NS packets from the same port and
  for same ND target is dropped till the hard_timeout value (10 secs).
+ The drop flow will match on LPORT tag metadata and ND target to make
  sure it drops NS packets per port and for same ND target.

"cookie=0x4000000, duration=0.100s, table=45, n_packets=0, n_bytes=0,
  hard_timeout=10, priority=60,icmp6,
  metadata=0x60000000000/0xfffff0000000000,icmp_type=135,icmp_code=0,
  nd_target=fe80::f816:3eff:fe45:ad28 actions=drop"

"cookie=0x4000000, duration=219.531s, table=45, n_packets=0, n_bytes=0,
  priority=50,icmp6,metadata=0x138a000000/0xffff000000,icmp_type=135,
  icmp_code=0,nd_target=2001:db8:0:2::1 actions=controller:65535,
  learn(table=45,hard_timeout=10,priority=60,cookie=0x4000000,
  eth_type=0x86dd,nw_proto=58,icmpv6_type=135,nxm_nx_icmpv6_code[],
  oxm_of_metadata[40..59],nxm_nx_nd_target[])"

"cookie=0x4000000, duration=219.531s, table=45, n_packets=1,
  n_bytes=86, priority=50,icmp6,metadata=0x138a000000/0xffff000000,
  icmp_type=135,icmp_code=0,nd_target=fe80::f816:3eff:fe45:ad28
  actions=controller:65535,learn(table=45,hard_timeout=10,priority=60,
  cookie=0x4000000,eth_type=0x86dd,nw_proto=58,icmpv6_type=135,
  nxm_nx_icmpv6_code[],oxm_of_metadata[40..59],nxm_nx_nd_target[])"

Change-Id: If410a56477e5dc4602e78a365faa5a32dc1d241d
Signed-off-by: Somashekar Byrappa <somashekar.b@altencalsoftlabs.com>
ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/utils/Ipv6ServiceConstants.java
ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/utils/Ipv6ServiceUtils.java
ipv6service/impl/src/main/resources/initial/netvirt-ipv6service-config.xml
ipv6service/impl/src/main/yang/ipv6service-config.yang

index 352ca2d724841b85076c9bf38387af34472e52ae..73435fe522ee65947bf78ddaabe83ffde492a1e5 100644 (file)
@@ -26,6 +26,7 @@ public interface Ipv6ServiceConstants {
     String DEVICE_OWNER_COMPUTE_NOVA = "compute:nova";
 
     short RS_PUNT_PROTECTION_FLOW_PRIORITY = 60;
+    short NS_PUNT_PROTECTION_FLOW_PRIORITY = 60;
     short DEFAULT_FLOW_PRIORITY = 50;
     short PUNT_NA_FLOW_PRIORITY = 40;
 
index 0d4e125cce392d449d89c9dc05842d4ad9fbfe28..e424b28637f6a91596b866ba66ac20ad0bc09f0b 100644 (file)
@@ -41,6 +41,7 @@ import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
+import org.opendaylight.genius.mdsalutil.actions.ActionLearn.FlowMod;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
@@ -183,12 +184,12 @@ public class Ipv6ServiceUtils {
         return matches;
     }
 
-    private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, String ndTarget) {
+    private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, Ipv6Address ipv6Address) {
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV6);
         matches.add(MatchIpProtocol.ICMPV6);
         matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue(), (short) 0));
-        matches.add(new MatchIpv6NdTarget(new Ipv6Address(ndTarget)));
+        matches.add(new MatchIpv6NdTarget(ipv6Address));
         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
         return matches;
     }
@@ -209,27 +210,48 @@ public class Ipv6ServiceUtils {
                 .append(flowType).toString();
     }
 
-    public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId,  Long elanTag, Ipv6Address ipv6Address,
+    public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, Long elanTag, Ipv6Address ipv6Address,
             int addOrRemove) {
-        List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(elanTag, ipv6Address.getValue());
-        List<InstructionInfo> instructions = new ArrayList<>();
-        List<ActionInfo> actionsInfos = new ArrayList<>();
-        actionsInfos.add(new ActionPuntToController());
-        instructions.add(new InstructionApplyActions(actionsInfos));
+        String flowId = getIPv6FlowRef(dpId, elanTag, Ipv6Util.getFormattedIpv6Address(ipv6Address));
 
-        String formattedIp = Ipv6Util.getFormattedIpv6Address(ipv6Address);
-        FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, getIPv6FlowRef(dpId, elanTag, formattedIp),
-                Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE,
-                neighborSolicitationMatch, instructions);
         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
             LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
-            mdsalUtil.removeFlow(rsFlowEntity);
+            LoggingFutures
+                    .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+                        mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
+                    }), LOG, "Error while removing flow={}", flowId);
         } else {
-            LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
-            mdsalUtil.installFlow(rsFlowEntity);
+            List<ActionInfo> actionsInfos = new ArrayList<>();
+            actionsInfos.add(new ActionPuntToController());
+
+            int ndPuntTimeout = ipv6serviceConfig.getNeighborDiscoveryPuntTimeout();
+            if (isNdPuntProtectionEnabled(ndPuntTimeout)) {
+                actionsInfos.add(getLearnActionForNsPuntProtection(ndPuntTimeout));
+            }
+            List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
+            List<MatchInfo> nsMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
+            FlowEntity nsFlowEntity =
+                    MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
+                            "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE, nsMatch, instructions);
+
+            LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId={}, elanTag={} ipv6Address={}", dpId, elanTag,
+                    ipv6Address.getValue());
+            LoggingFutures
+                    .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+                        mdsalUtil.addFlow(tx, nsFlowEntity);
+                    }), LOG, "Error while adding flow={}", nsFlowEntity);
         }
     }
 
+    private ActionLearn getLearnActionForNsPuntProtection(int ndPuntTimeout) {
+        List<FlowMod> flowMods = getFlowModsForIpv6PuntProtection(Icmpv6Type.NEIGHBOR_SOLICITATION);
+        flowMods.add(new ActionLearn.MatchFromField(NxmOfFieldType.NXM_NX_ND_TARGET.getType(),
+                NxmOfFieldType.NXM_NX_ND_TARGET.getType(), NxmOfFieldType.NXM_NX_ND_TARGET.getFlowModHeaderLenInt()));
+
+        return new ActionLearn(0, ndPuntTimeout, Ipv6ServiceConstants.NS_PUNT_PROTECTION_FLOW_PRIORITY,
+                NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0, flowMods);
+    }
+
     public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, Long elanTag, int addOrRemove) {
         if (dpId == null || dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
             return;
@@ -267,27 +289,34 @@ public class Ipv6ServiceUtils {
     private ActionLearn getLearnActionForRsPuntProtection(int rdPuntTimeout) {
         return new ActionLearn(0, rdPuntTimeout, Ipv6ServiceConstants.RS_PUNT_PROTECTION_FLOW_PRIORITY,
                 NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0,
-                Arrays.asList(
-                        new ActionLearn.MatchFromValue(NwConstants.ETHTYPE_IPV6,
-                                NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
-                                NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
-                        new ActionLearn.MatchFromValue(IPProtocols.IPV6ICMP.shortValue(),
-                                NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
-                                NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
-                        new ActionLearn.MatchFromValue(Icmpv6Type.ROUTER_SOLICITATION.getValue(),
-                                NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getType(),
-                                NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getFlowModHeaderLenInt()),
-                        new ActionLearn.MatchFromValue((short) 0, NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
-                                NxmOfFieldType.NXM_OF_ICMPv6_CODE.getFlowModHeaderLenInt()),
-                        new ActionLearn.MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
-                                MetaDataUtil.METADATA_LPORT_TAG_OFFSET, NxmOfFieldType.OXM_OF_METADATA.getType(),
-                                MetaDataUtil.METADATA_LPORT_TAG_OFFSET, MetaDataUtil.METADATA_LPORT_TAG_BITLEN)));
+                getFlowModsForIpv6PuntProtection(Icmpv6Type.ROUTER_SOLICITATION));
+    }
+
+    private List<FlowMod> getFlowModsForIpv6PuntProtection(Icmpv6Type icmpv6Type) {
+        return new ArrayList<>(Arrays.asList(
+                new ActionLearn.MatchFromValue(NwConstants.ETHTYPE_IPV6, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
+                        NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
+                new ActionLearn.MatchFromValue(IPProtocols.IPV6ICMP.shortValue(),
+                        NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
+                        NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
+                new ActionLearn.MatchFromValue(icmpv6Type.getValue(), NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getType(),
+                        NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getFlowModHeaderLenInt()),
+                new ActionLearn.MatchFromField(NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
+                        NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
+                        NxmOfFieldType.NXM_OF_ICMPv6_CODE.getFlowModHeaderLenInt()),
+                new ActionLearn.MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
+                        MetaDataUtil.METADATA_LPORT_TAG_OFFSET, NxmOfFieldType.OXM_OF_METADATA.getType(),
+                        MetaDataUtil.METADATA_LPORT_TAG_OFFSET, MetaDataUtil.METADATA_LPORT_TAG_BITLEN)));
     }
 
     private boolean isRdPuntProtectionEnabled(int rdPuntTimeout) {
         return rdPuntTimeout != 0;
     }
 
+    private boolean isNdPuntProtectionEnabled(int ndPuntTimeout) {
+        return ndPuntTimeout != 0;
+    }
+
     public void installIcmpv6NaForwardFlow(short tableId, IVirtualPort vmPort, BigInteger dpId, Long elanTag,
             int addOrRemove) {
         List<MatchInfo> matches = getIcmpv6NAMatch(elanTag);
index 2e2474c501c672f53d9c2a9ccc3a3f00025957df..80af42f48feba06c0998b1599c3e9c576ac15ce7 100644 (file)
@@ -1,3 +1,4 @@
 <ipv6service-config xmlns="urn:opendaylight:netvirt:ipv6service:config">
   <router-discovery-punt-timeout>10</router-discovery-punt-timeout>
+  <neighbor-discovery-punt-timeout>10</neighbor-discovery-punt-timeout>
 </ipv6service-config>
index 96c1d2b40a271822dd26ad0949f3a6308efb57d0..8abe60b047a5e4a4b5d5f004f5c05738c522a929 100644 (file)
@@ -20,5 +20,12 @@ module ipv6service-config {
             type uint16;
             default 10;
         }
+
+        leaf neighbor-discovery-punt-timeout {
+            description "Hard timeout value for learnt flows for neighbor discovery punts (unit - seconds).
+                To turn off the rate limiting and installation of learnt flows, it should be set to 0";
+            type uint16;
+            default 10;
+        }
     }
 }