diff options
Diffstat (limited to 'framework/src/onos/providers/openflow/meter')
6 files changed, 731 insertions, 0 deletions
diff --git a/framework/src/onos/providers/openflow/meter/pom.xml b/framework/src/onos/providers/openflow/meter/pom.xml new file mode 100644 index 00000000..9de5c1b0 --- /dev/null +++ b/framework/src/onos/providers/openflow/meter/pom.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2015 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. + --> +<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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-of-providers</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-of-provider-meter</artifactId> + <packaging>bundle</packaging> + + <description>ONOS OpenFlow protocol meter provider</description> + +</project>
\ No newline at end of file diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterModBuilder.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterModBuilder.java new file mode 100644 index 00000000..c07354b6 --- /dev/null +++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterModBuilder.java @@ -0,0 +1,159 @@ +/* + * Copyright 2015 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.provider.of.meter.impl; + +import org.onosproject.net.meter.Band; +import org.onosproject.net.meter.Meter; +import org.onosproject.net.meter.MeterId; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.OFMeterFlags; +import org.projectfloodlight.openflow.protocol.OFMeterMod; +import org.projectfloodlight.openflow.protocol.OFMeterModCommand; +import org.projectfloodlight.openflow.protocol.meterband.OFMeterBand; +import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDrop; +import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDscpRemark; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Builder for a meter modification. + */ +public final class MeterModBuilder { + + private final Logger log = getLogger(getClass()); + + private final long xid; + private final OFFactory factory; + private Meter.Unit unit = Meter.Unit.KB_PER_SEC; + private boolean burst = false; + private Long id; + private Collection<Band> bands; + + public MeterModBuilder(long xid, OFFactory factory) { + this.xid = xid; + this.factory = factory; + } + + public static MeterModBuilder builder(long xid, OFFactory factory) { + return new MeterModBuilder(xid, factory); + } + + public MeterModBuilder withRateUnit(Meter.Unit unit) { + this.unit = unit; + return this; + } + + public MeterModBuilder burst() { + this.burst = true; + return this; + } + + public MeterModBuilder withId(MeterId meterId) { + this.id = meterId.id(); + return this; + } + + public MeterModBuilder withBands(Collection<Band> bands) { + this.bands = bands; + return this; + } + + public OFMeterMod add() { + validate(); + OFMeterMod.Builder builder = builderMeterMod(); + builder.setCommand(OFMeterModCommand.ADD.ordinal()); + return builder.build(); + } + + public OFMeterMod remove() { + validate(); + OFMeterMod.Builder builder = builderMeterMod(); + builder.setCommand(OFMeterModCommand.DELETE.ordinal()); + return builder.build(); + } + + public OFMeterMod modify() { + validate(); + OFMeterMod.Builder builder = builderMeterMod(); + builder.setCommand(OFMeterModCommand.MODIFY.ordinal()); + return builder.build(); + } + + private OFMeterMod.Builder builderMeterMod() { + OFMeterMod.Builder builder = factory.buildMeterMod(); + int flags = 0; + if (burst) { + // covering loxi short comings. + flags |= 1 << OFMeterFlags.BURST.ordinal(); + } + switch (unit) { + case PKTS_PER_SEC: + flags |= 1 << OFMeterFlags.PKTPS.ordinal(); + break; + case KB_PER_SEC: + flags |= 1 << OFMeterFlags.KBPS.ordinal(); + break; + default: + log.warn("Unknown unit type {}", unit); + } + //FIXME: THIS WILL CHANGE IN OF1.4 to setBands. + builder.setMeters(buildBands()); + builder.setFlags(flags) + .setMeterId(id) + .setXid(xid); + return builder; + } + + private List<OFMeterBand> buildBands() { + return bands.stream().map(b -> { + switch (b.type()) { + case DROP: + OFMeterBandDrop.Builder dropBuilder = + factory.meterBands().buildDrop(); + if (burst) { + dropBuilder.setBurstSize(b.burst()); + } + dropBuilder.setRate(b.rate()); + return dropBuilder.build(); + case REMARK: + OFMeterBandDscpRemark.Builder remarkBand = + factory.meterBands().buildDscpRemark(); + if (burst) { + remarkBand.setBurstSize(b.burst()); + } + remarkBand.setRate(b.rate()); + remarkBand.setPrecLevel(b.dropPrecedence()); + return remarkBand.build(); + default: + log.warn("Unknown band type {}", b.type()); + return null; + } + }).filter(value -> value != null).collect(Collectors.toList()); + } + + private void validate() { + checkNotNull(id, "id cannot be null"); + checkNotNull(bands, "Must have bands"); + checkArgument(bands.size() > 0, "Must have at lease one band"); + } +} diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterStatsCollector.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterStatsCollector.java new file mode 100644 index 00000000..83dc6458 --- /dev/null +++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterStatsCollector.java @@ -0,0 +1,103 @@ +/* + * Copyright 2015 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.provider.of.meter.impl; + +import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.TimerTask; +import org.onlab.util.Timer; +import org.onosproject.openflow.controller.OpenFlowSwitch; +import org.onosproject.openflow.controller.RoleState; +import org.projectfloodlight.openflow.protocol.OFMeterStatsRequest; +import org.slf4j.Logger; + +import java.util.concurrent.TimeUnit; + +import static org.slf4j.LoggerFactory.getLogger; + +/* + * Sends Meter Stats Request and collect the Meter statistics with a time interval. + */ +public class MeterStatsCollector implements TimerTask { + + private final HashedWheelTimer timer = Timer.getTimer(); + private final OpenFlowSwitch sw; + private final Logger log = getLogger(getClass()); + private final int refreshInterval; + + private Timeout timeout; + + private boolean stopTimer = false; + + /** + * Creates a GroupStatsCollector object. + * + * @param sw Open Flow switch + * @param interval time interval for collecting group statistic + */ + public MeterStatsCollector(OpenFlowSwitch sw, int interval) { + this.sw = sw; + this.refreshInterval = interval; + } + + @Override + public void run(Timeout timeout) throws Exception { + log.trace("Collecting stats for {}", sw.getStringId()); + + sendMeterStatistic(); + + if (!this.stopTimer) { + log.trace("Scheduling stats collection in {} seconds for {}", + this.refreshInterval, this.sw.getStringId()); + timeout.getTimer().newTimeout(this, refreshInterval, + TimeUnit.SECONDS); + } + } + + private void sendMeterStatistic() { + if (log.isTraceEnabled()) { + log.trace("sendMeterStatistics {}:{}", sw.getStringId(), sw.getRole()); + } + if (sw.getRole() != RoleState.MASTER) { + return; + } + + OFMeterStatsRequest.Builder builder = + sw.factory().buildMeterStatsRequest(); + builder.setXid(0).setMeterId(0xFFFFFFFF); + + sw.sendMsg(builder.build()); + + } + + /** + * Starts the collector. + */ + public void start() { + log.info("Starting Meter Stats collection thread for {}", sw.getStringId()); + timeout = timer.newTimeout(this, 1, TimeUnit.SECONDS); + } + + /** + * Stops the collector. + */ + public void stop() { + log.info("Stopping Meter Stats collection thread for {}", sw.getStringId()); + this.stopTimer = true; + timeout.cancel(); + } +} diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java new file mode 100644 index 00000000..f5a777be --- /dev/null +++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java @@ -0,0 +1,393 @@ +/* + * Copyright 2015 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.provider.of.meter.impl; + + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalCause; +import com.google.common.cache.RemovalNotification; +import com.google.common.collect.Maps; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.core.CoreService; +import org.onosproject.net.meter.Band; +import org.onosproject.net.meter.DefaultBand; +import org.onosproject.net.meter.DefaultMeter; +import org.onosproject.net.meter.Meter; +import org.onosproject.net.meter.MeterFailReason; +import org.onosproject.net.meter.MeterId; +import org.onosproject.net.meter.MeterOperation; +import org.onosproject.net.meter.MeterOperations; +import org.onosproject.net.meter.MeterProvider; +import org.onosproject.net.meter.MeterProviderRegistry; +import org.onosproject.net.meter.MeterProviderService; +import org.onosproject.net.meter.MeterState; +import org.onosproject.net.DeviceId; +import org.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.openflow.controller.Dpid; +import org.onosproject.openflow.controller.OpenFlowController; +import org.onosproject.openflow.controller.OpenFlowEventListener; +import org.onosproject.openflow.controller.OpenFlowSwitch; +import org.onosproject.openflow.controller.OpenFlowSwitchListener; +import org.onosproject.openflow.controller.RoleState; +import org.projectfloodlight.openflow.protocol.OFErrorMsg; +import org.projectfloodlight.openflow.protocol.OFErrorType; +import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFMeterBandStats; +import org.projectfloodlight.openflow.protocol.OFMeterConfigStatsReply; +import org.projectfloodlight.openflow.protocol.OFMeterStats; +import org.projectfloodlight.openflow.protocol.OFMeterStatsReply; +import org.projectfloodlight.openflow.protocol.OFPortStatus; +import org.projectfloodlight.openflow.protocol.OFStatsReply; +import org.projectfloodlight.openflow.protocol.OFStatsType; +import org.projectfloodlight.openflow.protocol.OFVersion; +import org.projectfloodlight.openflow.protocol.errormsg.OFMeterModFailedErrorMsg; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Provider which uses an OpenFlow controller to handle meters. + */ +@Component(immediate = true, enabled = true) +public class OpenFlowMeterProvider extends AbstractProvider implements MeterProvider { + + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected OpenFlowController controller; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MeterProviderRegistry providerRegistry; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + private MeterProviderService providerService; + + private static final AtomicLong XID_COUNTER = new AtomicLong(1); + + static final int POLL_INTERVAL = 10; + static final long TIMEOUT = 30; + + private Cache<Long, MeterOperation> pendingOperations; + + + private InternalMeterListener listener = new InternalMeterListener(); + private Map<Dpid, MeterStatsCollector> collectors = Maps.newHashMap(); + + /** + * Creates a OpenFlow meter provider. + */ + public OpenFlowMeterProvider() { + super(new ProviderId("of", "org.onosproject.provider.meter")); + } + + @Activate + public void activate() { + providerService = providerRegistry.register(this); + + pendingOperations = CacheBuilder.newBuilder() + .expireAfterWrite(TIMEOUT, TimeUnit.SECONDS) + .removalListener((RemovalNotification<Long, MeterOperation> notification) -> { + if (notification.getCause() == RemovalCause.EXPIRED) { + providerService.meterOperationFailed(notification.getValue(), + MeterFailReason.TIMEOUT); + } + }).build(); + + controller.addEventListener(listener); + controller.addListener(listener); + + controller.getSwitches().forEach((sw -> createStatsCollection(sw))); + } + + @Deactivate + public void deactivate() { + providerRegistry.unregister(this); + controller.removeEventListener(listener); + controller.removeListener(listener); + providerService = null; + } + + @Override + public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) { + Dpid dpid = Dpid.dpid(deviceId.uri()); + OpenFlowSwitch sw = controller.getSwitch(dpid); + if (sw == null) { + log.error("Unknown device {}", deviceId); + meterOps.operations().forEach(op -> + providerService.meterOperationFailed(op, + MeterFailReason.UNKNOWN_DEVICE) + ); + return; + } + + meterOps.operations().forEach(op -> performOperation(sw, op)); + } + + @Override + public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) { + Dpid dpid = Dpid.dpid(deviceId.uri()); + OpenFlowSwitch sw = controller.getSwitch(dpid); + if (sw == null) { + log.error("Unknown device {}", deviceId); + providerService.meterOperationFailed(meterOp, + MeterFailReason.UNKNOWN_DEVICE); + return; + } + + performOperation(sw, meterOp); + + } + + private void performOperation(OpenFlowSwitch sw, MeterOperation op) { + + pendingOperations.put(op.meter().id().id(), op); + + + Meter meter = op.meter(); + MeterModBuilder builder = MeterModBuilder.builder(meter.id().id(), sw.factory()); + if (meter.isBurst()) { + builder.burst(); + } + builder.withBands(meter.bands()) + .withId(meter.id()) + .withRateUnit(meter.unit()); + + switch (op.type()) { + case ADD: + sw.sendMsg(builder.add()); + break; + case REMOVE: + sw.sendMsg(builder.remove()); + break; + case MODIFY: + sw.sendMsg(builder.modify()); + break; + default: + log.warn("Unknown Meter command {}; not sending anything", + op.type()); + providerService.meterOperationFailed(op, + MeterFailReason.UNKNOWN_COMMAND); + } + + } + + private void createStatsCollection(OpenFlowSwitch sw) { + if (isMeterSupported(sw)) { + MeterStatsCollector msc = new MeterStatsCollector(sw, POLL_INTERVAL); + msc.start(); + collectors.put(new Dpid(sw.getId()), msc); + } + } + + private boolean isMeterSupported(OpenFlowSwitch sw) { + if (sw.factory().getVersion() == OFVersion.OF_10 || + sw.factory().getVersion() == OFVersion.OF_11 || + sw.factory().getVersion() == OFVersion.OF_12) { + return false; + } + + return true; + } + + private void pushMeterStats(Dpid dpid, OFStatsReply msg) { + DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid)); + + if (msg.getStatsType() == OFStatsType.METER) { + OFMeterStatsReply reply = (OFMeterStatsReply) msg; + Collection<Meter> meters = buildMeters(deviceId, reply.getEntries()); + //TODO do meter accounting here. + providerService.pushMeterMetrics(deviceId, meters); + } else if (msg.getStatsType() == OFStatsType.METER_CONFIG) { + OFMeterConfigStatsReply reply = (OFMeterConfigStatsReply) msg; + // FIXME: Map<Long, Meter> meters = collectMeters(deviceId, reply); + } + + } + + private Map<Long, Meter> collectMeters(DeviceId deviceId, + OFMeterConfigStatsReply reply) { + return Maps.newHashMap(); + //TODO: Needs a fix to be applied to loxi MeterConfig stat is incorrect + } + + private Collection<Meter> buildMeters(DeviceId deviceId, + List<OFMeterStats> entries) { + return entries.stream().map(stat -> { + DefaultMeter.Builder builder = DefaultMeter.builder(); + Collection<Band> bands = buildBands(stat.getBandStats()); + builder.forDevice(deviceId) + .withId(MeterId.meterId(stat.getMeterId())) + //FIXME: need to encode appId in meter id, but that makes + // things a little annoying for debugging + .fromApp(coreService.getAppId("org.onosproject.core")) + .withBands(bands); + DefaultMeter meter = builder.build(); + meter.setState(MeterState.ADDED); + meter.setLife(stat.getDurationSec()); + meter.setProcessedBytes(stat.getByteInCount().getValue()); + meter.setProcessedPackets(stat.getPacketInCount().getValue()); + meter.setReferenceCount(stat.getFlowCount()); + + // marks the meter as seen on the dataplane + pendingOperations.invalidate(stat.getMeterId()); + return meter; + }).collect(Collectors.toSet()); + } + + private Collection<Band> buildBands(List<OFMeterBandStats> bandStats) { + return bandStats.stream().map(stat -> { + DefaultBand band = DefaultBand.builder().build(); + band.setBytes(stat.getByteBandCount().getValue()); + band.setPackets(stat.getPacketBandCount().getValue()); + return band; + }).collect(Collectors.toSet()); + } + + private void signalMeterError(OFMeterModFailedErrorMsg meterError, + MeterOperation op) { + switch (meterError.getCode()) { + case UNKNOWN: + providerService.meterOperationFailed(op, + MeterFailReason.UNKNOWN_DEVICE); + break; + case METER_EXISTS: + providerService.meterOperationFailed(op, + MeterFailReason.EXISTING_METER); + break; + case INVALID_METER: + providerService.meterOperationFailed(op, + MeterFailReason.INVALID_METER); + break; + case UNKNOWN_METER: + providerService.meterOperationFailed(op, + MeterFailReason.UNKNOWN); + break; + case BAD_COMMAND: + providerService.meterOperationFailed(op, + MeterFailReason.UNKNOWN_COMMAND); + break; + case BAD_FLAGS: + providerService.meterOperationFailed(op, + MeterFailReason.UNKNOWN_FLAGS); + break; + case BAD_RATE: + providerService.meterOperationFailed(op, + MeterFailReason.BAD_RATE); + break; + case BAD_BURST: + providerService.meterOperationFailed(op, + MeterFailReason.BAD_BURST); + break; + case BAD_BAND: + providerService.meterOperationFailed(op, + MeterFailReason.BAD_BAND); + break; + case BAD_BAND_VALUE: + providerService.meterOperationFailed(op, + MeterFailReason.BAD_BAND_VALUE); + break; + case OUT_OF_METERS: + providerService.meterOperationFailed(op, + MeterFailReason.OUT_OF_METERS); + break; + case OUT_OF_BANDS: + providerService.meterOperationFailed(op, + MeterFailReason.OUT_OF_BANDS); + break; + default: + providerService.meterOperationFailed(op, + MeterFailReason.UNKNOWN); + } + } + + private class InternalMeterListener + implements OpenFlowSwitchListener, OpenFlowEventListener { + @Override + public void handleMessage(Dpid dpid, OFMessage msg) { + switch (msg.getType()) { + case STATS_REPLY: + pushMeterStats(dpid, (OFStatsReply) msg); + break; + case ERROR: + OFErrorMsg error = (OFErrorMsg) msg; + if (error.getErrType() == OFErrorType.METER_MOD_FAILED) { + MeterOperation op = + pendingOperations.getIfPresent(error.getXid()); + pendingOperations.invalidate(error.getXid()); + if (op == null) { + log.warn("Unknown Meter operation failed {}", error); + } else { + OFMeterModFailedErrorMsg meterError = + (OFMeterModFailedErrorMsg) error; + signalMeterError(meterError, op); + } + } + break; + default: + break; + } + + } + + @Override + public void switchAdded(Dpid dpid) { + createStatsCollection(controller.getSwitch(dpid)); + } + + @Override + public void switchRemoved(Dpid dpid) { + MeterStatsCollector msc = collectors.remove(dpid); + if (msc != null) { + msc.stop(); + } + } + + @Override + public void switchChanged(Dpid dpid) { + + } + + @Override + public void portChanged(Dpid dpid, OFPortStatus status) { + + } + + @Override + public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) { + + } + } + + + +} diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/package-info.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/package-info.java new file mode 100644 index 00000000..9515712c --- /dev/null +++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 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. + */ + +/** + * Provider that uses OpenFlow controller as a means of device metering management. + */ +package org.onosproject.provider.of.meter.impl;
\ No newline at end of file diff --git a/framework/src/onos/providers/openflow/meter/src/test/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProviderTest.java b/framework/src/onos/providers/openflow/meter/src/test/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProviderTest.java new file mode 100644 index 00000000..0c5d5389 --- /dev/null +++ b/framework/src/onos/providers/openflow/meter/src/test/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProviderTest.java @@ -0,0 +1,22 @@ +/* + * Copyright 2015 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.provider.of.meter.impl; + + +public class OpenFlowMeterProviderTest { + + +}
\ No newline at end of file |