From 09220c20d74cc008c4d8319a1ed4a6be2518f63c Mon Sep 17 00:00:00 2001 From: Pier Luigi Date: Thu, 14 Sep 2017 22:00:30 +0200 Subject: [PATCH] [ONOS-7003] Policer implementation Changes: - Introduce trafficcontrol package - Add policer - Add policer id - Add policing resource - Add token bucket - Add unit tests Change-Id: I70065d58d3df7033e67a81943ebf60187c33c3e2 --- .../trafficcontrol/DefaultPolicer.java | 260 +++++++++++++ .../trafficcontrol/DefaultTokenBucket.java | 179 +++++++++ .../net/behaviour/trafficcontrol/Policer.java | 262 +++++++++++++ .../trafficcontrol/PolicerEntry.java | 55 +++ .../behaviour/trafficcontrol/PolicerId.java | 88 +++++ .../trafficcontrol/PolicingResource.java | 89 +++++ .../behaviour/trafficcontrol/TokenBucket.java | 163 +++++++++ .../trafficcontrol/TokenBucketEntry.java | 41 +++ .../trafficcontrol/package-info.java | 20 + .../trafficcontrol/PolicerIdTest.java | 139 +++++++ .../behaviour/trafficcontrol/PolicerTest.java | 343 ++++++++++++++++++ .../trafficcontrol/PolicingResourceTest.java | 100 +++++ .../trafficcontrol/TokenBucketTest.java | 179 +++++++++ .../trafficcontrol/package-info.java | 20 + 14 files changed, 1938 insertions(+) create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultPolicer.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultTokenBucket.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/Policer.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerEntry.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerId.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResource.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucket.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketEntry.java create mode 100644 core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java create mode 100644 core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerIdTest.java create mode 100644 core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerTest.java create mode 100644 core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResourceTest.java create mode 100644 core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketTest.java create mode 100644 core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultPolicer.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultPolicer.java new file mode 100644 index 0000000000..d375f9d198 --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultPolicer.java @@ -0,0 +1,260 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import java.util.Collection; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of the policer interface. + */ +@Beta +public final class DefaultPolicer implements Policer, PolicerEntry { + + // Immutable parameters + private final DeviceId deviceId; + private final ApplicationId applicationId; + private final PolicerId policerId; + private final boolean colorAware; + private final Unit unit; + private final Collection tokenBuckets; + private final String description; + + // Mutable parameters + private long referenceCount; + private long processedPackets; + private long processedBytes; + private long life; + + private DefaultPolicer(DeviceId dId, ApplicationId aId, PolicerId pId, + boolean cA, Unit u, Collection tB, + String d) { + deviceId = dId; + applicationId = aId; + policerId = pId; + colorAware = cA; + unit = u; + tokenBuckets = tB; + description = d; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public ApplicationId applicationId() { + return applicationId; + } + + @Override + public PolicerId policerId() { + return policerId; + } + + @Override + public boolean isColorAware() { + return colorAware; + } + + @Override + public Unit unit() { + return unit; + } + + @Override + public Collection tokenBuckets() { + return tokenBuckets; + } + + @Override + public String description() { + return description; + } + + @Override + public long referenceCount() { + return referenceCount; + } + + @Override + public void setReferenceCount(long count) { + referenceCount = count; + } + + @Override + public long processedPackets() { + return processedPackets; + } + + @Override + public void setProcessedPackets(long packets) { + processedPackets = packets; + } + + @Override + public long processedBytes() { + return processedBytes; + } + + @Override + public void setProcessedBytes(long bytes) { + processedBytes = bytes; + } + + @Override + public long life() { + return life; + } + + @Override + public void setLife(long l) { + life = l; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("appId", applicationId()) + .add("id", policerId()) + .add("isColorAware", isColorAware()) + .add("unit", unit()) + .add("tokenBuckets", tokenBuckets()) + .add("description", description()) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DefaultPolicer that = (DefaultPolicer) o; + return Objects.equal(policerId, that.policerId); + } + + @Override + public int hashCode() { + return policerId.hashCode(); + } + + /** + * Returns a new builder reference. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Implementation of the policer builder interface. + */ + public static final class Builder implements Policer.Builder { + + private DeviceId deviceId; + private ApplicationId applicationId; + private PolicerId policerId; + // Default to unaware + private boolean colorAware = false; + // Default to MBps + private Unit unit = Unit.MB_PER_SEC; + private Collection tokenBuckets; + private String description = ""; + + @Override + public Policer.Builder forDeviceId(DeviceId dId) { + deviceId = dId; + return this; + } + + @Override + public Policer.Builder fromApp(ApplicationId appId) { + applicationId = appId; + return this; + } + + @Override + public Policer.Builder withId(PolicerId id) { + policerId = id; + return this; + } + + @Override + public Policer.Builder colorAware(boolean isColorAware) { + colorAware = isColorAware; + return this; + } + + @Override + public Policer.Builder withUnit(Unit u) { + unit = u; + return this; + } + + @Override + public Policer.Builder withPolicingResource(PolicingResource policingResource) { + policerId = policingResource.policerId(); + deviceId = policingResource.connectPoint().deviceId(); + return this; + } + + @Override + public Policer.Builder withTokenBuckets(Collection tB) { + tokenBuckets = ImmutableSet.copyOf(tB); + return this; + } + + @Override + public Policer.Builder withDescription(String d) { + description = d; + return this; + } + + @Override + public DefaultPolicer build() { + // Not null condition on some mandatory parameters + checkNotNull(deviceId, "Must specify a deviceId"); + checkNotNull(applicationId, "Must specify an application id"); + checkNotNull(policerId, "Must specify a policer id"); + checkNotNull(unit, "Must specify a unit for the policer"); + checkNotNull(tokenBuckets, "Must have token buckets"); + checkNotNull(description, "Must have a description"); + + // Verify argument conditions + checkArgument(!tokenBuckets.isEmpty(), "Must have at least one token bucket"); + + // Finally we build the policer + return new DefaultPolicer(deviceId, applicationId, policerId, + colorAware, unit, tokenBuckets, + description); + } + } +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultTokenBucket.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultTokenBucket.java new file mode 100644 index 0000000000..f3920b23bf --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/DefaultTokenBucket.java @@ -0,0 +1,179 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_CLASS; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_PRECEDENCE; + +/** + * Default implementation of the token bucket interface. + */ +@Beta +public final class DefaultTokenBucket implements TokenBucket, TokenBucketEntry { + + // Immutable parameters + private final long rate; + private final long burstSize; + private final Action action; + private final short dscp; + + // Mutable parameters + private long processedPackets; + private long processedBytes; + + private DefaultTokenBucket(long r, long bS, Action a, short d) { + rate = r; + burstSize = bS; + action = a; + dscp = d; + } + + @Override + public long rate() { + return rate; + } + + @Override + public long burstSize() { + return burstSize; + } + + @Override + public Action action() { + return action; + } + + @Override + public short dscp() { + return dscp; + } + + @Override + public long processedPackets() { + return processedPackets; + } + + @Override + public void setProcessedPackets(long packets) { + processedPackets = packets; + } + + @Override + public long processedBytes() { + return processedBytes; + } + + @Override + public void setProcessedBytes(long bytes) { + processedBytes = bytes; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("rate", rate()) + .add("burstSize", burstSize()) + .add("action", action()) + .add("dscp", dscp()).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DefaultTokenBucket that = (DefaultTokenBucket) o; + return rate == that.rate && + burstSize == that.burstSize && + Objects.equal(action, that.action) && + dscp == that.dscp; + } + + @Override + public int hashCode() { + return Objects.hashCode(rate, burstSize, action, dscp); + } + + /** + * Returns a new builder reference. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Implementation of the token bucket builder interface. + */ + public static final class Builder implements TokenBucket.Builder { + + private long rate; + // Default to 2 * MTU + private long burstSize = 2 * 1500; + private Action action; + private short dscp; + + @Override + public TokenBucket.Builder withRate(long r) { + rate = r; + return this; + } + + @Override + public TokenBucket.Builder withBurstSize(long bS) { + burstSize = bS; + return this; + } + + @Override + public TokenBucket.Builder withAction(Action a) { + action = a; + return this; + } + + @Override + public TokenBucket.Builder withDscp(short d) { + dscp = d; + return this; + } + + @Override + public DefaultTokenBucket build() { + // Not null condition on the action + checkNotNull(action, "Must specify an action"); + + // If action is based on DSCP modification + if (action == DSCP_CLASS || action == DSCP_PRECEDENCE) { + // dscp should be a value between 0 and 255 + checkArgument(dscp >= MIN_DSCP && dscp <= MAX_DSCP, "Dscp is out of range"); + } + + // Finally we build the token bucket + return new DefaultTokenBucket(rate, burstSize, action, dscp); + } + } +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/Policer.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/Policer.java new file mode 100644 index 0000000000..af170504ae --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/Policer.java @@ -0,0 +1,262 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import java.util.Collection; + +/** + * Generic abstraction for a policer which can mark and/or discard ingress + * traffic. Each policer is made up of an identifier and a set of attributes + * which defines the type of policer. + *

+ * For example a policer specifying only a single token bucket, it will model + * a simple drop policer or a marker policer. For the former, the traffic in + * profile is green or red if it is out-of-profile. The latter envisages green + * or yellow traffic. Currently there is no RFC for this kind of policer but + * some vendors implement this model. + *

+ * RFC 2697 can be modelled creating a policer with a collection of two + * token buckets: [0] CIR + CBS; [1] CIR + EBS. In this way, it is possible + * to create a policer single rate three color marker. + *

+ * RFC 2698 and P4 meter are modelled in the same way but different attributes + * for the token buckets: [0] PIR + PBS; [2] CIR + CBS. In this way, we can + * create a policer two rate three color marker. + *

+ * How these policers will be implemented depends on the specific technology + * used in the device. For an OF device, the single rate two color marker it + * could be implemented with a simple meter with a drop band. + *

+ * Following abstraction has been designed to cover several types of policing + * that have been specified during the years. However, this does not assure that + * used technology will support all possible scenarios. For example, OF limitations + * are well known in this field and implementations are even worse. + */ +@Beta +public interface Policer { + + /** + * Unit of traffic used by this policer. + */ + enum Unit { + /** + * Packets per second. + */ + PKTS_PER_SEC, + /** + * Byte per second. + */ + B_PER_SEC, + /** + * KByte per second. + */ + KB_PER_SEC, + /** + * MByte per second. + */ + MB_PER_SEC + } + + /** + * The device of this policer, where policing + * is applied. + * + * @return the device id + */ + DeviceId deviceId(); + + /** + * The id of the application which created this policer. + * + * @return the identifier of the application + */ + ApplicationId applicationId(); + + /** + * Returns how many are referencing this policer. + * + * Availability of this information depends on the + * technology used for the implementation of this policer. + * + * @return the reference count + */ + long referenceCount(); + + /** + * Stats which reports how many packets have been + * processed so far. + * + * Availability of this information depends on the + * technology used for the implementation of this policer. + * + * @return the processed packets + */ + long processedPackets(); + + /** + * Stats which reports how many bytes have been + * processed so far. + * + * Availability of this information depends on the + * technology used for the implementation of this policer. + * + * @return the processed bytes + */ + long processedBytes(); + + /** + * The id of this policer. + * + * @return the policer id + */ + PolicerId policerId(); + + /** + * Indicates if this policer is aware of the marking indication + * in the ethernet frames. + * + * TODO Understand for the future how it is implemented by the vendors + * + * @return true if this policer is color aware. + */ + boolean isColorAware(); + + /** + * The lifetime in seconds of this policer. + * + * Availability of this information depends on the + * technology used for the implementation of this policer. + * + * @return number of seconds + */ + long life(); + + /** + * The unit used within this policer. + * + * @return the unit + */ + Unit unit(); + + /** + * The token buckets used within this policer. + * + * @return the list of the token buckets + */ + Collection tokenBuckets(); + + /** + * Brief description of this policer. + * + * @return human readable description + */ + String description(); + + /** + * A policer builder. + */ + interface Builder { + + /** + * Assigns the device for this policer. + *

+ * Note: mandatory setter for this builder + *

+ * @param deviceId a device id + * @return this + */ + Builder forDeviceId(DeviceId deviceId); + + /** + * Assigns the application that built this policer. + *

+ * Note: mandatory setter for this builder + *

+ * @param appId an application id + * @return this + */ + Builder fromApp(ApplicationId appId); + + /** + * Assigns the id to this policer. + *

+ * Note: mandatory setter for this builder + *

+ * @param id an identifier + * @return this + */ + Builder withId(PolicerId id); + + /** + * Sets this policer to be color aware. + * Defaults to false. + * + * @param isColorAware if it is color aware or not + * @return this + */ + Builder colorAware(boolean isColorAware); + + /** + * Assigns the unit to use for this policer. + * Defaults to MB/s. + * + * @param unit a unit + * @return this + */ + Builder withUnit(Unit unit); + + /** + * Assigns policer id and device id for this policer. + * + * @param policingResource the policing resource + * @return this + */ + Builder withPolicingResource(PolicingResource policingResource); + + /** + * Assigns token buckets for this policer. + *

+ * Note: at least one token bucket + *

+ * @param tokenBuckets the collection of token buckets + * @return this + */ + Builder withTokenBuckets(Collection tokenBuckets); + + /** + * Assigns description for this policer. + * Default is empty description. + * + * @param description the description + * @return this + */ + Builder withDescription(String description); + + /** + * Builds the policer based on the specified parameters + * when possible. + * + * @return a policer + */ + Policer build(); + } + +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerEntry.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerEntry.java new file mode 100644 index 0000000000..0f019efd67 --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerEntry.java @@ -0,0 +1,55 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.annotations.Beta; + +/** + * Represents a stored policer. + */ +@Beta +public interface PolicerEntry { + + /** + * Set the amount of time the policer has existed in seconds. + * + * @param life number of seconds + */ + void setLife(long life); + + /** + * Sets how many are using this policer. + * + * @param count a reference count. + */ + void setReferenceCount(long count); + + /** + * Updates the number of packets seen by this policer. + * + * @param packets a packet count. + */ + void setProcessedPackets(long packets); + + /** + * Updates the number of bytes seen by the policer. + * + * @param bytes a byte counter. + */ + void setProcessedBytes(long bytes); + +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerId.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerId.java new file mode 100644 index 0000000000..c373dbeb6e --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicerId.java @@ -0,0 +1,88 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + + +import com.google.common.annotations.Beta; +import org.onlab.util.Identifier; + +import java.net.URI; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Unique identifier for an ONOS Policer {@link org.onosproject.net.behaviour.trafficcontrol.Policer}. + * It uniquely identifies a Policer in the scope of a single device inside ONOS. There may not be any + * correspondence with the identifiers of the technology implementing the Policer in the device. + * Mapping (if necessary) is left to the specific implementation. + */ +@Beta +public final class PolicerId extends Identifier { + + /** + * Represents either no id, or an unspecified id. + */ + public static final PolicerId NONE = policerId("none:none"); + + private static final int POLICER_ID_MAX_LENGTH = 1024; + + private final URI uri; + + // Not allowed + private PolicerId(URI u) { + super(u.toString()); + uri = u; + } + + // Needed for serialization + private PolicerId() { + super(); + uri = null; + } + + /** + * Creates a policer id using the supplied URI. + * + * @param uri policer id URI + * @return PolicerId + */ + public static PolicerId policerId(URI uri) { + return new PolicerId(uri); + } + + /** + * Creates a policer id using the supplied URI string. + * + * @param string policer id URI string + * @return PolicerID + */ + public static PolicerId policerId(String string) { + checkArgument(string.length() <= POLICER_ID_MAX_LENGTH, + "URI string exceeds maximum length " + POLICER_ID_MAX_LENGTH); + return policerId(URI.create(string)); + } + + /** + * Returns the backing URI. + * + * @return backing URI + */ + public URI uri() { + return uri; + } + +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResource.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResource.java new file mode 100644 index 0000000000..29ab25834c --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResource.java @@ -0,0 +1,89 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.NetworkResource; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction which encapsulates policer + * data to be used as network resource. + */ +@Beta +public final class PolicingResource implements NetworkResource { + + // The policer id identifying this resource + private final PolicerId policerId; + // The connect point where the policer applies + private final ConnectPoint connectPoint; + + public PolicingResource(PolicerId pId, ConnectPoint cP) { + checkNotNull(pId, "Must specify a policer id"); + checkNotNull(cP, "Must specify a connect point"); + policerId = pId; + connectPoint = cP; + } + + /** + * Return the policer id of this resource. + * + * @return the policer id + */ + public PolicerId policerId() { + return policerId; + } + + /** + * Returns the connect point of this resource. + * + * @return the connect point + */ + public ConnectPoint connectPoint() { + return connectPoint; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", policerId()) + .add("connectPoint", connectPoint()).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PolicingResource that = (PolicingResource) o; + return Objects.equal(policerId, that.policerId) && + Objects.equal(connectPoint, that.connectPoint); + } + + @Override + public int hashCode() { + return Objects.hashCode(policerId, connectPoint); + } + +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucket.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucket.java new file mode 100644 index 0000000000..a86466b0cb --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucket.java @@ -0,0 +1,163 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.annotations.Beta; + +/** + * Generic abstraction for a token bucket which can mark and/or discard + * traffic. Each token bucket in ONOS is made up of a set of attributes which + * identifies the type. + */ +@Beta +public interface TokenBucket { + + /** + * Upper bound for DSCP. + */ + short MAX_DSCP = 255; + /** + * Lower bound for DSCP. + */ + short MIN_DSCP = 0; + + /** + * Action applied to the exceeding traffic. + * Action depends on the tocken bucket type + */ + enum Action { + /** + * Drop action. + */ + DROP, + /** + * Marking increases DSCP drop precedence. + */ + DSCP_PRECEDENCE, + /** + * Marking sets DSCP class. + */ + DSCP_CLASS, + /** + * Marking sets Drop Elegible Indicator. + */ + DEI + } + + /** + * Rate of traffic subject to the SLAs + * specified for this token bucket. + * + * @return the rate value + */ + long rate(); + + /** + * Maximum burst size subject to the SLAs + * specified for this token bucket. + * + * @return the burst size in bytes + */ + long burstSize(); + + /** + * Action used by this token bucket + * for the exceeding traffic. + * + * @return the type of action + */ + Action action(); + + /** + * Dscp value, it meaning depends on the used marking. + * + * @return the dscp value for this token bucket + */ + short dscp(); + + /** + * Stats which reports how many packets have been + * processed so far. + * + * Availability of this information depends on the + * technology used for the implementation of the policer. + * + * @return the processed packets + */ + long processedPackets(); + + /** + * Stats which reports how many bytes have been + * processed so far. + * + * Availability of this information depends on the + * technology used for the implementation of the policer. + * + * @return the processed bytes + */ + long processedBytes(); + + /** + * Token bucket builder. + */ + interface Builder { + + /** + * Assigns the rate to this token bucket. + * + * @param rate a rate value + * @return this + */ + Builder withRate(long rate); + + /** + * Assigns the burst size to this token bucket. + * Default to 2 * 1500 bytes. + * + * @param burstSize a burst size + * @return this + */ + Builder withBurstSize(long burstSize); + + /** + * Assigns the action to this token bucket. + *

+ * Note: mandatory setter for this builder + *

+ * @param action an action + * @return this + */ + Builder withAction(Action action); + + /** + * Assigns the dscp value to this token bucket. + * + * @param dscp a dscp value + * @return this + */ + Builder withDscp(short dscp); + + /** + * Builds the token bucket based on the specified + * parameters when possible. + * + * @return a token bucket + */ + TokenBucket build(); + + } +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketEntry.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketEntry.java new file mode 100644 index 0000000000..00ca270c65 --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketEntry.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.annotations.Beta; + +/** + * Represents a stored token bucket. + */ +@Beta +public interface TokenBucketEntry { + + /** + * Updates the number of packets seen by this token bucket. + * + * @param packets a packet count. + */ + void setProcessedPackets(long packets); + + /** + * Updates the number of bytes seen by this token bucket. + * + * @param bytes a byte counter. + */ + void setProcessedBytes(long bytes); + +} diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java new file mode 100644 index 0000000000..188f3de5ba --- /dev/null +++ b/core/api/src/main/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * Traffic control behaviors and related classes. + */ +package org.onosproject.net.behaviour.trafficcontrol; diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerIdTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerIdTest.java new file mode 100644 index 0000000000..883f40dae8 --- /dev/null +++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerIdTest.java @@ -0,0 +1,139 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.base.Strings; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onlab.junit.ImmutableClassChecker; + +import java.net.URI; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; + +/** + * Test class for PolicerId. + */ +public class PolicerIdTest { + + // Test scheme + private static final String FOO_SCHEME = "foo"; + // OpenFlow scheme + private static final String OF_SCHEME = "of"; + // Some test ids + private static final Short ONE = 1; + private static final Short TWO = 15; + private static final String A = "A"; + private static final String LA = "a"; + + /** + * Test policer id creation from URI. + */ + @Test + public void testfromUriCreation() { + // Create URI representing the id + URI uriOne = URI.create(OF_SCHEME + ":" + Integer.toHexString(ONE)); + // Create policer id + PolicerId one = PolicerId.policerId(uriOne); + // Verify proper creation + assertThat(one, notNullValue()); + assertThat(one.id(), is(uriOne.toString().toLowerCase())); + assertThat(one.uri(), is(uriOne)); + } + + /** + * Test policer id creation from string. + */ + @Test + public void testfromStringCreation() { + // Create String representing the id + String stringTwo = OF_SCHEME + ":" + Integer.toHexString(TWO); + // Create policer id + PolicerId two = PolicerId.policerId(stringTwo); + // Verify proper creation + assertThat(two, notNullValue()); + assertThat(two.id(), is(stringTwo)); + assertThat(two.uri(), is(URI.create(stringTwo))); + } + + /** + * Exception expected to raise when creating a wrong policer id. + */ + @Rule + public ExpectedException exceptionWrongId = ExpectedException.none(); + + /** + * Test wrong creation of a policer id. + */ + @Test + public void testWrongCreation() { + // Build not allowed string + String wrongString = Strings.repeat("x", 1025); + // Define expected exception + exceptionWrongId.expect(IllegalArgumentException.class); + // Create policer id + PolicerId.policerId(wrongString); + } + + /** + * Test equality between policer ids. + */ + @Test + public void testEquality() { + // Create URI representing the id one + URI uriOne = URI.create(OF_SCHEME + ":" + Integer.toHexString(ONE)); + // Create String representing the id one + String stringOne = OF_SCHEME + ":" + Integer.toHexString(ONE); + // Create String representing the id two + String stringTwo = OF_SCHEME + ":" + Integer.toHexString(TWO); + // Create String representing the id A + String stringA = FOO_SCHEME + ":" + A; + // Create String representing the id LA + String stringLA = FOO_SCHEME + ":" + LA; + // Create policer id one + PolicerId one = PolicerId.policerId(uriOne); + // Create policer id one + PolicerId copyOfOne = PolicerId.policerId(stringOne); + // Verify equality + assertEquals(one, copyOfOne); + // Create a different policer id + PolicerId two = PolicerId.policerId(stringTwo); + // Verify not equals + assertNotEquals(two, one); + assertNotEquals(two, copyOfOne); + // Create policer id A + PolicerId a = PolicerId.policerId(A); + // Create policer id LA + PolicerId la = PolicerId.policerId(LA); + // Verify not equals + assertNotEquals(a, la); + } + + /** + * Tests immutability of PolicerId. + */ + @Test + public void testImmutability() { + ImmutableClassChecker.assertThatClassIsImmutable(PolicerId.class); + } + +} diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerTest.java new file mode 100644 index 0000000000..142f962852 --- /dev/null +++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerTest.java @@ -0,0 +1,343 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import com.google.common.collect.ImmutableList; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onosproject.TestApplicationId; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; +import static org.onosproject.net.behaviour.trafficcontrol.Policer.Unit.KB_PER_SEC; +import static org.onosproject.net.behaviour.trafficcontrol.Policer.Unit.MB_PER_SEC; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DROP; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_CLASS; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_PRECEDENCE; + +/** + * Test class for policer implementation. + */ +public class PolicerTest { + + // Fake Application Id + private static final ApplicationId FOO_APP_ID = new TestApplicationId("foo"); + // Connect points + private static final String SDID1 = "of:00000000000001"; + private static final DeviceId DID1 = DeviceId.deviceId(SDID1); + // OpenFlow scheme + private static final String OF_SCHEME = "of"; + // Policers identifiers + private static final String SID1 = OF_SCHEME + ":" + Integer.toHexString(1); + private static final PolicerId ID1 = PolicerId.policerId(SID1); + private static final String SID2 = OF_SCHEME + ":" + Integer.toHexString(2); + private static final PolicerId ID2 = PolicerId.policerId(SID2); + private static final String SID3 = OF_SCHEME + ":" + Integer.toHexString(3); + private static final PolicerId ID3 = PolicerId.policerId(SID3); + private static final String SID4 = OF_SCHEME + ":" + Integer.toHexString(4); + private static final PolicerId ID4 = PolicerId.policerId(SID4); + private static final String SID5 = OF_SCHEME + ":" + Integer.toHexString(5); + private static final PolicerId ID5 = PolicerId.policerId(SID5); + private static final String SID6 = OF_SCHEME + ":" + Integer.toHexString(6); + private static final PolicerId ID6 = PolicerId.policerId(SID6); + private static final String SID7 = OF_SCHEME + ":" + Integer.toHexString(7); + private static final PolicerId ID7 = PolicerId.policerId(SID7); + private static final String SID8 = OF_SCHEME + ":" + Integer.toHexString(8); + private static final PolicerId ID8 = PolicerId.policerId(SID8); + private static final String SID9 = OF_SCHEME + ":" + Integer.toHexString(9); + private static final PolicerId ID9 = PolicerId.policerId(SID9); + + /** + * Test block traffic policer. + */ + @Test + public void testBlockCreation() { + // Create a block traffic token bucket + TokenBucket tokenBucket = DefaultTokenBucket.builder() + .withBurstSize(0) + .withAction(DROP) + .build(); + // Create a policer with above token bucket + Policer policer = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID1) + .withTokenBuckets(ImmutableList.of(tokenBucket)) + .build(); + // Assert on device id + assertThat(policer.deviceId(), is(DID1)); + // Assert on app id + assertThat(policer.applicationId(), is(FOO_APP_ID)); + // Assert on policer id + assertThat(policer.policerId(), is(ID1)); + // It is not color aware + assertFalse(policer.isColorAware()); + // Unit is Mbps + assertThat(policer.unit(), is(MB_PER_SEC)); + // One token bucket + assertThat(policer.tokenBuckets().size(), is(1)); + // One token bucket equals to tokenBucket + assertTrue(policer.tokenBuckets().contains(tokenBucket)); + } + + /** + * Test simple drop policer. + */ + @Test + public void testDropCreation() { + // Create a drop traffic token bucket at 1MB/s + TokenBucket tokenBucket = DefaultTokenBucket.builder() + .withRate(1) + .withAction(DROP) + .build(); + // Create a policer with above token bucket + Policer policer = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID2) + .withTokenBuckets(ImmutableList.of(tokenBucket)) + .build(); + // Assert on device id + assertThat(policer.deviceId(), is(DID1)); + // Assert on app id + assertThat(policer.applicationId(), is(FOO_APP_ID)); + // Assert on policer id + assertThat(policer.policerId(), is(ID2)); + // It is not color aware + assertFalse(policer.isColorAware()); + // Unit is Mbps + assertThat(policer.unit(), is(MB_PER_SEC)); + // One token bucket + assertThat(policer.tokenBuckets().size(), is(1)); + // One token bucket equals to tokenBucket + assertTrue(policer.tokenBuckets().contains(tokenBucket)); + } + + /** + * Test simple mark policer. + */ + @Test + public void testMarkCreation() { + // Create a drop traffic token bucket at 1MB/s + TokenBucket tokenBucket = DefaultTokenBucket.builder() + .withRate(1) + .withAction(DSCP_PRECEDENCE) + .withDscp((short) 2) + .build(); + // Create a policer with above token bucket + Policer policer = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID3) + .withTokenBuckets(ImmutableList.of(tokenBucket)) + .build(); + // Assert on device id + assertThat(policer.deviceId(), is(DID1)); + // Assert on app id + assertThat(policer.applicationId(), is(FOO_APP_ID)); + // Assert on policer id + assertThat(policer.policerId(), is(ID3)); + // It is not color aware + assertFalse(policer.isColorAware()); + // Unit is Mbps + assertThat(policer.unit(), is(MB_PER_SEC)); + // One token bucket + assertThat(policer.tokenBuckets().size(), is(1)); + // One token bucket equals to tokenBucket + assertTrue(policer.tokenBuckets().contains(tokenBucket)); + } + + /** + * Test single rate three colors scenario (RFC 2697). + */ + @Test + public void testSingleRateThreeColors() { + // Create token bucket for committed rate + TokenBucket crTokenBucket = DefaultTokenBucket.builder() + .withRate(1) + .withAction(DSCP_PRECEDENCE) + .withDscp((short) 2) + .build(); + // Create token bucket for excess rate + TokenBucket erTokenBucket = DefaultTokenBucket.builder() + .withRate(1) + .withBurstSize(4 * 1500) + .withAction(DROP) + .build(); + // Create a policer with above token buckets + Policer policer = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID4) + // The order is important + .withTokenBuckets(ImmutableList.of(crTokenBucket, erTokenBucket)) + .build(); + // Assert on device id + assertThat(policer.deviceId(), is(DID1)); + // Assert on app id + assertThat(policer.applicationId(), is(FOO_APP_ID)); + // Assert on policer id + assertThat(policer.policerId(), is(ID4)); + // It is not color aware + assertFalse(policer.isColorAware()); + // Unit is Mbps + assertThat(policer.unit(), is(MB_PER_SEC)); + // Two token buckets + assertThat(policer.tokenBuckets().size(), is(2)); + // One token bucket equals to crTokenBucket + assertTrue(policer.tokenBuckets().contains(crTokenBucket)); + // One token bucket equals to erTokenBucket + assertTrue(policer.tokenBuckets().contains(erTokenBucket)); + } + + /** + * Test two rates three colors scenario (RFC 2698 and P4 meter). + */ + @Test + public void testTwoRatesThreeColors() { + // Create token bucket for peak rate at 10Mb/s + TokenBucket prTokenBucket = DefaultTokenBucket.builder() + // (10 * 1000)/8 ---> 1250KB/s + .withRate(1250) + .withBurstSize(10 * 1500) + .withAction(DROP) + .build(); + // Create token bucket for committed rate at 1Mb/s + TokenBucket crTokenBucket = DefaultTokenBucket.builder() + // (1 * 1000)/8 ---> 125KB/s + .withRate(125) + .withAction(DSCP_CLASS) + .withDscp((short) 10) + .build(); + // Create a policer with above token buckets + Policer policer = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID5) + .withUnit(KB_PER_SEC) + // The order is important + .withTokenBuckets(ImmutableList.of(prTokenBucket, crTokenBucket)) + .build(); + // Assert on device id + assertThat(policer.deviceId(), is(DID1)); + // Assert on app id + assertThat(policer.applicationId(), is(FOO_APP_ID)); + // Assert on policer id + assertThat(policer.policerId(), is(ID5)); + // It is not color aware + assertFalse(policer.isColorAware()); + // Unit is Mbps + assertThat(policer.unit(), is(KB_PER_SEC)); + // Two token buckets + assertThat(policer.tokenBuckets().size(), is(2)); + // One token bucket equals to prTokenBucket + assertTrue(policer.tokenBuckets().contains(prTokenBucket)); + // One token bucket equals to crTokenBucket + assertTrue(policer.tokenBuckets().contains(crTokenBucket)); + } + + /** + * Exception expected to raise when creating a policer with null params. + */ + @Rule + public ExpectedException exceptionNullParam = ExpectedException.none(); + + /** + * Test creation with null parameters. + */ + @Test + public void testNullParam() { + // Define expected exception + exceptionNullParam.expect(NullPointerException.class); + // Invalid policer, device id is not defined + DefaultPolicer.builder() + .fromApp(FOO_APP_ID) + .withId(ID6) + .build(); + } + + /** + * Exception expected to raise when creating a policer without token buckets. + */ + @Rule + public ExpectedException exceptionNoTokenBuckets = ExpectedException.none(); + + /** + * Test creation without token buckets. + */ + @Test + public void testNoTokenBuckets() { + // Define expected exception + exceptionNoTokenBuckets.expect(IllegalArgumentException.class); + // Invalid policer, no token buckets + DefaultPolicer.builder() + .fromApp(FOO_APP_ID) + .withId(ID7) + .forDeviceId(DID1) + .withTokenBuckets(ImmutableList.of()) + .build(); + } + + /** + * Test equality between policers. + */ + @Test + public void testEqualilty() { + // Create a block traffic token bucket + TokenBucket blockTokenBucket = DefaultTokenBucket.builder() + .withBurstSize(0) + .withAction(DROP) + .build(); + // Create a mark traffic token bucket + TokenBucket markTokenBucket = DefaultTokenBucket.builder() + .withBurstSize(0) + .withAction(DSCP_CLASS) + .withDscp((short) 10) + .build(); + // Create first policer + Policer policerOne = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID8) + .withTokenBuckets(ImmutableList.of(blockTokenBucket)) + .build(); + // Create second policer + Policer policerTwo = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID9) + .withTokenBuckets(ImmutableList.of(markTokenBucket)) + .build(); + // Create third policer copy of one + // Create first policer + Policer policerThree = DefaultPolicer.builder() + .forDeviceId(DID1) + .fromApp(FOO_APP_ID) + .withId(ID8) + .withTokenBuckets(ImmutableList.of(blockTokenBucket)) + .build(); + // One and Three are equal + assertEquals(policerOne, policerThree); + // Two is different due to the different id + assertNotEquals(policerOne, policerTwo); + assertNotEquals(policerThree, policerTwo); + } + +} diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResourceTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResourceTest.java new file mode 100644 index 0000000000..7f6d1f9cff --- /dev/null +++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResourceTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onlab.junit.ImmutableClassChecker; +import org.onosproject.net.ConnectPoint; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.*; + +/** + * Test class for PolicingResource. + */ +public class PolicingResourceTest { + + // Connectpoints + private static final String SCP1 = "of:00000000000001/1"; + private static final String SCP2 = "of:00000000000001/2"; + private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint(SCP1); + private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint(SCP2); + // OpenFlow scheme + private static final String OF_SCHEME = "of"; + // Policer identifier + private static final String SID = OF_SCHEME + ":" + Integer.toHexString(1); + private static final PolicerId PID = PolicerId.policerId(SID); + + /** + * Test policing resource creation. + */ + @Test + public void testCreation() { + // Create a new policing resource + PolicingResource policingResource = new PolicingResource(PID, CP1); + // Verify proper creation + assertThat(policingResource, notNullValue()); + assertThat(policingResource.policerId(), is(PID)); + assertThat(policingResource.connectPoint(), is(CP1)); + } + + /** + * Exception expected to raise when creating policing resource with null id. + */ + @Rule + public ExpectedException exceptionNullId = ExpectedException.none(); + + /** + * Test wrong creation of a policing resource. + */ + @Test + public void testNullIdCreation() { + // Define expected exception + exceptionNullId.expect(NullPointerException.class); + // Create wrong policing resource + new PolicingResource(null, CP1); + } + + /** + * Test equality between policing resources. + */ + @Test + public void testEqualilty() { + // Create two identical resources + PolicingResource one = new PolicingResource(PID, CP1); + PolicingResource copyOfOne = new PolicingResource(PID, CP1); + // Verify equality + assertEquals(one, copyOfOne); + // Create a different resource + PolicingResource two = new PolicingResource(PID, CP2); + // Verify not equals + assertNotEquals(two, one); + assertNotEquals(two, copyOfOne); + } + + /** + * Tests immutability of PolicingResource. + */ + @Test + public void testImmutability() { + ImmutableClassChecker.assertThatClassIsImmutable(PolicingResource.class); + } + +} diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketTest.java new file mode 100644 index 0000000000..7deedda5d0 --- /dev/null +++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketTest.java @@ -0,0 +1,179 @@ +/* + * Copyright 2017-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.behaviour.trafficcontrol; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.*; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DROP; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_CLASS; +import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_PRECEDENCE; + +/** + * Test class for TokenBucket. + */ +public class TokenBucketTest { + + // Test rate + private static final long RATE = 1; + // Test dscp drop precedence + private static final short DSCP_PREC = 2; + // Test dscp class + private static final short DSCP_CL = 250; + // Test wrong dscp + private static final short WRONG_DSCP = -1; + + /** + * Test creation of a drop token bucket. + */ + @Test + public void testDropCreation() { + // Create a drop token bucket + TokenBucket drop = DefaultTokenBucket.builder() + .withRate(RATE) + .withAction(DROP) + .build(); + // Not null + assertThat(drop, notNullValue()); + // Rate should be equal to RATE + assertThat(drop.rate(), is(RATE)); + // Burst size should be equal to 2xMTU + assertThat(drop.burstSize(), is(2 * 1500L)); + // Action should be drop + assertThat(drop.action(), is(DROP)); + } + + /** + * Test creation of a dscp precedence token bucket. + */ + @Test + public void testDscpPrecCreation() { + // Create a dscp precedence token bucket + TokenBucket drop = DefaultTokenBucket.builder() + .withRate(RATE) + .withAction(DSCP_PRECEDENCE) + .withBurstSize(6 * 1500) + .withDscp(DSCP_PREC) + .build(); + // Not null + assertThat(drop, notNullValue()); + // Rate should be equal to RATE + assertThat(drop.rate(), is(RATE)); + // Burst size should be equal to 6xMTU + assertThat(drop.burstSize(), is(6 * 1500L)); + // Action should increase dscp drop precedence + assertThat(drop.action(), is(DSCP_PRECEDENCE)); + // Dcsp drop precedence should be increased of 2 + assertThat(drop.dscp(), is(DSCP_PREC)); + } + + /** + * Test creation of a dscp class token bucket. + */ + @Test + public void testDscpClassCreation() { + // Create a dscp class token bucket + TokenBucket drop = DefaultTokenBucket.builder() + .withRate(RATE) + .withAction(DSCP_CLASS) + .withDscp(DSCP_CL) + .build(); + // Not null + assertThat(drop, notNullValue()); + // Rate should be equal to RATE + assertThat(drop.rate(), is(RATE)); + // Burst size should be equal to 2xMTU + assertThat(drop.burstSize(), is(2 * 1500L)); + // Action should be drop + assertThat(drop.action(), is(DSCP_CLASS)); + // Dcsp drop precedence should be increased of 2 + assertThat(drop.dscp(), is(DSCP_CL)); + } + + /** + * Exception expected to raise when creating a token bucket with null action. + */ + @Rule + public ExpectedException exceptionNullAction = ExpectedException.none(); + + /** + * Test creation of a token bucket with null action. + */ + @Test + public void testNullActionCreation() { + // Define expected exception + exceptionNullAction.expect(NullPointerException.class); + // Create a token bucket without action + TokenBucket drop = DefaultTokenBucket.builder() + .withRate(RATE) + .build(); + } + + /** + * Exception expected to raise when creating a token bucket with wrong dscp. + */ + @Rule + public ExpectedException exceptionWrongDscp = ExpectedException.none(); + + /** + * Test creation of a token bucket with wrong dscp. + */ + @Test + public void testWrongDscpCreation() { + // Define expected exception + exceptionWrongDscp.expect(IllegalArgumentException.class); + // Create a token bucket with wrong dscp + TokenBucket drop = DefaultTokenBucket.builder() + .withRate(RATE) + .withAction(DSCP_PRECEDENCE) + .withDscp(WRONG_DSCP) + .build(); + } + + /** + * Test equality between policer ids. + */ + @Test + public void testEqualilty() { + // Create a drop token bucket + TokenBucket drop = DefaultTokenBucket.builder() + .withRate(RATE) + .withAction(DROP) + .build(); + // Create a mark token bucket + TokenBucket mark = DefaultTokenBucket.builder() + .withRate(RATE) + .withAction(DSCP_PRECEDENCE) + .withDscp(DSCP_PREC) + .build(); + // Create a copy of the drop token bucket + TokenBucket copyDrop = DefaultTokenBucket.builder() + .withRate(RATE) + .withAction(DROP) + .build(); + // Verify equality + assertEquals(drop, copyDrop); + // Verify not equals + assertNotEquals(mark, drop); + assertNotEquals(mark, copyDrop); + } + +} diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java new file mode 100644 index 0000000000..63c5f92867 --- /dev/null +++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-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. + */ + +/** + * Test class for traffic control behaviors and related classes. + */ +package org.onosproject.net.behaviour.trafficcontrol;