Rate limit for IPv6 RS punt packets. 34/76934/5
authorSomashekar Byrappa <somashekar.b@altencalsoftlabs.com>
Fri, 12 Oct 2018 11:54:46 +0000 (17:24 +0530)
committerSomashekar Byrappa <somashekar.b@altencalsoftlabs.com>
Wed, 24 Oct 2018 11:13:42 +0000 (16:43 +0530)
+ RS punt controller flow is updated with learn action which adds drop
  RS flow per port.
+ The drop flow will have higher priority (60) than the punt controller
  flow (50) to make sure subsequent RS packets for the same port is
  dropped till the hard_timeout value (10 secs).
+ The drop flow will match metadata on LPORT tag to make sure it drops
  RS packets per port.

 "cookie=0x4000000, duration=3.379s, table=45, n_packets=0, n_bytes=0,
   hard_timeout=10, priority=60,
   icmp6,metadata=0x50000000000/0xfffff0000000000,icmp_type=133,
   icmp_code=0 actions=drop"

 "cookie=0x4000000, duration=1.413s, table=45, n_packets=0, n_bytes=0,
   hard_timeout=10, priority=60,icmp6,
   metadata=0x70000000000/0xfffff0000000000,icmp_type=133,icmp_code=0
   actions=drop"

 "cookie=0x4000000, duration=11367.920s, table=45, n_packets=10,
   n_bytes=700, priority=50,icmp6,metadata=0x1389000000/0xffff000000,
   icmp_type=133,icmp_code=0 actions=CONTROLLER:65535,learn(table=45,
   hard_timeout=10,priority=60,cookie=0x4000000,eth_type=0x86dd,
   nw_proto=58,icmpv6_type=133,icmpv6_code=0,OXM_OF_METADATA[40..59])"

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

Change-Id: I4a6ec6e5d3b87722f6b722f38410f4acd7a77db3
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 [new file with mode: 0644]
ipv6service/impl/src/main/resources/org/opendaylight/blueprint/ipv6service.xml
ipv6service/impl/src/main/yang/ipv6service-config.yang [new file with mode: 0644]

index 43607b5c1a39308c35f05f5406e3b481643b3d69..352ca2d724841b85076c9bf38387af34472e52ae 100644 (file)
@@ -25,9 +25,11 @@ public interface Ipv6ServiceConstants {
     String DEVICE_OWNER_DHCP = "network:dhcp";
     String DEVICE_OWNER_COMPUTE_NOVA = "compute:nova";
 
-    BigInteger INVALID_DPID = new BigInteger("-1");
+    short RS_PUNT_PROTECTION_FLOW_PRIORITY = 60;
     short DEFAULT_FLOW_PRIORITY = 50;
     short PUNT_NA_FLOW_PRIORITY = 40;
+
+    BigInteger INVALID_DPID = new BigInteger("-1");
     String FLOWID_PREFIX = "IPv6.";
     String FLOWID_SEPARATOR = ".";
 
index 696eaf5c715d64b63b4817f0b6e1f356cab17e9d..b782ddd0e2ee16db45eac2f0da46ce0782123795 100644 (file)
@@ -13,6 +13,7 @@ import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import javax.inject.Inject;
@@ -21,6 +22,9 @@ import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.infra.Datastore;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.genius.ipv6util.api.Icmpv6Type;
 import org.opendaylight.genius.ipv6util.api.Ipv6Constants;
 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
@@ -31,6 +35,8 @@ 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.actions.ActionLearn;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
@@ -41,7 +47,9 @@ import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6NdTarget;
 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Source;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
 import org.opendaylight.genius.utils.ServiceIndex;
+import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
 import org.opendaylight.netvirt.ipv6service.VirtualSubnet;
 import org.opendaylight.netvirt.ipv6service.api.IVirtualPort;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
@@ -62,6 +70,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.config.rev181010.Ipv6serviceConfig;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -84,11 +93,15 @@ public class Ipv6ServiceUtils {
 
     private final DataBroker broker;
     private final IMdsalApiManager mdsalUtil;
+    private final ManagedNewTransactionRunner txRunner;
+    private final Ipv6serviceConfig ipv6serviceConfig;
 
     @Inject
-    public Ipv6ServiceUtils(DataBroker broker, IMdsalApiManager mdsalUtil) {
+    public Ipv6ServiceUtils(DataBroker broker, IMdsalApiManager mdsalUtil, Ipv6serviceConfig ipv6ServiceConfig) {
         this.broker = broker;
         this.mdsalUtil = mdsalUtil;
+        this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
+        this.ipv6serviceConfig = ipv6ServiceConfig;
     }
 
     /**
@@ -222,24 +235,60 @@ public class Ipv6ServiceUtils {
         if (dpId == null || dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
             return;
         }
-        List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
-        List<InstructionInfo> instructions = new ArrayList<>();
-        List<ActionInfo> actionsInfos = new ArrayList<>();
-        // Punt to controller
-        actionsInfos.add(new ActionPuntToController());
-        instructions.add(new InstructionApplyActions(actionsInfos));
-        FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                getIPv6FlowRef(dpId, elanTag, "IPv6RS"),Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
-                NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
+        String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6RS");
         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
             LOG.trace("Removing IPv6 Router 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 {
+            List<ActionInfo> actionsInfos = new ArrayList<>();
+            // Punt to controller
+            actionsInfos.add(new ActionPuntToController());
+
+            int rdPuntTimeout = ipv6serviceConfig.getRouterDiscoveryPuntTimeout();
+            if (isRdPuntProtectionEnabled(rdPuntTimeout)) {
+                actionsInfos.add(getLearnActionForRsPuntProtection(rdPuntTimeout));
+            }
+            List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
+            List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
+            FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+                    flowId,Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
+                    NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
+
             LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
-            mdsalUtil.installFlow(rsFlowEntity);
+            LoggingFutures
+                    .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+                        mdsalUtil.addFlow(tx, rsFlowEntity);
+                    }), LOG, "Error while adding flow={}", rsFlowEntity);
         }
     }
 
+    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)));
+    }
+
+    private boolean isRdPuntProtectionEnabled(int rdPuntTimeout) {
+        return rdPuntTimeout != 0;
+    }
+
     public void installIcmpv6NaForwardFlow(short tableId, IVirtualPort vmPort, BigInteger dpId, Long elanTag,
             int addOrRemove) {
         List<MatchInfo> matches = getIcmpv6NAMatch(elanTag);
diff --git a/ipv6service/impl/src/main/resources/initial/netvirt-ipv6service-config.xml b/ipv6service/impl/src/main/resources/initial/netvirt-ipv6service-config.xml
new file mode 100644 (file)
index 0000000..2e2474c
--- /dev/null
@@ -0,0 +1,3 @@
+<ipv6service-config xmlns="urn:opendaylight:netvirt:ipv6service:config">
+  <router-discovery-punt-timeout>10</router-discovery-punt-timeout>
+</ipv6service-config>
index bf04ed2bf0ae72d3a7c21f26f5b174b84084c8e0..d69c904a73b5e9e8f0215359fc24fb00ba5eae43 100644 (file)
   <odl:notification-listener ref="ipv6PktHandler" />
 
   <service ref="ifMgr" interface="org.opendaylight.netvirt.ipv6service.api.ElementCache" />
+
+  <odl:clustered-app-config id="ipv6serviceConfig"
+                            binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.config.rev181010.Ipv6serviceConfig"
+                            default-config-file-name="netvirt-ipv6service-config.xml"
+                            update-strategy="none">
+  </odl:clustered-app-config>
 </blueprint>
diff --git a/ipv6service/impl/src/main/yang/ipv6service-config.yang b/ipv6service/impl/src/main/yang/ipv6service-config.yang
new file mode 100644 (file)
index 0000000..96c1d2b
--- /dev/null
@@ -0,0 +1,24 @@
+module ipv6service-config {
+    yang-version 1;
+    namespace "urn:opendaylight:netvirt:ipv6service-config";
+    prefix "ipv6service-config";
+
+    description
+        "Configuration for IPv6 service.";
+
+    revision "2018-10-10" {
+        description
+                "Initial revision.";
+    }
+
+    container ipv6service-config {
+        config true;
+
+        leaf router-discovery-punt-timeout {
+            description "Hard timeout value for learnt flows for router 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;
+        }
+    }
+}