/* * Copyright 2016-present Open Networking Laboratory * * 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; import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; import org.onlab.packet.DscpClass; import org.onlab.util.Bandwidth; import org.onosproject.net.meter.Band; import org.onosproject.net.meter.Meter; import static org.onosproject.net.behaviour.BandwidthProfileAction.Action; import java.util.Iterator; import java.util.Objects; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** * Implementation of a generic bandwidth profile (marker/policer). */ @Beta public final class BandwidthProfile { /** * Denotes the type of the bandwidth profile. */ enum Type { /** * Corresponds to a Single Rate Two Color Marker/Policer. */ sr2CM, /** * Corresponds to a Single Rate Three Color Marker/Policer. * (IETF RFC 2697) */ srTCM, /** * Corresponds to a Two Rate Three Color Marker/Policer. * (IETF RFC 2698) */ trTCM } private final String name; private final Bandwidth cir; private final Bandwidth pir; private final Integer cbs; private final Integer pbs; private final Integer ebs; private final BandwidthProfileAction greenAction; private final BandwidthProfileAction yellowAction; private final BandwidthProfileAction redAction; private final boolean colorAware; /** * BandwidthProfile constructor. * * @param name the profile name * @param cir the committed information rate (CIR) * @param cbs the committed burst size (CBS) measured in bytes * @param pir the peak information rate (PIR) * @param pbs the peak burst size (PBS) measured in bytes * @param greenAction the action to be taken for traffic that conforms * to the CIR/CBS * @param yellowAction srTCM: the action to be taken for traffic that * conforms to the EBS but not to the CIR/CBS * trTCM: the action to be taken for traffic that * conforms to the PIR/PBS but not to the CIR/CBS * @param redAction sr2CM: the action to be taken for traffic that * does not conform to the CIR/CBS * srTCM: the action to be taken for traffic that * does not conform to the EBS * trTCM: the action to be taken for traffic that * does not conform to the PIR/PBS * @param colorAware indicates whether the profile considers incoming * traffic as already colored */ private BandwidthProfile(String name, Bandwidth cir, Bandwidth pir, Integer cbs, Integer pbs, Integer ebs, BandwidthProfileAction greenAction, BandwidthProfileAction yellowAction, BandwidthProfileAction redAction, boolean colorAware) { this.name = name; this.cir = cir; this.pir = pir; this.cbs = cbs; this.pbs = pbs; this.ebs = ebs; this.greenAction = greenAction; this.yellowAction = yellowAction; this.redAction = redAction; this.colorAware = colorAware; } /** * Obtains the name of this bandwidth profile. * * @return the bandwidth profile name */ public String name() { return name; } /** * Obtains the committed information rate (CIR) of this bandwidth profile. * * @return the CIR of the bandwidth profile */ public Bandwidth cir() { return cir; } /** * Obtains the peak information rate (PIR) of this bandwidth profile. * If this profile does not have a PIR, null is returned. * * @return the PIR of the profile; null if the profile does not have a PIR */ public Bandwidth pir() { return pir; } /** * Obtains the committed burst size (CBS) of this bandwidth profile. * The CBS is measured in bytes. * If this profile does not have a CBS, null is returned. * * @return the CBS of the profile (bytes); * null if the profile does not have a CBS */ public Integer cbs() { return cbs; } /** * Obtains the peak burst size (PBS) of this bandwidth profile. * The PBS is measured in bytes. * If this profile does not have a PBS, null is returned. * * @return the PBS of the bandwidth profile (bytes); * null if the profile does not have a PBS */ public Integer pbs() { return pbs; } /** * Obtains the excess burst size (EBS) of this bandwidth profile. * The EBS is measured in bytes. * If this profile does not have an EBS, null is returned. * * @return the EBS of the bandwidth profile (bytes); * null if the profile does not have an EBS */ public Integer ebs() { return ebs; } /** * Obtains the action to be taken for traffic marked as green. * Green color marking is applied to traffic that conforms to the CIR/CBS. * * @return the action to be taken for traffic marked as green */ public BandwidthProfileAction greenAction() { return greenAction; } /** * Obtains the action to be taken for traffic marked as yellow. * Yellow color marking is applied to traffic that does not conform * to the CIR/CBS but conforms to one of: * <ul> * <li>EBS (srTCM type)</li> * <li>PIR/PBS (trTCM type)</li> * </ul> * If this profile does has neither EBS or PIR/PBS, null is returned. * * @return the action to be taken for traffic marked as yellow; * null if neither EBS nor PIR/PBS are defined */ public BandwidthProfileAction yellowAction() { return yellowAction; } /** * Obtains the action to be taken for traffic marked as red. * Red color marking is applied to traffic that does not conform * to one of the following: * <ul> * <li>CIR/CBS (sr2CM type)</li> * <li>EBS (srTCM type)</li> * <li>PIR/PBS (trTCM type)</li> * </ul> * * @return the action to be taken for traffic marked as red */ public BandwidthProfileAction redAction() { return redAction; } /** * Obtains the color-aware mode of the bandwidth profile. * * @return true if the bandwidth profile is color-aware; false otherwise */ public boolean colorAware() { return colorAware; } /** * Obtains the bandwidth profile type depending on the profile parameters. * <ul> * <li>When PIR is defined, the profile corresponds to a * Two Rate Three Color Marker (trTCM)</li> * <li>When EBS is defined, the profile corresponds to a * Single Rate Three Color Marker (srTCM)</li> * <li>When neither PIR nor EBS are defined, the profile corresponds to a * Single Rate Two Color Marker/Policer (sr2CM)</li> * </ul> * * @return the bandwidth profile type */ public Type type() { return pir != null ? Type.trTCM : ebs != null ? Type.srTCM : Type.sr2CM; } /** * Creates a bandwidth profile based on the parameters of a Meter. * NOTE: The dropPrecedence in the Meter is interpreted as * the DSCP class to set on the packet * * @param meter the Meter to be used for creating the bandwidth profile * @return the bandwidth profile created */ public static BandwidthProfile fromMeter(Meter meter) { checkNotNull(meter); checkArgument(meter.bands().size() <= 2, "Meter must have no more than two bands."); Iterator<Band> bandIterator = meter.bands().iterator(); Band bandOne = bandIterator.next(); Band bandTwo = bandIterator.hasNext() ? bandIterator.next() : null; // Assign values to yellowBand and redBand depending on // the number of bands in the meter. // If only one band exists it will be designated as the redBand. // If two bands exist, the one with the lower rate will be // the yellowBand and the other the redBand. Band yellowBand = (bandTwo == null ? null : bandTwo.rate() > bandOne.rate() ? bandOne : bandTwo); Band redBand = (bandTwo == null ? bandOne : yellowBand == bandOne ? bandTwo : bandOne); BandwidthProfile.Builder bandwidthProfileBuilder = new Builder() // Consider the meter id as the bandwidth profile name .name(meter.id().toString()) .colorAware(false) // The implicit green action is pass .greenAction(getBuilder(Action.PASS).build()); if (yellowBand != null) { // Try to add yellow action; CIR/CBS will be obtained from // yellowBand and PIR/PBS from redBand. BandwidthProfileAction yellowAction = getBwProfileActionFromBand(yellowBand); checkNotNull(yellowAction, "Could not obtain yellow action from meter band"); bandwidthProfileBuilder .cir(Bandwidth.kBps(yellowBand.rate())) .cbs(yellowBand.burst() == null ? null : yellowBand.burst().intValue()) .pir(Bandwidth.kBps(redBand.rate())) .pbs(redBand.burst() == null ? null : redBand.burst().intValue()) .yellowAction(yellowAction); } else { // No yellow action to add; CIR/CBS will be obtained from redBand bandwidthProfileBuilder .cir(Bandwidth.kBps(redBand.rate())) .cbs(redBand.burst() == null ? null : redBand.burst().intValue()); } // Try to add red action in any case BandwidthProfileAction redAction = getBwProfileActionFromBand(redBand); checkNotNull(redAction, "Could not obtain red action from meter band"); return bandwidthProfileBuilder .redAction(redAction) .build(); } private static BandwidthProfileAction.Builder getBuilder(Action action) { return BandwidthProfileAction.builder().action(action); } private static BandwidthProfileAction getBwProfileActionFromBand(Band band) { checkNotNull(band.type(), "Could not obtain BW profile: Meter band type is null"); Action action = null; if (band.type().equals(Band.Type.DROP)) { action = Action.DISCARD; } else if (band.type().equals(Band.Type.REMARK)) { action = Action.REMARK; } checkNotNull(action, "Could not obtain BW profile: Invalid meter band type"); BandwidthProfileAction.Builder actionBuilder = getBuilder(action); if (band.type().equals(Band.Type.REMARK)) { checkNotNull(band.dropPrecedence(), "Could not obtain DSCP class from meter band"); actionBuilder.dscpClass(DscpClass.fromShort(band.dropPrecedence())); } return actionBuilder.build(); } /** * Returns a new builder. * * @return new builder */ public static Builder builder() { return new Builder(); } /** * Builder of BandwidthProfile entities. */ public static final class Builder { private String name; private Bandwidth cir; private Bandwidth pir; private Integer cbs; private Integer pbs; private Integer ebs; private BandwidthProfileAction greenAction; private BandwidthProfileAction yellowAction; private BandwidthProfileAction redAction; private boolean colorAware; /** * Sets the name of this bandwidth profile builder. * * @param name the builder name to set * @return this builder instance */ public Builder name(String name) { this.name = name; return this; } /** * Sets the committed information rate (CIR) of this builder. * * @param cir the builder CIR to set * @return this builder instance */ public Builder cir(Bandwidth cir) { this.cir = cir; return this; } /** * Sets the peak information rate (PIR) of this builder. * * @param pir the builder PIR to set * @return this builder instance */ public Builder pir(Bandwidth pir) { this.pir = pir; return this; } /** * Sets the committed burst size (CBS) of this builder. * The CBS is measured in bytes. * * @param cbs the builder CBS to set * @return this builder instance */ public Builder cbs(Integer cbs) { this.cbs = cbs; return this; } /** * Sets the peak burst size (PBS) of this builder. * The PBS is measured in bytes. * * @param pbs the builder CBS to set * @return this builder instance */ public Builder pbs(Integer pbs) { this.pbs = pbs; return this; } /** * Sets the excess burst size (EBS) of this builder. * The EBS is measured in bytes. * * @param ebs the builder EBS to set * @return this builder instance */ public Builder ebs(Integer ebs) { this.ebs = ebs; return this; } /** * Sets the green action of this builder. * * @param greenAction the builder green action to set * @return this builder instance */ public Builder greenAction(BandwidthProfileAction greenAction) { this.greenAction = greenAction; return this; } /** * Sets the yellow action of this builder. * * @param yellowAction the builder green action to set * @return this builder instance */ public Builder yellowAction(BandwidthProfileAction yellowAction) { this.yellowAction = yellowAction; return this; } /** * Sets the red action of this builder. * * @param redAction the builder green action to set * @return this builder instance */ public Builder redAction(BandwidthProfileAction redAction) { this.redAction = redAction; return this; } /** * Sets the color-aware mode of this builder. * * @param colorAware true if profile to be build is color-aware; * false otherwise * @return this builder instance */ public Builder colorAware(boolean colorAware) { this.colorAware = colorAware; return this; } /** * Builds a new BandwidthProfile instance. * based on this builder's parameters * * @return a new BandwidthProfile instance */ public BandwidthProfile build() { checkNotNull(name, "Bandwidth profile must have a name"); checkNotNull(cir, "Bandwidth profile must have a CIR"); checkNotNull(greenAction, "Bandwidth profile must have a green action"); checkNotNull(redAction, "Bandwidth profile must have a red action"); checkArgument(pir != null || pbs == null, "Bandwidth profile cannot have PBS without PIR"); checkArgument(pir == null || ebs == null, "Bandwidth profile cannot have both PIR and EBS"); checkArgument(yellowAction == null && pir == null && ebs == null || yellowAction != null && (pir != null ^ ebs != null), "Bandwidth profile must have a yellow action only " + "when either PIR or EBS are defined"); return new BandwidthProfile(name, cir, pir, cbs, pbs, ebs, greenAction, yellowAction, redAction, colorAware); } } @Override public int hashCode() { return Objects.hash(cir, pir, cbs, pbs, ebs, greenAction, yellowAction, redAction, colorAware); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof BandwidthProfile) { final BandwidthProfile that = (BandwidthProfile) obj; return this.getClass() == that.getClass() && Objects.equals(this.cir, that.cir) && Objects.equals(this.pir, that.pir) && Objects.equals(this.cbs, that.cbs) && Objects.equals(this.pbs, that.pbs) && Objects.equals(this.ebs, that.ebs) && Objects.equals(this.greenAction, that.greenAction) && Objects.equals(this.yellowAction, that.yellowAction) && Objects.equals(this.redAction, that.redAction) && Objects.equals(this.colorAware, that.colorAware); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .add("name", name) .add("cir", cir) .add("pir", pir) .add("cbs", cbs) .add("pbs", pbs) .add("ebs", ebs) .add("greenAction", greenAction) .add("yellowAction", yellowAction) .add("redAction", redAction) .add("colorAware", colorAware) .toString(); } }