Packet throttle support
Change-Id: I2e0426850399e5c176b82f64db334c189aec6152
diff --git a/apps/packet-throttle/BUCK b/apps/packet-throttle/BUCK
new file mode 100644
index 0000000..3f5eb4f
--- /dev/null
+++ b/apps/packet-throttle/BUCK
@@ -0,0 +1,12 @@
+BUNDLES = [
+ '//apps/packet-throttle/app:onos-apps-packet-throttle-app',
+]
+
+onos_app (
+ app_name = 'org.onosproject.packetthrottle',
+ title = 'Packet Throttler',
+ category = 'Traffic Steering',
+ url = 'http://onosproject.org',
+ description = 'Packet throttle application to make ONOS drop packets crossing threshold',
+ included_bundles = BUNDLES,
+)
diff --git a/apps/packet-throttle/app/BUCK b/apps/packet-throttle/app/BUCK
new file mode 100644
index 0000000..4fdd72a
--- /dev/null
+++ b/apps/packet-throttle/app/BUCK
@@ -0,0 +1,17 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//core/store/serializers:onos-core-serializers',
+ '//core/store/primitives:onos-core-primitives',
+ '//lib:org.apache.karaf.shell.console',
+ '//cli:onos-cli',
+]
+
+TEST_DEPS = [
+ '//lib:TEST_ADAPTERS',
+]
+
+osgi_jar_with_tests (
+ deps = COMPILE_DEPS,
+ test_deps = TEST_DEPS,
+)
+
diff --git a/apps/packet-throttle/app/pom.xml b/apps/packet-throttle/app/pom.xml
new file mode 100644
index 0000000..0fd1e0e
--- /dev/null
+++ b/apps/packet-throttle/app/pom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2019 Open Networking Foundation
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>onos-apps</artifactId>
+ <groupId>org.onosproject</groupId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-apps-packet-throttle-app</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <onos.version>1.12.2-SNAPSHOT</onos.version>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.component.annotations</artifactId>
+ <version>1.4.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>5.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ <version>4.2.1</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${onos.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/PacketThrottleManager.java b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/PacketThrottleManager.java
new file mode 100644
index 0000000..a25123e
--- /dev/null
+++ b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/PacketThrottleManager.java
@@ -0,0 +1,666 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.packetthrottle;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.net.packet.PacketInFilter;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.net.packet.packetfilter.DefaultPacketInFilter;
+import org.onosproject.net.packet.packetfilter.ArpPacketClassifier;
+import org.onosproject.net.packet.packetfilter.Dhcp6IndirectPacketClassifier;
+import org.onosproject.net.packet.packetfilter.Dhcp6DirectPacketClassifier;
+import org.onosproject.net.packet.packetfilter.DhcpPacketClassifier;
+import org.onosproject.net.packet.packetfilter.NAPacketClassifier;
+import org.onosproject.net.packet.packetfilter.NSPacketClassifier;
+import org.onosproject.net.packet.packetfilter.IcmpPacketClassifier;
+import org.onosproject.net.packet.packetfilter.Icmp6PacketClassifier;
+import org.onosproject.packetthrottle.api.PacketThrottleService;
+
+
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+
+/**
+ * Manage the packet throttle for various type of packets.
+ */
+@Component(immediate = true)
+@Service
+public class PacketThrottleManager implements PacketThrottleService {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ protected static final String ARP_FILTER = "arpFilter";
+ protected static final String DHCP_FILTER = "dhcpFilter";
+ protected static final String NS_FILTER = "nsFilter";
+ protected static final String NA_FILTER = "naFilter";
+ protected static final String DHCP6_DIRECT_FILTER = "dhcp6DirectFilter";
+ protected static final String DHCP6_INDIRECT_FILTER = "dhcp6IndirectFilter";
+ protected static final String ICMP_FILTER = "icmpFilter";
+ protected static final String ICMP6_FILTER = "icmp6Filter";
+
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ PacketService packetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService configService;
+
+ private static final int PPS_ARP = 100;
+ private static final int PPS_DHCP = 100;
+ private static final int PPS_NS = 100;
+ private static final int PPS_NA = 100;
+ private static final int PPS_DHCP6_DIRECT = 100;
+ private static final int PPS_DHCP6_INDIRECT = 100;
+ private static final int PPS_ICMP = 100;
+ private static final int PPS_ICMP6 = 100;
+
+ private static final int WIN_SIZE_ARP_MS = 500;
+ private static final int WIN_SIZE_DHCP_MS = 500;
+ private static final int WIN_SIZE_NS_MS = 500;
+ private static final int WIN_SIZE_NA_MS = 500;
+ private static final int WIN_SIZE_DHCP6_DIRECT_MS = 500;
+ private static final int WIN_SIZE_DHCP6_INDIRECT_MS = 500;
+ private static final int WIN_SIZE_ICMP_MS = 500;
+ private static final int WIN_SIZE_ICMP6_MS = 500;
+
+ private static final int GUARD_TIME_ARP_SEC = 10;
+ private static final int GUARD_TIME_DHCP_SEC = 10;
+ private static final int GUARD_TIME_NS_SEC = 10;
+ private static final int GUARD_TIME_NA_SEC = 10;
+ private static final int GUARD_TIME_DHCP6_DIRECT_SEC = 10;
+ private static final int GUARD_TIME_DHCP6_INDIRECT_SEC = 10;
+ private static final int GUARD_TIME_ICMP_SEC = 10;
+ private static final int GUARD_TIME_ICMP6_SEC = 10;
+
+ private static final int WIN_THRES_ARP = 10;
+ private static final int WIN_THRES_DHCP = 10;
+ private static final int WIN_THRES_NS = 10;
+ private static final int WIN_THRES_NA = 10;
+ private static final int WIN_THRES_DHCP6_DIRECT = 10;
+ private static final int WIN_THRES_DHCP6_INDIRECT = 10;
+ private static final int WIN_THRES_ICMP = 10;
+ private static final int WIN_THRES_ICMP6 = 10;
+
+ /**
+ * Parameter to set packet per second rate for all filter types.
+ */
+ @Property(name = "ppsArp", intValue = PPS_ARP,
+ label = "Packet per second for the ARP packet")
+ private int ppsArp = PPS_ARP;
+
+ @Property(name = "ppsDhcp", intValue = PPS_DHCP,
+ label = "Packet per second for the DHCP packet")
+ private int ppsDhcp = PPS_DHCP;
+
+ @Property(name = "ppsNs", intValue = PPS_NS,
+ label = "Packet per second for the NS packet")
+ private int ppsNs = PPS_NS;
+
+ @Property(name = "ppsNa", intValue = PPS_NA,
+ label = "Packet per second for the NA packet")
+ private int ppsNa = PPS_NA;
+
+ @Property(name = "ppsDhcp6Direct", intValue = PPS_DHCP6_DIRECT,
+ label = "Packet per second for the DHCP6 Direct message")
+ private int ppsDhcp6Direct = PPS_DHCP6_DIRECT;
+
+ @Property(name = "ppsDhcp6Indirect", intValue = PPS_DHCP6_INDIRECT,
+ label = "Packet per second for the DHCP6 indirect message")
+ private int ppsDhcp6Indirect = PPS_DHCP6_INDIRECT;
+
+ @Property(name = "ppsIcmp", intValue = PPS_ICMP,
+ label = "Packet per second for the ICMP message")
+ private int ppsIcmp = PPS_ICMP;
+
+ @Property(name = "ppsIcmp6", intValue = PPS_ICMP6,
+ label = "Packet per second for the ICMP6 message")
+ private int ppsIcmp6 = PPS_ICMP6;
+
+
+ /**
+ * Parameter to set window size in milli seconds to check overflow of packets.
+ */
+
+ @Property(name = "winSizeArp", intValue = WIN_SIZE_ARP_MS,
+ label = "Window size for the ARP packet in milliseconds")
+ private int winSizeArp = WIN_SIZE_ARP_MS;
+
+ @Property(name = "winSizeDhcp", intValue = WIN_SIZE_DHCP_MS,
+ label = "Window size for the DHCP packet in milliseconds")
+ private int winSizeDhcp = WIN_SIZE_DHCP_MS;
+
+ @Property(name = "winSizeNs", intValue = WIN_SIZE_NS_MS,
+ label = "Window size for the NS packet in milliseconds")
+ private int winSizeNs = WIN_SIZE_NS_MS;
+
+ @Property(name = "winSizeNa", intValue = WIN_SIZE_NA_MS,
+ label = "Window size for the NA packet in milliseconds")
+ private int winSizeNa = WIN_SIZE_NA_MS;
+
+ @Property(name = "winSizeDhcp6Direct", intValue = WIN_SIZE_DHCP6_DIRECT_MS,
+ label = "Window size for the DHCP6 Direct message in milliseconds")
+ private int winSizeDhcp6Direct = WIN_SIZE_DHCP6_DIRECT_MS;
+
+ @Property(name = "winSizeDhcp6Indirect", intValue = WIN_SIZE_DHCP6_INDIRECT_MS,
+ label = "Window size for the DHCP6 indirect message in milliseconds")
+ private int winSizeDhcp6Indirect = WIN_SIZE_DHCP6_INDIRECT_MS;
+
+ @Property(name = "winSizeIcmp", intValue = WIN_SIZE_ICMP_MS,
+ label = "Window size for the ICMP message in milliseconds")
+ private int winSizeIcmp = WIN_SIZE_ICMP_MS;
+
+ @Property(name = "winSizeIcmp6", intValue = WIN_SIZE_ICMP6_MS,
+ label = "Window size for the ICMP6 message in milliseconds")
+ private int winSizeIcmp6 = WIN_SIZE_ICMP6_MS;
+
+ /**
+ * Time duration for which no more packets will be processed for a given filter type
+ * provided consecutive overflow windows happens.
+ */
+
+ @Property(name = "guardTimeArp", intValue = GUARD_TIME_ARP_SEC,
+ label = "Guard time for the ARP packet in seconds")
+ private int guardTimeArp = GUARD_TIME_ARP_SEC;
+
+ @Property(name = "guardTimeDhcp", intValue = GUARD_TIME_DHCP_SEC,
+ label = "Guard time for the DHCP packet in seconds")
+ private int guardTimeDhcp = GUARD_TIME_DHCP_SEC;
+
+ @Property(name = "guardTimeNs", intValue = GUARD_TIME_NS_SEC,
+ label = "Guard time for the NS packet in seconds")
+ private int guardTimeNs = GUARD_TIME_NS_SEC;
+
+ @Property(name = "guardTimeNa", intValue = GUARD_TIME_NA_SEC,
+ label = "Guard time for the NA packet in seconds")
+ private int guardTimeNa = GUARD_TIME_NA_SEC;
+
+ @Property(name = "guardTimeDhcp6Direct", intValue = GUARD_TIME_DHCP6_DIRECT_SEC,
+ label = "Guard time for the DHCP6 Direct message in seconds")
+ private int guardTimeDhcp6Direct = GUARD_TIME_DHCP6_DIRECT_SEC;
+
+ @Property(name = "guardTimeDhcp6Indirect", intValue = GUARD_TIME_DHCP6_INDIRECT_SEC,
+ label = "Guard time for the DHCP6 indirect message in seconds")
+ private int guardTimeDhcp6Indirect = GUARD_TIME_DHCP6_INDIRECT_SEC;
+
+ @Property(name = "guardTimeIcmp", intValue = GUARD_TIME_ICMP_SEC,
+ label = "Guard time for the ICMP message in seconds")
+ private int guardTimeIcmp = GUARD_TIME_ICMP_SEC;
+
+ @Property(name = "guardTimeIcmp6", intValue = GUARD_TIME_ICMP6_SEC,
+ label = "Guard time for the ICMP6 message in seconds")
+ private int guardTimeIcmp6 = GUARD_TIME_ICMP6_SEC;
+
+ /**
+ * Consecutive overflow window threshold.
+ */
+
+ @Property(name = "winThresArp", intValue = WIN_THRES_ARP,
+ label = "Window drop threshold for the ARP packet")
+ private int winThresArp = WIN_THRES_ARP;
+
+ @Property(name = "winThresDhcp", intValue = WIN_THRES_DHCP,
+ label = "Window drop threshold for the DHCP packet")
+ private int winThresDhcp = WIN_THRES_DHCP;
+
+ @Property(name = "winThresNs", intValue = WIN_THRES_NS,
+ label = "Window drop threshold for the NS packet")
+ private int winThresNs = WIN_THRES_NS;
+
+ @Property(name = "winThresNa", intValue = WIN_THRES_NA,
+ label = "Window drop threshold for the NA packet")
+ private int winThresNa = WIN_THRES_NA;
+
+ @Property(name = "winThresDhcp6Direct", intValue = WIN_THRES_DHCP6_DIRECT,
+ label = "Window drop threshold for the DHCP6 Direct message")
+ private int winThresDhcp6Direct = WIN_THRES_DHCP6_DIRECT;
+
+ @Property(name = "winThresDhcp6Indirect", intValue = WIN_THRES_DHCP6_INDIRECT,
+ label = "Window drop threshold for the DHCP6 indirect message")
+ private int winThresDhcp6Indirect = WIN_THRES_DHCP6_INDIRECT;
+
+ @Property(name = "winThresIcmp", intValue = WIN_THRES_ICMP,
+ label = "Window drop threshold for the ICMP message")
+ private int winThresIcmp = WIN_THRES_ICMP;
+
+ @Property(name = "winThresIcmp6", intValue = WIN_THRES_ICMP6,
+ label = "Window drop threshold for the ICMP6 message")
+ private int winThresIcmp6 = WIN_THRES_ICMP6;
+
+
+
+
+ private Map<String, PacketInFilter> mapCounterFilter = new HashMap<>();
+
+ @Activate
+ protected void activate() {
+ log.info("Started");
+ configService.registerProperties(getClass());
+ createAllFilters();
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ configService.unregisterProperties(getClass(), false);
+ removeAllFilters();
+ log.info("Stopped");
+ }
+
+ private void checkChangeInPps(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+ int newPpsArp, newPpsDhcp, newPpsNs, newPpsNa, newPpsDhcp6Direct;
+ int newPpsDhcp6Indirect, newPpsIcmp, newPpsIcmp6;
+ try {
+ String s = get(properties, "ppsArp");
+ newPpsArp = isNullOrEmpty(s) ? ppsArp : Integer.parseInt(s.trim());
+
+ s = get(properties, "ppsDhcp");
+ newPpsDhcp = isNullOrEmpty(s) ? ppsDhcp : Integer.parseInt(s.trim());
+
+ s = get(properties, "ppsNs");
+ newPpsNs = isNullOrEmpty(s) ? ppsNs : Integer.parseInt(s.trim());
+
+ s = get(properties, "ppsNa");
+ newPpsNa = isNullOrEmpty(s) ? ppsNa : Integer.parseInt(s.trim());
+
+ s = get(properties, "ppsDhcp6Direct");
+ newPpsDhcp6Direct = isNullOrEmpty(s) ? ppsDhcp6Direct : Integer.parseInt(s.trim());
+
+ s = get(properties, "ppsDhcp6Indirect");
+ newPpsDhcp6Indirect = isNullOrEmpty(s) ? ppsDhcp6Indirect : Integer.parseInt(s.trim());
+
+ s = get(properties, "ppsIcmp");
+ newPpsIcmp = isNullOrEmpty(s) ? ppsIcmp : Integer.parseInt(s.trim());
+
+ s = get(properties, "ppsIcmp6");
+ newPpsIcmp6 = isNullOrEmpty(s) ? ppsIcmp6 : Integer.parseInt(s.trim());
+ } catch (NumberFormatException | ClassCastException e) {
+ newPpsArp = PPS_ARP;
+ newPpsDhcp = PPS_DHCP;
+ newPpsNs = PPS_NS;
+ newPpsNa = PPS_NA;
+ newPpsDhcp6Direct = PPS_DHCP6_DIRECT;
+ newPpsDhcp6Indirect = PPS_DHCP6_INDIRECT;
+ newPpsIcmp = PPS_ICMP;
+ newPpsIcmp6 = PPS_ICMP6;
+ }
+ if (newPpsArp != ppsArp) {
+ ppsArp = newPpsArp;
+ mapCounterFilter.get(ARP_FILTER).setPps(ppsArp);
+ }
+ if (newPpsDhcp != ppsDhcp) {
+ ppsDhcp = newPpsDhcp;
+ mapCounterFilter.get(DHCP_FILTER).setPps(ppsDhcp);
+ }
+ if (newPpsNs != ppsNs) {
+ ppsNs = newPpsNs;
+ mapCounterFilter.get(NS_FILTER).setPps(ppsNs);
+ }
+ if (newPpsNa != ppsNa) {
+ ppsNa = newPpsNa;
+ mapCounterFilter.get(NA_FILTER).setPps(ppsNa);
+ }
+ if (newPpsDhcp6Direct != ppsDhcp6Direct) {
+ ppsDhcp6Direct = newPpsDhcp6Direct;
+ mapCounterFilter.get(DHCP6_DIRECT_FILTER).setPps(ppsDhcp6Direct);
+ }
+ if (newPpsDhcp6Indirect != ppsDhcp6Indirect) {
+ ppsDhcp6Indirect = newPpsDhcp6Indirect;
+ mapCounterFilter.get(DHCP6_INDIRECT_FILTER).setPps(ppsDhcp6Indirect);
+ }
+ if (newPpsIcmp != ppsIcmp) {
+ ppsIcmp = newPpsIcmp;
+ mapCounterFilter.get(ICMP_FILTER).setPps(ppsIcmp);
+ }
+ if (newPpsIcmp6 != ppsIcmp6) {
+ ppsIcmp6 = newPpsIcmp6;
+ mapCounterFilter.get(ICMP6_FILTER).setPps(ppsIcmp6);
+ }
+ }
+
+ private void checkChangeInWinSize(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+
+ int newWinSizeArp, newWinSizeDhcp, newWinSizeNs, newWinSizeNa;
+ int newWinSizeDhcp6Direct, newWinSizeDhcp6Indirect, newWinSizeIcmp, newWinSizeIcmp6;
+ try {
+ String s = get(properties, "winSizeArp");
+ newWinSizeArp = isNullOrEmpty(s) ? winSizeArp : Integer.parseInt(s.trim());
+
+ s = get(properties, "winSizeDhcp");
+ newWinSizeDhcp = isNullOrEmpty(s) ? winSizeDhcp : Integer.parseInt(s.trim());
+
+ s = get(properties, "winSizeNs");
+ newWinSizeNs = isNullOrEmpty(s) ? winSizeNs : Integer.parseInt(s.trim());
+
+ s = get(properties, "winSizeNa");
+ newWinSizeNa = isNullOrEmpty(s) ? winSizeNa : Integer.parseInt(s.trim());
+
+ s = get(properties, "winSizeDhcp6Direct");
+ newWinSizeDhcp6Direct = isNullOrEmpty(s) ? winSizeDhcp6Direct : Integer.parseInt(s.trim());
+
+ s = get(properties, "winSizeDhcp6Indirect");
+ newWinSizeDhcp6Indirect = isNullOrEmpty(s) ? winSizeDhcp6Indirect : Integer.parseInt(s.trim());
+
+ s = get(properties, "winSizeIcmp");
+ newWinSizeIcmp = isNullOrEmpty(s) ? winSizeIcmp : Integer.parseInt(s.trim());
+
+ s = get(properties, "winSizeIcmp6");
+ newWinSizeIcmp6 = isNullOrEmpty(s) ? winSizeIcmp6 : Integer.parseInt(s.trim());
+ } catch (NumberFormatException | ClassCastException e) {
+ newWinSizeArp = WIN_SIZE_ARP_MS;
+ newWinSizeDhcp = WIN_SIZE_DHCP_MS;
+ newWinSizeNs = WIN_SIZE_NS_MS;
+ newWinSizeNa = WIN_SIZE_NA_MS;
+ newWinSizeDhcp6Direct = WIN_SIZE_DHCP6_DIRECT_MS;
+ newWinSizeDhcp6Indirect = WIN_SIZE_DHCP6_INDIRECT_MS;
+ newWinSizeIcmp = WIN_SIZE_ICMP_MS;
+ newWinSizeIcmp6 = WIN_SIZE_ICMP6_MS;
+ }
+ if (newWinSizeArp != winSizeArp) {
+ winSizeArp = newWinSizeArp;
+ mapCounterFilter.get(ARP_FILTER).setWinSize(winSizeArp);
+ }
+ if (newWinSizeDhcp != winSizeDhcp) {
+ winSizeDhcp = newWinSizeDhcp;
+ mapCounterFilter.get(DHCP_FILTER).setWinSize(winSizeDhcp);
+ }
+ if (newWinSizeNs != winSizeNs) {
+ winSizeNs = newWinSizeNs;
+ mapCounterFilter.get(NS_FILTER).setWinSize(winSizeNs);
+ }
+ if (newWinSizeNa != winSizeNa) {
+ winSizeNa = newWinSizeNa;
+ mapCounterFilter.get(NA_FILTER).setWinSize(winSizeNa);
+ }
+ if (newWinSizeDhcp6Direct != winSizeDhcp6Direct) {
+ winSizeDhcp6Direct = newWinSizeDhcp6Direct;
+ mapCounterFilter.get(DHCP6_DIRECT_FILTER).setWinSize(winSizeDhcp6Direct);
+ }
+ if (newWinSizeDhcp6Indirect != winSizeDhcp6Indirect) {
+ winSizeDhcp6Indirect = newWinSizeDhcp6Indirect;
+ mapCounterFilter.get(DHCP6_INDIRECT_FILTER).setWinSize(winSizeDhcp6Indirect);
+ }
+ if (newWinSizeIcmp != winSizeIcmp) {
+ winSizeIcmp = newWinSizeIcmp;
+ mapCounterFilter.get(ICMP_FILTER).setWinSize(winSizeIcmp);
+ }
+ if (newWinSizeIcmp6 != winSizeIcmp6) {
+ winSizeIcmp6 = newWinSizeIcmp6;
+ mapCounterFilter.get(ICMP6_FILTER).setWinSize(winSizeIcmp6);
+ }
+
+ }
+
+ private void checkChangeInGuardTime(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+ int newGuardTimeArp, newGuardTimeDhcp, newGuardTimeNs, newGuardTimeNa;
+ int newGuardTimeDhcp6Direct, newGuardTimeDhcp6Indirect, newGuardTimeIcmp, newGuardTimeIcmp6;
+ try {
+ String s = get(properties, "guardTimeArp");
+ newGuardTimeArp = isNullOrEmpty(s) ? guardTimeArp : Integer.parseInt(s.trim());
+
+ s = get(properties, "guardTimeDhcp");
+ newGuardTimeDhcp = isNullOrEmpty(s) ? guardTimeDhcp : Integer.parseInt(s.trim());
+
+ s = get(properties, "guardTimeNs");
+ newGuardTimeNs = isNullOrEmpty(s) ? guardTimeNs : Integer.parseInt(s.trim());
+
+ s = get(properties, "guardTimeNa");
+ newGuardTimeNa = isNullOrEmpty(s) ? guardTimeNa : Integer.parseInt(s.trim());
+
+ s = get(properties, "guardTimeDhcp6Direct");
+ newGuardTimeDhcp6Direct = isNullOrEmpty(s) ? guardTimeDhcp6Direct : Integer.parseInt(s.trim());
+
+ s = get(properties, "guardTimeDhcp6Indirect");
+ newGuardTimeDhcp6Indirect = isNullOrEmpty(s) ? guardTimeDhcp6Indirect : Integer.parseInt(s.trim());
+
+ s = get(properties, "guardTimeIcmp");
+ newGuardTimeIcmp = isNullOrEmpty(s) ? guardTimeIcmp : Integer.parseInt(s.trim());
+
+ s = get(properties, "guardTimeIcmp6");
+ newGuardTimeIcmp6 = isNullOrEmpty(s) ? guardTimeIcmp6 : Integer.parseInt(s.trim());
+ } catch (NumberFormatException | ClassCastException e) {
+
+ newGuardTimeArp = GUARD_TIME_ARP_SEC;
+ newGuardTimeDhcp = GUARD_TIME_DHCP_SEC;
+ newGuardTimeNs = GUARD_TIME_NS_SEC;
+ newGuardTimeNa = GUARD_TIME_NA_SEC;
+ newGuardTimeDhcp6Direct = GUARD_TIME_DHCP6_DIRECT_SEC;
+ newGuardTimeDhcp6Indirect = GUARD_TIME_DHCP6_INDIRECT_SEC;
+ newGuardTimeIcmp = GUARD_TIME_ICMP_SEC;
+ newGuardTimeIcmp6 = GUARD_TIME_ICMP6_SEC;
+ }
+ if (newGuardTimeArp != guardTimeArp) {
+ guardTimeArp = newGuardTimeArp;
+ mapCounterFilter.get(ARP_FILTER).setGuardTime(guardTimeArp);
+ }
+ if (newGuardTimeDhcp != guardTimeDhcp) {
+ guardTimeDhcp = newGuardTimeDhcp;
+ mapCounterFilter.get(DHCP_FILTER).setGuardTime(guardTimeDhcp);
+ }
+ if (newGuardTimeNs != guardTimeNs) {
+ guardTimeNs = newGuardTimeNs;
+ mapCounterFilter.get(NS_FILTER).setGuardTime(guardTimeNs);
+ }
+ if (newGuardTimeNa != guardTimeNa) {
+ guardTimeNa = newGuardTimeNa;
+ mapCounterFilter.get(NA_FILTER).setGuardTime(guardTimeNa);
+ }
+ if (newGuardTimeDhcp6Direct != guardTimeDhcp6Direct) {
+ guardTimeDhcp6Direct = newGuardTimeDhcp6Direct;
+ mapCounterFilter.get(DHCP6_DIRECT_FILTER).setGuardTime(guardTimeDhcp6Direct);
+ }
+ if (newGuardTimeDhcp6Indirect != guardTimeDhcp6Indirect) {
+ guardTimeDhcp6Indirect = newGuardTimeDhcp6Indirect;
+ mapCounterFilter.get(DHCP6_INDIRECT_FILTER).setGuardTime(guardTimeDhcp6Indirect);
+ }
+ if (newGuardTimeIcmp != guardTimeIcmp) {
+ guardTimeIcmp = newGuardTimeIcmp;
+ mapCounterFilter.get(ICMP_FILTER).setGuardTime(guardTimeIcmp);
+ }
+ if (newGuardTimeIcmp6 != guardTimeIcmp6) {
+ guardTimeIcmp6 = newGuardTimeIcmp6;
+ mapCounterFilter.get(ICMP6_FILTER).setGuardTime(guardTimeIcmp6);
+ }
+
+
+ }
+
+ private void checkChangeInWinThres(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+
+ int newWinThresArp, newWinThresDhcp, newWinThresNs, newWinThresNa;
+ int newWinThresDhcp6Direct, newWinThresDhcp6Indirect, newWinThresIcmp, newWinThresIcmp6;
+ try {
+
+ String s = get(properties, "winThresArp");
+ newWinThresArp = isNullOrEmpty(s) ? winThresArp : Integer.parseInt(s.trim());
+
+ s = get(properties, "winThresDhcp");
+ newWinThresDhcp = isNullOrEmpty(s) ? winThresDhcp : Integer.parseInt(s.trim());
+
+ s = get(properties, "winThresNs");
+ newWinThresNs = isNullOrEmpty(s) ? winThresNs : Integer.parseInt(s.trim());
+
+ s = get(properties, "winThresNa");
+ newWinThresNa = isNullOrEmpty(s) ? winThresNa : Integer.parseInt(s.trim());
+
+ s = get(properties, "winThresDhcp6Direct");
+ newWinThresDhcp6Direct = isNullOrEmpty(s) ? winThresDhcp6Direct : Integer.parseInt(s.trim());
+
+ s = get(properties, "winThresDhcp6Indirect");
+ newWinThresDhcp6Indirect = isNullOrEmpty(s) ? winThresDhcp6Indirect : Integer.parseInt(s.trim());
+
+ s = get(properties, "winThresIcmp");
+ newWinThresIcmp = isNullOrEmpty(s) ? winThresIcmp : Integer.parseInt(s.trim());
+
+ s = get(properties, "winThresIcmp6");
+ newWinThresIcmp6 = isNullOrEmpty(s) ? winThresIcmp6 : Integer.parseInt(s.trim());
+
+ } catch (NumberFormatException | ClassCastException e) {
+ newWinThresArp = WIN_THRES_ARP;
+ newWinThresDhcp = WIN_THRES_DHCP;
+ newWinThresNs = WIN_THRES_NS;
+ newWinThresNa = WIN_THRES_NA;
+ newWinThresDhcp6Direct = WIN_THRES_DHCP6_DIRECT;
+ newWinThresDhcp6Indirect = WIN_THRES_DHCP6_INDIRECT;
+ newWinThresIcmp = WIN_THRES_ICMP;
+ newWinThresIcmp6 = WIN_THRES_ICMP6;
+
+ }
+
+ if (newWinThresArp != winThresArp) {
+ winThresArp = newWinThresArp;
+ mapCounterFilter.get(ARP_FILTER).setWinThres(winThresArp);
+ }
+ if (newWinThresDhcp != winThresDhcp) {
+ winThresDhcp = newWinThresDhcp;
+ mapCounterFilter.get(DHCP_FILTER).setWinThres(winThresDhcp);
+ }
+ if (newWinThresNs != winThresNs) {
+ winThresNs = newWinThresNs;
+ mapCounterFilter.get(NS_FILTER).setWinThres(winThresNs);
+ }
+ if (newWinThresNa != winThresNa) {
+ winThresNa = newWinThresNa;
+ mapCounterFilter.get(NA_FILTER).setWinThres(winThresNa);
+ }
+ if (newWinThresDhcp6Direct != winThresDhcp6Direct) {
+ winThresDhcp6Direct = newWinThresDhcp6Direct;
+ mapCounterFilter.get(DHCP6_DIRECT_FILTER).setWinThres(winThresDhcp6Direct);
+ }
+ if (newWinThresDhcp6Indirect != winThresDhcp6Indirect) {
+ winThresDhcp6Indirect = newWinThresDhcp6Indirect;
+ mapCounterFilter.get(DHCP6_INDIRECT_FILTER).setWinThres(winThresDhcp6Indirect);
+ }
+ if (newWinThresIcmp != winThresIcmp) {
+ winThresIcmp = newWinThresIcmp;
+ mapCounterFilter.get(ICMP_FILTER).setWinThres(winThresIcmp);
+ }
+ if (newWinThresIcmp6 != winThresIcmp6) {
+ winThresIcmp6 = newWinThresIcmp6;
+ mapCounterFilter.get(ICMP6_FILTER).setWinThres(winThresIcmp6);
+ }
+
+ }
+
+ @Modified
+ private void modified(ComponentContext context) {
+ if (context == null) {
+ log.info("Default config");
+ return;
+ }
+
+ checkChangeInPps(context);
+ checkChangeInWinSize(context);
+ checkChangeInGuardTime(context);
+ checkChangeInWinThres(context);
+
+ log.info("Reconfigured ppsArp: {} ppsDhcp: {} ppsNs: {} ppsNa: {} " +
+ "ppsDhcp6Direct: {} ppsDhcp6Indirect: {} ppsIcmp: {} ppsIcmp6: {}",
+ ppsArp, ppsDhcp, ppsNs, ppsNa, ppsDhcp6Direct, ppsDhcp6Indirect,
+ ppsIcmp, ppsIcmp6);
+
+ log.info("Reconfigured winSizeArp: {} winSizeDhcp: {} winSizeNs: {} winSizeNa: {} " +
+ "winSizeDhcp6Direct: {} winSizeDhcp6Indirect: {} winSizeIcmp: {} winSizeIcmp6: {}",
+ winSizeArp, winSizeDhcp, winSizeNs, winSizeNa, winSizeDhcp6Direct,
+ winSizeDhcp6Indirect, winSizeIcmp, winSizeIcmp6);
+
+ log.info("Reconfigured guardTimeArp: {} guardTimeDhcp: {} guardTimeNs: {} guardTimeNa: {} " +
+ "guardTimeDhcp6Direct: {} guardTimeDhcp6Indirect: {} guardTimeIcmp: {} guardTimeIcmp6: {}",
+ guardTimeArp, guardTimeDhcp, guardTimeNs, guardTimeNa, guardTimeDhcp6Direct,
+ guardTimeDhcp6Indirect, guardTimeIcmp, guardTimeIcmp6);
+
+ log.info("Reconfigured winThresArp: {} winThresDhcp: {} winThresNs: {} winThresNa: {} " +
+ "winThresDhcp6Direct: {} winThresDhcp6Indirect: {} winThresIcmp: {} winThresIcmp6: {}",
+ winThresArp, winThresDhcp, winThresNs, winThresNa, winThresDhcp6Direct,
+ winThresDhcp6Indirect, winThresIcmp, winThresIcmp6);
+ }
+
+ /**
+ * Create all required filters.
+ */
+ private void createAllFilters() {
+ DefaultPacketInFilter filter;
+ ArpPacketClassifier arp = new ArpPacketClassifier();
+ filter = new DefaultPacketInFilter(ppsArp, winSizeArp, guardTimeArp, winThresArp, ARP_FILTER, arp);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ DhcpPacketClassifier dhcp4 = new DhcpPacketClassifier();
+ filter = new DefaultPacketInFilter(ppsDhcp, winSizeDhcp, guardTimeDhcp, winThresDhcp, DHCP_FILTER, dhcp4);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ Dhcp6DirectPacketClassifier dhcp6Direct = new Dhcp6DirectPacketClassifier();
+ filter = new DefaultPacketInFilter(ppsDhcp6Direct, winSizeDhcp6Direct, guardTimeDhcp6Direct,
+ winThresDhcp6Direct, DHCP6_DIRECT_FILTER, dhcp6Direct);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ Dhcp6IndirectPacketClassifier dhcp6Indirect = new Dhcp6IndirectPacketClassifier();
+ filter = new DefaultPacketInFilter(ppsDhcp6Direct, winSizeDhcp6Direct, guardTimeDhcp6Direct,
+ winThresDhcp6Direct, DHCP6_INDIRECT_FILTER, dhcp6Indirect);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ NAPacketClassifier na = new NAPacketClassifier();
+ filter = new DefaultPacketInFilter(ppsNa, winSizeNa, guardTimeNa, winThresNa, NA_FILTER, na);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ NSPacketClassifier ns = new NSPacketClassifier();
+ filter = new DefaultPacketInFilter(ppsNs, winSizeNs, guardTimeNs, winThresNs, NS_FILTER, ns);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ IcmpPacketClassifier icmp = new IcmpPacketClassifier();
+ filter = new DefaultPacketInFilter(ppsIcmp, winSizeIcmp, guardTimeIcmp, winThresIcmp, ICMP_FILTER, icmp);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ Icmp6PacketClassifier icmp6 = new Icmp6PacketClassifier();
+ filter = new DefaultPacketInFilter(ppsIcmp6, winSizeIcmp6, guardTimeIcmp6, winThresIcmp6, ICMP6_FILTER, icmp6);
+ packetService.addFilter(filter);
+ mapCounterFilter.put(filter.name(), filter);
+ }
+
+ /**
+ * Delete all the filters.
+ */
+ private void removeAllFilters() {
+ packetService.clearFilters();
+ mapCounterFilter.clear();
+ }
+
+ @Override
+ public Map<String, PacketInFilter> filterMap() {
+ return ImmutableMap.copyOf(mapCounterFilter);
+ }
+
+
+
+}
diff --git a/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/api/PacketThrottleService.java b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/api/PacketThrottleService.java
new file mode 100644
index 0000000..80abbdc
--- /dev/null
+++ b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/api/PacketThrottleService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.packetthrottle.api;
+
+import org.onosproject.net.packet.PacketInFilter;
+import java.util.Map;
+
+public interface PacketThrottleService {
+
+ /**
+ * Returns all avaiable packet filters.
+ * @return all packet filters
+ */
+ Map<String, PacketInFilter> filterMap();
+
+}
diff --git a/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/api/package-info.java b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/api/package-info.java
new file mode 100644
index 0000000..220deb0
--- /dev/null
+++ b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Packet throttle application.
+ */
+package org.onosproject.packetthrottle.api;
\ No newline at end of file
diff --git a/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/cli/PacketOverFlowStatsShowCommand.java b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/cli/PacketOverFlowStatsShowCommand.java
new file mode 100644
index 0000000..4c57956
--- /dev/null
+++ b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/cli/PacketOverFlowStatsShowCommand.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.packetthrottle.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.packet.PacketInFilter;
+import org.onosproject.packetthrottle.api.PacketThrottleService;
+import java.util.Map;
+
+
+/**
+ * Displays the statistics of the packets dropped due to throttle.
+ */
+@Command(scope = "onos", name = "pkt-stats-overflow-show",
+ description = "Displays the packet overflow statistics values")
+public class PacketOverFlowStatsShowCommand extends AbstractShellCommand {
+
+ private static final String FORMAT = "PacketType = %s, Count = %s";
+
+
+
+ @Override
+ protected void execute() {
+ PacketInFilter filter;
+ PacketThrottleService packetThrottleService = get(PacketThrottleService.class);
+ Map<String, PacketInFilter> filterMap = packetThrottleService.filterMap();
+ for (Map.Entry<String, PacketInFilter> entry: filterMap.entrySet()) {
+ filter = entry.getValue();
+ print(FORMAT, filter.name(), filter.droppedPackets());
+ }
+ }
+}
diff --git a/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/cli/package-info.java b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/cli/package-info.java
new file mode 100644
index 0000000..e94b5a4
--- /dev/null
+++ b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Packet throttle application.
+ */
+package org.onosproject.packetthrottle.cli;
diff --git a/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/package-info.java b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/package-info.java
new file mode 100644
index 0000000..ba0df46
--- /dev/null
+++ b/apps/packet-throttle/app/src/main/java/org/onosproject/packetthrottle/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Packet throttle application.
+ */
+package org.onosproject.packetthrottle;
\ No newline at end of file
diff --git a/apps/packet-throttle/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/packet-throttle/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 0000000..af13a4f
--- /dev/null
+++ b/apps/packet-throttle/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ Copyright 2019-present Open Networking Foundation
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.packetthrottle.cli.PacketOverFlowStatsShowCommand"/>
+ </command>
+ </command-bundle>
+</blueprint>
diff --git a/apps/packet-throttle/app/src/test/java/org/onosproject/packetthrottle/PacketThrottleManagerTest.java b/apps/packet-throttle/app/src/test/java/org/onosproject/packetthrottle/PacketThrottleManagerTest.java
new file mode 100644
index 0000000..4582a43
--- /dev/null
+++ b/apps/packet-throttle/app/src/test/java/org/onosproject/packetthrottle/PacketThrottleManagerTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.packetthrottle;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.net.packet.PacketInFilter;
+import com.google.common.collect.Sets;
+import org.onosproject.net.packet.packetfilter.ArpPacketClassifier;
+import org.onosproject.net.packet.packetfilter.DefaultPacketInFilter;
+import static org.junit.Assert.*;
+
+
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.List;
+
+/**
+ * Set of tests of the PacketThrottleManager.
+ */
+public class PacketThrottleManagerTest {
+
+ private PacketThrottleManager manager;
+
+
+ @Before
+ public void setUp() {
+ manager = new PacketThrottleManager();
+ manager.configService = new TestComponentConfig();
+ manager.packetService = new MockPacketService();
+ manager.activate();
+ }
+
+ @After
+ public void tearDown() {
+ manager.deactivate();
+ }
+
+ @Test
+ public void testFilter() {
+ DefaultPacketInFilter filter;
+ ArpPacketClassifier arp = new ArpPacketClassifier();
+ filter = new DefaultPacketInFilter(100, 500, 10, 10, PacketThrottleManager.ARP_FILTER, arp);
+ manager.packetService.addFilter(filter);
+ assertEquals(9, manager.packetService.getFilters().size());
+ manager.packetService.removeFilter(filter);
+ assertEquals(8, manager.packetService.getFilters().size());
+ }
+
+ private class MockPacketService extends PacketServiceAdapter {
+ Set<PacketProcessor> packetProcessors = Sets.newHashSet();
+ OutboundPacket emittedPacket;
+ private List<PacketInFilter> filters = new ArrayList<>();
+
+ @Override
+ public void addProcessor(PacketProcessor processor, int priority) {
+
+ packetProcessors.add(processor);
+ }
+
+ public void processPacket(PacketContext packetContext) {
+ packetProcessors.forEach(p -> p.process(packetContext));
+ }
+
+ @Override
+ public void emit(OutboundPacket packet) {
+
+ this.emittedPacket = packet;
+ }
+
+ @Override
+ public void addFilter(PacketInFilter filter) {
+ filters.add(filter);
+ }
+
+ @Override
+ public void removeFilter(PacketInFilter filter) {
+ filters.remove(filter);
+ }
+
+ @Override
+ public List<PacketInFilter> getFilters() {
+ return ImmutableList.copyOf(filters);
+ }
+ }
+
+ /**
+ * Mocks the ComponentConfigRegistry.
+ */
+ private class TestComponentConfig extends ComponentConfigAdapter {
+
+ }
+}
diff --git a/apps/packet-throttle/pom.xml b/apps/packet-throttle/pom.xml
new file mode 100644
index 0000000..4c8d20e
--- /dev/null
+++ b/apps/packet-throttle/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2019 Open Networking Foundation
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>onos-apps</artifactId>
+ <groupId>org.onosproject</groupId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-apps-packet-throttle</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <description>Packet throttle application to make ONOS drop packets crossing threshold.</description>
+
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <onos.version>1.12.2-SNAPSHOT</onos.version>
+ <onos.app.name>org.onosproject.packetthrottle</onos.app.name>
+ <onos.app.title>onos-apps-packet-throttle</onos.app.title>
+ <onos.app.origin>Infosys, Inc.</onos.app.origin>
+ <onos.app.category>Traffic Steering</onos.app.category>
+ <onos.app.url>http://onosproject.org</onos.app.url>
+ <onos.app.readme>Packet throttle application to make ONOS drop non-important packets.</onos.app.readme>
+ </properties>
+
+ <modules>
+ <module>app</module>
+ </modules>
+
+</project>
diff --git a/core/api/src/main/java/org/onosproject/net/packet/PacketInClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/PacketInClassifier.java
new file mode 100644
index 0000000..34c7502
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/PacketInClassifier.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet;
+
+
+/**
+ * Abstraction of incoming packet classifier for filtering.
+ */
+public interface PacketInClassifier {
+
+ /**
+ * Returns true if the packet classifier matches else false.
+ * The matching criterion should be non overlapping with other
+ * implementation of the PacketInClassifier.
+ *
+ * @param packet PacketContext holding the packet information
+ * @return boolean checks whether packet matches classifier
+ */
+ boolean match(PacketContext packet);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/PacketInFilter.java b/core/api/src/main/java/org/onosproject/net/packet/PacketInFilter.java
new file mode 100644
index 0000000..1338b05
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/PacketInFilter.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet;
+
+/**
+ * Abstraction of incoming packet filter.
+ */
+public interface PacketInFilter {
+
+ /**
+ * Types of filter action applied to incoming packets.
+ */
+ enum FilterAction {
+ /**
+ * Signifies that the packet is allowed to be processed.
+ */
+ PACKET_ALLOW,
+ /**
+ * Signifies that the packet is denied from being processed
+ * as it crossed the maxCounter.
+ */
+ PACKET_DENY,
+ /**
+ * Signifies that filter applied is a valid filter.
+ */
+ FILTER_VALID,
+ /**
+ * Signifies that this filter is disabled.
+ */
+ FILTER_DISABLED,
+ /**
+ * Signifies that the current window for packet processing is full
+ * and the window is blocked for packet processing.
+ */
+ WINDOW_BLOCKED,
+ /**
+ * Signifies that the packet processing is blocked as the
+ * threshold has crossed.
+ */
+ PACKET_BLOCKED,
+ /**
+ * Signifies that the filter applied is invalid filter.
+ */
+ FILTER_INVALID
+ }
+
+ /**
+ * Returns FilterAction before processing the packet.
+ * Decides if the packet is allowed to be processed or not.
+ *
+ * @param packet PackerContext holding the packet information
+ * @return FilterAction
+ */
+ FilterAction preProcess(PacketContext packet);
+
+ /**
+ * Get the name of the counter.
+ *
+ * @return name of the counter
+ */
+ String name();
+
+ /**
+ * Get the current value of the count of packets for this particular
+ * filter type waiting to get processed.
+ *
+ * @return count of packets with current filter type waiting to get processed
+ */
+ int pendingPackets();
+
+ /**
+ * Get the count of the dropped packets for this filter type.
+ *
+ * @return count of dropped packets for this filter type
+ */
+ int droppedPackets();
+
+ /**
+ * Set the pps rate for the current filter type to calculate the max counter
+ * allowed with window size.
+ *
+ * @param pps Packet per second rate expected
+ */
+ void setPps(int pps);
+
+ /**
+ * Set the window size for rate limiting.
+ *
+ * @param winSize Window size in milli seconds
+ */
+ void setWinSize(int winSize);
+
+ /**
+ * Set the Guard time in case WinThres is crossed.
+ *
+ * @param guardTime Guard time in seconds
+ */
+ void setGuardTime(int guardTime);
+
+ /**
+ * Set the Window Threshold for dropping the packet.
+ *
+ * @param winThres Threshold count of the consecutive windows with packet drops
+ */
+ void setWinThres(int winThres);
+
+ /**
+ * Stop the threads running for this filter.
+ *
+ */
+ void stop();
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/PacketService.java b/core/api/src/main/java/org/onosproject/net/packet/PacketService.java
index 56889a5..21ecd49 100644
--- a/core/api/src/main/java/org/onosproject/net/packet/PacketService.java
+++ b/core/api/src/main/java/org/onosproject/net/packet/PacketService.java
@@ -19,6 +19,7 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.TrafficSelector;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -52,6 +53,22 @@
void removeProcessor(PacketProcessor processor);
/**
+ * Adds the specified filter to the list of packet filters.
+ * It will be added into the list in the order in which it is added.
+ *
+ * @param filter filter to be added
+ */
+ default void addFilter(PacketInFilter filter) {}
+
+
+ /**
+ * Removes the specified filter from the filters list.
+ *
+ * @param filter filter to be removed
+ */
+ default void removeFilter(PacketInFilter filter) {}
+
+ /**
* Returns priority bindings of all registered packet processor entries.
*
* @return list of existing packet processor entries
@@ -123,4 +140,20 @@
*/
void emit(OutboundPacket packet);
+ /**
+ * Get the list of packet filters present in ONOS.
+ *
+ * @return List of packet filters
+ */
+ default List<PacketInFilter> getFilters() {
+ return new ArrayList<>();
+ }
+
+ /**
+ * Clear all packet filters in one shot.
+ *
+ */
+ default void clearFilters() {}
+
+
}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/ArpPacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/ArpPacketClassifier.java
new file mode 100644
index 0000000..5aed044
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/ArpPacketClassifier.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+
+public class ArpPacketClassifier implements PacketInClassifier {
+
+ @Override
+ public boolean match(PacketContext packet) {
+
+ Ethernet eth = packet.inPacket().parsed();
+ if (eth != null && (eth.getEtherType() == Ethernet.TYPE_ARP)) {
+ ARP arpPacket = (ARP) eth.getPayload();
+ if (arpPacket.getOpCode() == ARP.OP_REQUEST) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/DefaultPacketInFilter.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/DefaultPacketInFilter.java
new file mode 100644
index 0000000..d628f80
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/DefaultPacketInFilter.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+import org.onosproject.net.packet.PacketInFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Objects;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.onlab.util.Tools.groupedThreads;
+
+/**
+ * Default implementation of a packet-in filter.
+ */
+public class DefaultPacketInFilter implements PacketInFilter {
+
+ /**
+ * Tracks the count of specific packet types (eg ARP, ND, DHCP etc)
+ * to be limited in the packet queue. This count always reflects the
+ * number of packets in the queue at any point in time
+ */
+ private AtomicInteger currentCounter = new AtomicInteger(0);
+
+ /**
+ * Tracks the number of continuous windows where the drop packet happens.
+ */
+ private AtomicInteger windowBlockCounter = new AtomicInteger(0);
+
+ /**
+ * Tracks the counter of the packet which are dropped.
+ */
+ private AtomicInteger overFlowCounter = new AtomicInteger(0);
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * Max Allowed packet rate beyond which the packet will be dropped
+ * within given window size.
+ */
+ private int pps = 100;
+
+ /**
+ * Window size which will be used for number of packets acceptable
+ * based on the accepted pps.
+ */
+ private int winSize = 500;
+
+ /**
+ * Guard time in seconds which will be enabled if there are continuous
+ * windows crossing winThres where the packet rate crosses the acceptable
+ * packet count calculated based on accepted pps.
+ * Guard time should be always greater then the the window size.
+ */
+ private int guardTime = 10;
+
+ /**
+ * Threshold of continuous windows where the packet drop happens post which
+ * the guardTime will be triggered and no future packet processing happens
+ * till the expiry of this guard time.
+ */
+ private int winThres = 10;
+
+
+ private int maxCounter;
+
+ private ScheduledExecutorService timerExecutor;
+
+ private ScheduledExecutorService windowUnblockExecutor;
+
+ private boolean windowBlocked;
+
+ private boolean packetProcessingBlocked;
+
+
+ /**
+ * Name of the counter.
+ */
+ private String counterName;
+
+ /**
+ * PacketInclassifier associated with this filter object.
+ */
+ private final PacketInClassifier classifier;
+
+
+
+ /**
+ * Only one filter object per packet type to be associated.
+ * Multiple filter types will result in undefined behavior.
+ * @param pps Rate at which the packet is accepted in packets per second
+ * @param winSize Size of window in milli seconds within which
+ * the packet rate will be analyzed
+ * @param guardTime Time duration in seconds for which the packet processing
+ * will be on hold if there is a continuous window where
+ * cross of the rate happens and that window count crosses
+ * winThres
+ * @param winThres Continuous window threshold after which gaurdTime will be
+ * activated
+ * @param counterName Name of the counter
+ * @param classifier Packet classification
+ */
+ public DefaultPacketInFilter(int pps, int winSize, int guardTime, int winThres,
+ String counterName, PacketInClassifier classifier) {
+ this.pps = pps;
+ this.winSize = winSize;
+ this.guardTime = guardTime;
+ this.winThres = winThres;
+ this.counterName = counterName;
+ this.classifier = classifier;
+ this.maxCounter = (pps * winSize) / 1000;
+ timerExecutor = Executors.newScheduledThreadPool(1,
+ groupedThreads("packet/packetfilter",
+ "packet-filter-timer-%d", log));
+
+ windowUnblockExecutor = Executors.newScheduledThreadPool(1,
+ groupedThreads("packet/packetfilter",
+ "packet-filter-unblocker-%d", log));
+ timerExecutor.scheduleAtFixedRate(new ClearWindowBlock(),
+ 0,
+ winSize,
+ TimeUnit.MILLISECONDS);
+
+
+ windowBlocked = false;
+ packetProcessingBlocked = false;
+
+ }
+
+
+
+ @Override
+ public FilterAction preProcess(PacketContext packet) {
+
+
+ maxCounter = (pps * winSize) / 1000;
+
+ // If pps is set then min value for maxCounter is 1
+ if (maxCounter == 0 && pps != 0) {
+ log.trace("{}: maxCounter set to 1 as was coming as 0", counterName);
+ maxCounter = 1;
+ }
+
+
+
+ if (!classifier.match(packet)) {
+ return FilterAction.FILTER_INVALID;
+ }
+
+ if (pps == 0 && maxCounter == 0) {
+ log.trace("{}: Filter is disabled", counterName);
+ return FilterAction.FILTER_DISABLED;
+ }
+ log.trace("{}: Preprocess called", counterName);
+
+ // Packet block checking should be done before windowBlocked checking
+ // otherwise there will be windows with packets while packet processing is suspended
+ // and that may break the existing check logic
+ if (packetProcessingBlocked) {
+ log.trace("{}: Packet processing is blocked for sometime", counterName);
+ return FilterAction.PACKET_BLOCKED;
+ }
+
+ if (windowBlocked) {
+ log.trace("{}: Packet processing is blocked for the window number: {}",
+ counterName, windowBlockCounter.get());
+ return FilterAction.WINDOW_BLOCKED;
+ }
+
+ if (currentCounter.getAndIncrement() < maxCounter) {
+ log.trace("{}: Packet is picked for processing with currentCounter: {} and maxCounter: {}",
+ counterName, currentCounter.get(), maxCounter);
+ return FilterAction.PACKET_ALLOW;
+ }
+ //Need to decrement the currentCounter and increment overFlowCounter
+ //Need to block the window and increment the window block counter
+ windowBlocked = true;
+ //TODO: Review this and the complete state machine
+ // If windowBlock crosses threshold then block packet processing for guard time
+ if (windowBlockCounter.incrementAndGet() > winThres) {
+ log.trace("{}: Packet processing blocked as current window crossed threshold " +
+ "currentWindowNumber: {} maxWindowNumber: {}",
+ counterName, windowBlockCounter.get(), winThres);
+ packetProcessingBlocked = true;
+ windowUnblockExecutor.schedule(new ClearPacketProcessingBlock(),
+ guardTime,
+ TimeUnit.SECONDS);
+ } else {
+ log.trace("{}: WindowBlockCounter: {} winThres: {}", counterName, windowBlockCounter.get(),
+ winThres);
+ }
+ //MT: Temp change in logic to branch the code - Rolled back
+ currentCounter.decrementAndGet();
+ if (overFlowCounter.incrementAndGet() < 0) {
+ overFlowCounter.set(0);
+ }
+ log.trace("{}: Overflow counter is: {}", counterName, overFlowCounter.get());
+ return FilterAction.PACKET_DENY;
+
+ }
+
+ @Override
+ public String name() {
+ return counterName;
+ }
+
+ @Override
+ public int pendingPackets() {
+ return currentCounter.get();
+ }
+
+ @Override
+ public int droppedPackets() {
+ return overFlowCounter.get();
+ }
+
+
+
+ @Override
+ public void setPps(int pps) {
+ this.pps = pps;
+ }
+
+ @Override
+ public void setWinSize(int winSize) {
+ this.winSize = winSize;
+ }
+
+ @Override
+ public void setGuardTime(int guardTime) {
+ this.guardTime = guardTime;
+ }
+
+ @Override
+ public void setWinThres(int winThres) {
+ this.winThres = winThres;
+ }
+
+ @Override
+ public void stop() {
+ timerExecutor.shutdown();
+ windowUnblockExecutor.shutdown();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DefaultPacketInFilter that = (DefaultPacketInFilter) o;
+ return pps == that.pps &&
+ winSize == that.winSize &&
+ guardTime == that.guardTime &&
+ winThres == that.winThres &&
+ counterName.equals(that.counterName) &&
+ classifier.equals(that.classifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(pps, winSize, guardTime, winThres, counterName, classifier);
+ }
+
+
+ private final class ClearWindowBlock implements Runnable {
+ @Override
+ public void run() {
+ // If window is not already blocked and there is at least one packet processed
+ // in that window then reset the window block counter:
+ if (!windowBlocked) {
+ log.trace("{}: WindowBlockCounter is reset as there was no blocking in current " +
+ "window with current windowBlockCounter: {}", counterName, windowBlockCounter.get());
+ windowBlockCounter.set(0);
+ }
+ if (currentCounter.get() == 0) {
+ //No packet processed in current window so do not change anything in the current state
+ log.trace("{}: No packets in the current window so not doing anything in ClearWindowBlock",
+ counterName);
+ return;
+ }
+
+ //Reset the counter and unblock the window
+ log.trace("{}: Current counter and windowBlocked is reset in ClearWindowBlock", counterName);
+ currentCounter.set(0);
+ windowBlocked = false;
+ }
+ }
+
+ private final class ClearPacketProcessingBlock implements Runnable {
+ @Override
+ public void run() {
+ //Reset the counter and unblock the window and packet processing
+ //CurrentCounter and windowBlocked counter setting is not required here
+ //Still setting to be on safer side
+ log.trace("{}: All blocks cleared in ClearPacketProcessingBlock", counterName);
+ currentCounter.set(0);
+ windowBlocked = false;
+ packetProcessingBlocked = false;
+ windowBlockCounter.set(0);
+ }
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Dhcp6DirectPacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Dhcp6DirectPacketClassifier.java
new file mode 100644
index 0000000..a320a44
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Dhcp6DirectPacketClassifier.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.DHCP6;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.UDP;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+public class Dhcp6DirectPacketClassifier implements PacketInClassifier {
+ private final Logger log = getLogger(getClass());
+ @Override
+ public boolean match(PacketContext packet) {
+
+ Ethernet eth = packet.inPacket().parsed();
+
+ if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
+ IPv6 ipv6Packet = (IPv6) eth.getPayload();
+
+ if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_UDP) {
+ UDP udpPacket = (UDP) ipv6Packet.getPayload();
+ //Directly connected host
+ if (udpPacket.getDestinationPort() == UDP.DHCP_V6_SERVER_PORT &&
+ udpPacket.getSourcePort() == UDP.DHCP_V6_CLIENT_PORT) {
+ DHCP6 dhcp6 = (DHCP6) udpPacket.getPayload();
+ if (dhcp6.getMsgType() == DHCP6.MsgType.SOLICIT.value()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Dhcp6IndirectPacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Dhcp6IndirectPacketClassifier.java
new file mode 100644
index 0000000..afb2c31
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Dhcp6IndirectPacketClassifier.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.BasePacket;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.DHCP6;
+import org.onlab.packet.UDP;
+import org.onlab.packet.dhcp.Dhcp6RelayOption;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+import org.slf4j.Logger;
+
+import java.util.Arrays;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+public class Dhcp6IndirectPacketClassifier implements PacketInClassifier {
+ private final Logger log = getLogger(getClass());
+
+ @Override
+ public boolean match(PacketContext packet) {
+
+ Ethernet eth = packet.inPacket().parsed();
+
+ if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
+ IPv6 ipv6Packet = (IPv6) eth.getPayload();
+
+ if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_UDP) {
+ UDP udpPacket = (UDP) ipv6Packet.getPayload();
+ //Indirectly connected host
+ if (udpPacket.getDestinationPort() == UDP.DHCP_V6_SERVER_PORT &&
+ udpPacket.getSourcePort() == UDP.DHCP_V6_SERVER_PORT &&
+ Arrays.equals(ipv6Packet.getDestinationAddress(),
+ Ip6Address.valueOf("ff02::1:2").toOctets())) {
+ DHCP6 relayMessage = (DHCP6) udpPacket.getPayload();
+ DHCP6 dhcp6 = (DHCP6) relayMessage.getOptions().stream()
+ .filter(opt -> opt instanceof Dhcp6RelayOption)
+ .map(BasePacket::getPayload)
+ .map(pld -> (DHCP6) pld)
+ .findFirst()
+ .orElse(null);
+
+ if (dhcp6.getMsgType() == DHCP6.MsgType.SOLICIT.value()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/DhcpPacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/DhcpPacketClassifier.java
new file mode 100644
index 0000000..1389c8c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/DhcpPacketClassifier.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.DHCP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.UDP;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+
+public class DhcpPacketClassifier implements PacketInClassifier {
+
+ @Override
+ public boolean match(PacketContext packet) {
+
+ Ethernet eth = packet.inPacket().parsed();
+
+ if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
+ IPv4 ipv4Packet = (IPv4) eth.getPayload();
+
+ if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
+ UDP udpPacket = (UDP) ipv4Packet.getPayload();
+
+ if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
+ udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
+ DHCP dhcp = (DHCP) udpPacket.getPayload();
+ if (dhcp.getPacketType() == DHCP.MsgType.DHCPDISCOVER) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Icmp6PacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Icmp6PacketClassifier.java
new file mode 100644
index 0000000..7dfa806
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/Icmp6PacketClassifier.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+public class Icmp6PacketClassifier implements PacketInClassifier {
+ private final Logger log = getLogger(getClass());
+ @Override
+ public boolean match(PacketContext packet) {
+ Ethernet eth = packet.inPacket().parsed();
+
+ if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
+ IPv6 ipv6Packet = (IPv6) eth.getPayload();
+
+ if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
+ ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
+ if (icmp6Packet.getIcmpType() == ICMP6.ECHO_REQUEST) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/IcmpPacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/IcmpPacketClassifier.java
new file mode 100644
index 0000000..501357c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/IcmpPacketClassifier.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP;
+import org.onlab.packet.IPv4;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+
+public class IcmpPacketClassifier implements PacketInClassifier {
+
+ @Override
+ public boolean match(PacketContext packet) {
+
+ Ethernet eth = packet.inPacket().parsed();
+
+ if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
+ IPv4 ipv4Packet = (IPv4) eth.getPayload();
+
+ if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_ICMP) {
+ ICMP icmpPacket = (ICMP) ipv4Packet.getPayload();
+ if (icmpPacket.getIcmpType() == ICMP.TYPE_ECHO_REQUEST) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/NAPacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/NAPacketClassifier.java
new file mode 100644
index 0000000..2dc653c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/NAPacketClassifier.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+
+public class NAPacketClassifier implements PacketInClassifier {
+
+ @Override
+ public boolean match(PacketContext packet) {
+
+ Ethernet eth = packet.inPacket().parsed();
+
+ if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
+ IPv6 ipv6Packet = (IPv6) eth.getPayload();
+ if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
+ ICMP6 icmp6 = (ICMP6) ipv6Packet.getPayload();
+ if (icmp6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/NSPacketClassifier.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/NSPacketClassifier.java
new file mode 100644
index 0000000..4d90ada
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/NSPacketClassifier.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.packet.packetfilter;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketInClassifier;
+
+public class NSPacketClassifier implements PacketInClassifier {
+
+ @Override
+ public boolean match(PacketContext packet) {
+
+ Ethernet eth = packet.inPacket().parsed();
+
+ if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
+ IPv6 ipv6Packet = (IPv6) eth.getPayload();
+ if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
+ ICMP6 icmp6 = (ICMP6) ipv6Packet.getPayload();
+ if (icmp6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/packet/packetfilter/package-info.java b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/package-info.java
new file mode 100644
index 0000000..2918caf
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/packet/packetfilter/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Packet filter classifier for various Packet types.
+ */
+package org.onosproject.net.packet.packetfilter;
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java
index 5a1dfd5..10fa7e2 100644
--- a/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java
@@ -69,4 +69,9 @@
@Override
public void emit(OutboundPacket packet) {
}
+
+ @Override
+ public List<PacketInFilter> getFilters() {
+ return null;
+ }
}
diff --git a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
index 6be6c54..c007eab 100644
--- a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
+++ b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
@@ -59,12 +59,17 @@
import org.onosproject.net.packet.PacketStoreDelegate;
import org.onosproject.net.provider.AbstractProviderRegistry;
import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.packet.PacketInFilter;
+import org.onosproject.net.packet.PacketInFilter.FilterAction;
import org.slf4j.Logger;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.groupedThreads;
@@ -74,6 +79,7 @@
import static org.onosproject.security.AppPermission.Type.PACKET_WRITE;
import static org.slf4j.LoggerFactory.getLogger;
+
/**
* Provides a basic implementation of the packet SB & NB APIs.
*/
@@ -122,6 +128,11 @@
private ApplicationId appId;
private NodeId localNodeId;
+ private List<PacketInFilter> filters = new CopyOnWriteArrayList<>();
+
+
+
+
@Activate
public void activate() {
eventHandlingExecutor = Executors.newSingleThreadExecutor(
@@ -190,6 +201,16 @@
}
@Override
+ public void addFilter(PacketInFilter filter) {
+ filters.add(filter);
+ }
+
+ @Override
+ public void removeFilter(PacketInFilter filter) {
+ filters.remove(filter);
+ }
+
+ @Override
public List<PacketProcessorEntry> getProcessors() {
checkPermission(PACKET_READ);
return ImmutableList.copyOf(processors);
@@ -364,6 +385,20 @@
store.emit(packet);
}
+ @Override
+ public List<PacketInFilter> getFilters() {
+ return ImmutableList.copyOf(filters);
+ }
+
+ @Override
+ public void clearFilters() {
+ for (PacketInFilter filter: filters) {
+ filter.stop();
+ }
+ filters.clear();
+ }
+
+
private void localEmit(OutboundPacket packet) {
Device device = deviceService.getDevice(packet.sendThrough());
if (device == null) {
@@ -391,8 +426,57 @@
super(provider);
}
+
+ /**
+ * Loops through all packet filters and checks if the filter is
+ * enabled and allowed to be processed.
+ * It increments the counter to track the pending packets to be
+ * processed based on the filter selected.
+ *
+ * @param context PackerContext holding the packet information
+ * @return FilterAction Action decided for the based on the filter applied
+ */
+ private FilterAction prePacketProcess(PacketContext context) {
+ FilterAction filterAction = FilterAction.FILTER_INVALID;
+ for (PacketInFilter filter: filters) {
+ filterAction = filter.preProcess(context);
+ if (filterAction == FilterAction.FILTER_DISABLED) {
+ if (log.isTraceEnabled()) {
+ log.trace("{}: filter is disabled during pre processing", filter.name());
+ }
+ continue;
+ }
+ if (filterAction == FilterAction.PACKET_DENY) {
+ if (log.isTraceEnabled()) {
+ log.trace("{}: overflow counter after dropping packet is: {}", filter.name(),
+ filter.droppedPackets());
+ }
+ break;
+ }
+ if (filterAction == FilterAction.PACKET_ALLOW) {
+ if (log.isTraceEnabled()) {
+ log.trace("{}: counter after picked for processing is: {}", filter.name(),
+ filter.pendingPackets());
+ }
+ break;
+ }
+ }
+ return filterAction;
+ }
+
+
@Override
public void processPacket(PacketContext context) {
+
+ FilterAction filterAction = prePacketProcess(context);
+
+ if (filterAction == FilterAction.PACKET_DENY) {
+ if (log.isTraceEnabled()) {
+ log.trace("The packet is dropped as crossed the maxcount");
+ }
+ return;
+ }
+
// TODO filter packets sent to processors based on registrations
for (ProcessorEntry entry : processors) {
try {
@@ -414,7 +498,6 @@
}
}
}
-
}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
index 49b5f64..24105ff 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
@@ -50,6 +50,7 @@
import org.onosproject.net.packet.PacketRequest;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.packet.PacketStoreDelegate;
+
import org.onosproject.net.provider.ProviderId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/modules.defs b/modules.defs
index ae4486a..052e7ee 100644
--- a/modules.defs
+++ b/modules.defs
@@ -248,6 +248,7 @@
'//apps/mcast:onos-apps-mcast-oar',
'//apps/layout:onos-apps-layout-oar',
'//apps/imr:onos-apps-imr-oar',
+ '//apps/packet-throttle:onos-apps-packet-throttle-oar',
]
PROTOCOL_APPS = [