diff options
Diffstat (limited to 'framework/src/onos/core')
135 files changed, 5586 insertions, 928 deletions
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java index a311002f..408a8933 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java @@ -63,6 +63,16 @@ public interface ComponentConfigService { void setProperty(String componentName, String name, String value); /** + * Presets the value of the specified configuration property, regardless + * of the component's state. + * + * @param componentName component name + * @param name property name + * @param value new property value + */ + void preSetProperty(String componentName, String name, String value); + + /** * Clears the value of the specified configuration property thus making * the property take on its default value. * @@ -72,3 +82,4 @@ public interface ComponentConfigService { void unsetProperty(String componentName, String name); } + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java index 4949bc40..8c5fb790 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java @@ -25,8 +25,10 @@ package org.onosproject.net; */ public final class AnnotationKeys { + // Prohibit instantiation - private AnnotationKeys() {} + private AnnotationKeys() { + } /** * Annotation key for instance name. @@ -125,12 +127,22 @@ public final class AnnotationKeys { public static final String OWNER = "owner"; /** + * Annotation key for the channel id. + */ + public static final String CHANNEL_ID = "channelId"; + + /** + * Annotation key for the management address. + */ + public static final String MANAGEMENT_ADDRESS = "managementAddress"; + + /** * Returns the value annotated object for the specified annotation key. * The annotated value is expected to be String that can be parsed as double. * If parsing fails, the returned value will be 1.0. * * @param annotated annotated object whose annotated value is obtained - * @param key key of annotation + * @param key key of annotation * @return double value of annotated object for the specified key */ public static double getAnnotatedValue(Annotated annotated, String key) { diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java new file mode 100644 index 00000000..4895964f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java @@ -0,0 +1,100 @@ +/* + * 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.net; + +import org.onosproject.net.provider.ProviderId; + +import java.util.List; +import java.util.Objects; +import static com.google.common.collect.ImmutableSet.of; + +/** + * Default implementation of a network disjoint path pair. + */ +public class DefaultDisjointPath extends DefaultPath implements DisjointPath { + + private final DefaultPath path1; + private final DefaultPath path2; + + boolean usingPath1 = true; + + /** + * Creates a disjoint path pair from two default paths. + * + * @param providerId provider identity + * @param path1 primary path + * @param path2 backup path + */ + public DefaultDisjointPath(ProviderId providerId, DefaultPath path1, DefaultPath path2) { + super(providerId, path1.links(), path1.cost() + path2.cost()); + this.path1 = path1; + this.path2 = path2; + } + + @Override + public List<Link> links() { + if (usingPath1) { + return path1.links(); + } else { + return path2.links(); + } + } + + @Override + public double cost() { + if (usingPath1) { + return path1.cost(); + } + return path2.cost(); + } + + @Override + public Path primary() { + return path1; + } + + @Override + public Path backup() { + return path2; + } + + @Override + public int hashCode() { + return Objects.hash(of(path1, path2), src(), dst()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultDisjointPath) { + final DefaultDisjointPath other = (DefaultDisjointPath) obj; + return Objects.equals(this.path1, other.path1) && Objects.equals(this.path2, other.path2); + } + return false; + } + + @Override + public boolean useBackup() { + if (path2 == null || path2.links() == null) { + return false; + } + usingPath1 = !usingPath1; + return true; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java new file mode 100644 index 00000000..3d54cbfc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java @@ -0,0 +1,49 @@ +/* + * 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.net; + + +/** + * Representation of a contiguous directed path in a network. Path comprises + * of a sequence of links, where adjacent links must share the same device, + * meaning that destination of the source of one link must coincide with the + * destination of the previous link. + */ +public interface DisjointPath extends Path { + + /** + * Uses backup path. + * + * @return boolean corresponding to whether request to use + * backup was successful. + */ + boolean useBackup(); + + /** + * Gets primary path. + * + * @return primary path + */ + Path primary(); + + /** + * Gets secondary path. + * + * @return secondary path + */ + Path backup(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java index bb8a788b..cd7cb977 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java @@ -15,23 +15,27 @@ */ package org.onosproject.net.behaviour; +import org.onosproject.net.driver.HandlerBehaviour; + import java.util.List; /** * Device behaviour to obtain and set controllers at the device. */ -public interface ControllerConfig { +public interface ControllerConfig extends HandlerBehaviour { //TODO: add other controller parameters as needed. /** * Obtain the list of controller which are currently configured. + * * @return a list for controller descriptions */ List<ControllerInfo> getControllers(); /** * Set a list of controllers on a device. + * * @param controllers a list of controller descriptions */ void setControllers(List<ControllerInfo> controllers); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java index 9ff808a9..ded3b3ae 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java @@ -15,24 +15,112 @@ */ package org.onosproject.net.behaviour; +import com.google.common.base.Preconditions; import org.onlab.packet.IpAddress; +import java.util.Objects; + /** * Represents information for a device to connect to a controller. */ public class ControllerInfo { - public final IpAddress ip; - public final int tcpPort; + private IpAddress ip = IpAddress.valueOf("0.0.0.0"); + private int port = 6653; + private String type = "error"; /** * Information for contacting the controller. * - * @param ip the ip address - * @param tcpPort the tcp port + * @param ip the ip address + * @param port the tcp port */ - public ControllerInfo(IpAddress ip, int tcpPort) { + public ControllerInfo(IpAddress ip, int port, String type) { this.ip = ip; - this.tcpPort = tcpPort; + this.port = port; + this.type = type; + } + + /** + * Information for contacting the controller, if some information + * is not contained in the target string because it's optional + * it's leaved as in the field declaration (default values). + * + * @param target column returned from ovsdb query + */ + public ControllerInfo(String target) { + String[] data = target.split(":"); + this.type = data[0]; + Preconditions.checkArgument(!data[0].contains("unix"), + "Unable to create controller info " + + "from {} because it's based " + + "on unix sockets", target); + if (data[0].startsWith("p")) { + if (data.length >= 2) { + this.port = Integer.parseInt(data[1]); + } + if (data.length == 3) { + this.ip = IpAddress.valueOf(data[2]); + } + } else { + this.ip = IpAddress.valueOf(data[1]); + if (data.length == 3) { + this.port = Integer.parseInt(data[2]); + } + } + } + + /** + * Exposes the ip address of the controller. + * + * @return IpAddress ip address + */ + public IpAddress ip() { + return ip; + } + + /** + * Exposes the tcp port of the controller. + * + * @return int tcp port + */ + public int port() { + return port; + } + + /** + * Exposes the type of the controller connection. + * + * @return String type + */ + public String type() { + return type; + } + + public String target() { + if (type.startsWith("p")) { + return type + ":" + port + ":" + ip; + } else { + return type + ":" + ip + ":" + port; + } + } + + + @Override + public int hashCode() { + return Objects.hash(ip, port, type); + } + + @Override + public boolean equals(Object toBeCompared) { + if (toBeCompared instanceof ControllerInfo) { + ControllerInfo controllerInfo = (ControllerInfo) toBeCompared; + if (controllerInfo.type().equals(this.type) + && controllerInfo.ip().equals(this.ip()) + && controllerInfo.port() == this.port) { + return true; + } + } + return false; } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java index c1eed980..8eb69a45 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java @@ -41,27 +41,27 @@ public interface NetworkConfigService /** * Returns the subject factory with the specified key. * - * @param subjectKey subject class key + * @param subjectClassKey subject class key * @return subject class */ - SubjectFactory getSubjectFactory(String subjectKey); + SubjectFactory getSubjectFactory(String subjectClassKey); /** * Returns the subject factory for the specified class. * * @param subjectClass subject class - * @return subject class key + * @return subject class factory */ SubjectFactory getSubjectFactory(Class subjectClass); /** * Returns the configuration class with the specified key. * - * @param subjectKey subject class key - * @param configKey subject class name + * @param subjectClassKey subject class key + * @param configKey subject class name * @return subject class */ - Class<? extends Config> getConfigClass(String subjectKey, String configKey); + Class<? extends Config> getConfigClass(String subjectClassKey, String configKey); /** * Returns the set of subjects for which some configuration is available. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java index cd2db344..f992d727 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java @@ -28,7 +28,7 @@ import com.google.common.annotations.Beta; public abstract class SubjectFactory<S> { private final Class<S> subjectClass; - private final String subjectKey; + private final String subjectClassKey; /** * Creates a new configuration factory for the specified class of subjects @@ -36,12 +36,12 @@ public abstract class SubjectFactory<S> { * subject and configuration class keys are used merely as keys for use in * composite JSON trees. * - * @param subjectClass subject class - * @param subjectKey subject class key + * @param subjectClass subject class + * @param subjectClassKey subject class key */ - protected SubjectFactory(Class<S> subjectClass, String subjectKey) { + protected SubjectFactory(Class<S> subjectClass, String subjectClassKey) { this.subjectClass = subjectClass; - this.subjectKey = subjectKey; + this.subjectClassKey = subjectClassKey; } /** @@ -60,8 +60,20 @@ public abstract class SubjectFactory<S> { * * @return configuration key */ - public String subjectKey() { - return subjectKey; + public String subjectClassKey() { + return subjectClassKey; + } + + /** + * Returns the unique key of the specified configuration subject. + * This is primarily aimed for use in composite JSON trees in external + * representations and has no bearing on the internal behaviours. + * + * @param subject specific subject + * @return subject key + */ + public String subjectKey(S subject) { + return subject.toString(); } /** diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java index fd8bfa3e..afde9a9e 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java @@ -25,6 +25,7 @@ public class BasicDeviceConfig extends BasicElementConfig<DeviceId> { public static final String TYPE = "type"; public static final String DRIVER = "driver"; + public static final String MANAGEMENT_ADDRESS = "managementAddress"; /** * Returns the device type. @@ -64,6 +65,25 @@ public class BasicDeviceConfig extends BasicElementConfig<DeviceId> { return (BasicElementConfig) setOrClear(DRIVER, driverName); } + /** + * Returns the device management ip (ip:port). + * + * @return device management address (ip:port) or null if not set + */ + public String managementAddress() { + return get(MANAGEMENT_ADDRESS, null); + } + + /** + * Sets the driver name. + * + * @param managementAddress new device management address (ip:port); null to clear + * @return self + */ + public BasicElementConfig managementAddress(String managementAddress) { + return (BasicElementConfig) setOrClear(MANAGEMENT_ADDRESS, managementAddress); + } + // TODO: device port meta-data to be configured via BasicPortsConfig // TODO: device credentials/keys diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java index 884f2e20..311566b3 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java @@ -43,6 +43,10 @@ public final class SubjectFactories { public ApplicationId createSubject(String key) { return coreService.registerApplication(key); } + @Override + public String subjectKey(ApplicationId subject) { + return subject.name(); + } }; public static final SubjectFactory<DeviceId> DEVICE_SUBJECT_FACTORY = @@ -59,6 +63,10 @@ public final class SubjectFactories { public ConnectPoint createSubject(String key) { return ConnectPoint.deviceConnectPoint(key); } + @Override + public String subjectKey(ConnectPoint subject) { + return key(subject); + } }; public static final SubjectFactory<HostId> HOST_SUBJECT_FACTORY = @@ -78,6 +86,10 @@ public final class SubjectFactories { return LinkKey.linkKey(ConnectPoint.deviceConnectPoint(cps[0]), ConnectPoint.deviceConnectPoint(cps[1])); } + @Override + public String subjectKey(LinkKey subject) { + return key(subject.src()) + "-" + key(subject.dst()); + } }; /** @@ -90,4 +102,8 @@ public final class SubjectFactories { coreService = service; } + private static String key(ConnectPoint subject) { + return subject.deviceId() + "/" + subject.port(); + } + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java new file mode 100644 index 00000000..929b285d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java @@ -0,0 +1,89 @@ +/* + * 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.net.flow; + +import org.onosproject.net.DeviceId; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of table statistics entry interface. + */ +public final class DefaultTableStatisticsEntry implements TableStatisticsEntry { + + private final DeviceId deviceId; + private final int tableId; + private final long activeFlowEntries; + private final long packetsLookedupCount; + private final long packetsMatchedCount; + + /** + * Default table statistics constructor. + * + * @param deviceId device identifier + * @param tableId table identifier + * @param activeFlowEntries number of active flow entries in the table + * @param packetsLookedupCount number of packets looked up in table + * @param packetsMatchedCount number of packets that hit table + */ + public DefaultTableStatisticsEntry(DeviceId deviceId, + int tableId, + long activeFlowEntries, + long packetsLookedupCount, + long packetsMatchedCount) { + this.deviceId = checkNotNull(deviceId); + this.tableId = tableId; + this.activeFlowEntries = activeFlowEntries; + this.packetsLookedupCount = packetsLookedupCount; + this.packetsMatchedCount = packetsMatchedCount; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("device: " + deviceId + ", "); + + sb.append("tableId: " + this.tableId + ", "); + sb.append("activeEntries: " + this.activeFlowEntries + ", "); + sb.append("packetsLookedUp: " + this.packetsLookedupCount + ", "); + sb.append("packetsMatched: " + this.packetsMatchedCount); + + return sb.toString(); + } + + @Override + public int tableId() { + return tableId; + } + + @Override + public long activeFlowEntries() { + return activeFlowEntries; + } + + @Override + public long packetsLookedup() { + return packetsLookedupCount; + } + + @Override + public long packetsMatched() { + return packetsMatchedCount; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java index f88c6bc3..4416456c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java @@ -23,22 +23,26 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; -import org.onosproject.net.IndexedLambda; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeSet; /** * Default traffic selector implementation. */ public final class DefaultTrafficSelector implements TrafficSelector { + private static final Comparator<? super Criterion> TYPE_COMPARATOR = + (c1, c2) -> c1.type().compareTo(c2.type()); + private final Set<Criterion> criteria; private static final TrafficSelector EMPTY @@ -50,7 +54,9 @@ public final class DefaultTrafficSelector implements TrafficSelector { * @param criteria criteria */ private DefaultTrafficSelector(Set<Criterion> criteria) { - this.criteria = ImmutableSet.copyOf(criteria); + TreeSet<Criterion> elements = new TreeSet<>(TYPE_COMPARATOR); + elements.addAll(criteria); + this.criteria = ImmutableSet.copyOf(elements); } @Override @@ -345,18 +351,6 @@ public final class DefaultTrafficSelector implements TrafficSelector { return add(Criteria.matchIPv6ExthdrFlags(exthdrFlags)); } - @Deprecated - @Override - public Builder matchLambda(short lambda) { - return add(Criteria.matchLambda(new IndexedLambda(lambda))); - } - - @Deprecated - @Override - public Builder matchOpticalSignalType(short signalType) { - return add(Criteria.matchOpticalSignalType(signalType)); - } - @Override public TrafficSelector build() { return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values())); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java index 5d18a9ad..a628725c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java @@ -31,7 +31,6 @@ import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.meter.MeterId; -import java.util.Collections; import java.util.List; import java.util.Objects; @@ -51,7 +50,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { private final boolean hasClear; private static final DefaultTrafficTreatment EMPTY - = new DefaultTrafficTreatment(Collections.emptyList()); + = new DefaultTrafficTreatment(ImmutableList.of(Instructions.createNoAction())); private final Instructions.MeterInstruction meter; /** @@ -212,8 +211,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { List<Instruction> current = immediate; - - // Creates a new builder private Builder() { } @@ -224,7 +221,10 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { treatment.deferred().forEach(i -> add(i)); immediate(); - treatment.immediate().forEach(i -> add(i)); + treatment.immediate().stream() + // NOACTION will get re-added if there are no other actions + .filter(i -> i.type() != Instruction.Type.NOACTION) + .forEach(i -> add(i)); clear = treatment.clearedDeferred(); } @@ -234,6 +234,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { switch (instruction.type()) { case DROP: + case NOACTION: case OUTPUT: case GROUP: case L0MODIFICATION: @@ -250,6 +251,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { break; case METER: meter = (Instructions.MeterInstruction) instruction; + break; default: throw new IllegalArgumentException("Unknown instruction type: " + instruction.type()); @@ -258,9 +260,23 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { return this; } + /** + * Add a NOACTION when DROP instruction is explicitly specified. + * + * @return the traffic treatment builder + */ @Override public Builder drop() { - return add(Instructions.createDrop()); + return add(Instructions.createNoAction()); + } + + /** + * Add a NOACTION when no instruction is specified. + * + * @return the traffic treatment builder + */ + private Builder noAction() { + return add(Instructions.createNoAction()); } @Override @@ -380,11 +396,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { } @Override - public Builder transition(FlowRule.Type type) { - return add(Instructions.transition(type.ordinal())); - } - - @Override public Builder transition(Integer tableId) { return add(Instructions.transition(tableId)); } @@ -463,14 +474,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { @Override public TrafficTreatment build() { - //Don't add DROP instruction by default when instruction - //set is empty. This will be handled in DefaultSingleTablePipeline - //driver. - - //if (deferred.size() == 0 && immediate.size() == 0 - // && table == null && !clear) { - // drop(); - //} + if (deferred.size() == 0 && immediate.size() == 0 + && table == null && !clear) { + immediate(); + noAction(); + } return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java new file mode 100644 index 00000000..afceb14e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java @@ -0,0 +1,122 @@ +/*
+ * 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.net.flow;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default flow entry class with FlowLiveType value, IMMEDIATE_FLOW, SHORT_FLOW, MID_FLOW, LONG_FLOW.
+ */
+public class DefaultTypedFlowEntry extends DefaultFlowEntry
+ implements TypedStoredFlowEntry {
+ private FlowLiveType liveType;
+
+ /**
+ * Creates a typed flow entry from flow rule and its statistics, with default flow live type(IMMEDIATE_FLOW).
+ *
+ * @param rule the flow rule
+ * @param state the flow state
+ * @param life the flow duration since creation
+ * @param packets the flow packets count
+ * @param bytes the flow bytes count
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule, FlowEntryState state,
+ long life, long packets, long bytes) {
+ super(rule, state, life, packets, bytes);
+ this.liveType = FlowLiveType.IMMEDIATE_FLOW;
+ }
+
+ /**
+ * Creates a typed flow entry from flow rule, with default flow live type(IMMEDIATE_FLOW).
+ *
+ * @param rule the flow rule
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule) {
+ super(rule);
+ this.liveType = FlowLiveType.IMMEDIATE_FLOW;
+ }
+
+ /**
+ * Creates a typed flow entry from flow entry, with default flow live type(IMMEDIATE_FLOW).
+ *
+ * @param fe the flow entry
+ *
+ */
+ public DefaultTypedFlowEntry(FlowEntry fe) {
+ super(fe, fe.state(), fe.life(), fe.packets(), fe.bytes());
+ this.liveType = FlowLiveType.IMMEDIATE_FLOW;
+ }
+
+ /**
+ * Creates a typed flow entry from flow rule and flow live type.
+ *
+ * @param rule the flow rule
+ * @param liveType the flow live type
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule, FlowLiveType liveType) {
+ super(rule);
+ this.liveType = liveType;
+ }
+
+ /**
+ * Creates a typed flow entry from flow entry and flow live type.
+ *
+ * @param fe the flow rule
+ * @param liveType the flow live type
+ *
+ */
+ public DefaultTypedFlowEntry(FlowEntry fe, FlowLiveType liveType) {
+ super(fe, fe.state(), fe.life(), fe.packets(), fe.bytes());
+ this.liveType = liveType;
+ }
+
+ /**
+ * Creates a typed flow entry from flow rule, error code and flow live type.
+ *
+ * @param rule the flow rule
+ * @param errType the flow error type
+ * @param errCode the flow error code
+ * @param liveType the flow live type
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule, int errType, int errCode, FlowLiveType liveType) {
+ super(rule, errType, errCode);
+ this.liveType = liveType;
+ }
+
+ @Override
+ public FlowLiveType flowLiveType() {
+ return this.liveType;
+ }
+
+ @Override
+ public void setFlowLiveType(FlowLiveType liveType) {
+ this.liveType = liveType;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("entry", super.toString())
+ .add("type", liveType)
+ .toString();
+ }
+}
+
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java index a487cbc4..35d45fbd 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java @@ -29,43 +29,6 @@ public interface FlowRule { int MIN_PRIORITY = 0; /** - * The FlowRule type is used to determine in which table the flow rule needs - * to be put for multi-table support switch. For single table switch, - * Default is used. - * - * @deprecated in Cardinal Release - */ - @Deprecated - enum Type { - /* - * Default type - used in flow rule for single table switch NOTE: this - * setting should not be used as Table 0 in a multi-table pipeline - */ - DEFAULT, - /* Used in flow entry for IP table */ - IP, - /* Used in flow entry for MPLS table */ - MPLS, - /* Used in flow entry for ACL table */ - ACL, - - /* VLAN-to-MPLS table */ - VLAN_MPLS, - - /* VLAN table */ - VLAN, - - /* Ethtype table */ - ETHER, - - /* Class of Service table */ - COS, - - /* Table 0 in a multi-table pipeline */ - FIRST, - } - - /** * Returns the ID of this flow. * * @return the flow ID diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java index 8a36a921..aefa96b4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java @@ -15,6 +15,8 @@ */ package org.onosproject.net.flow; +import java.util.List; + import org.onosproject.net.DeviceId; import org.onosproject.net.provider.ProviderService; @@ -41,6 +43,24 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries); /** + * Pushes the collection of flow entries currently applied on the given + * device without flowMissing process. + * + * @param deviceId device identifier + * @param flowEntries collection of flow rules + */ + void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries); + + /** + * Pushes the collection of table statistics entries currently extracted + * from the given device. + * + * @param deviceId device identifier + * @param tableStatsEntries collection of flow table statistics entries + */ + void pushTableStatistics(DeviceId deviceId, List<TableStatisticsEntry> tableStatsEntries); + + /** * Indicates to the core that the requested batch operation has * been completed. * @@ -48,5 +68,4 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide * @param operation the resulting outcome of the operation */ void batchOperationCompleted(long batchId, CompletedBatchOperation operation); - } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java index d4f959c3..ee8d5a98 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java @@ -104,4 +104,11 @@ public interface FlowRuleService */ void apply(FlowRuleOperations ops); + /** + * Returns the collection of flow table statistics of the specified device. + * + * @param deviceId device identifier + * @return collection of flow table statistics + */ + Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java index cece9893..d81c73c9 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java @@ -15,6 +15,8 @@ */ package org.onosproject.net.flow; +import java.util.List; + import org.onosproject.net.DeviceId; import org.onosproject.store.Store; @@ -93,4 +95,23 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe * @return flow_removed event, or null if nothing removed */ FlowRuleEvent removeFlowRule(FlowEntry rule); + + /** + * Updates the flow table statistics of the specified device using + * the given statistics. + * + * @param deviceId device identifier + * @param tableStats list of table statistics + * @return ready to send event describing what occurred; + */ + FlowRuleEvent updateTableStatistics(DeviceId deviceId, + List<TableStatisticsEntry> tableStats); + + /** + * Returns the flow table statistics associated with a device. + * + * @param deviceId the device ID + * @return the flow table statistics + */ + Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java new file mode 100644 index 00000000..563f31ce --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java @@ -0,0 +1,59 @@ +/* + * 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.net.flow; + +import org.onosproject.net.DeviceId; + +/** + * Interface for flow table statistics of a device. + */ +public interface TableStatisticsEntry { + + /** + * Returns the device Id. + * + * @return device id + */ + DeviceId deviceId(); + + /** + * Returns the table number. + * + * @return table number + */ + int tableId(); + + /** + * Returns the number of active flow entries in this table. + * + * @return the number of active flow entries + */ + long activeFlowEntries(); + + /** + * Returns the number of packets looked up in the table. + * + * @return the number of packets looked up in the table + */ + long packetsLookedup(); + + /** + * Returns the number of packets that successfully matched in the table. + * + * @return the number of packets that successfully matched in the table + */ + long packetsMatched(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java index 534f6b9e..1286ffc1 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java @@ -386,30 +386,6 @@ public interface TrafficSelector { Builder matchIPv6ExthdrFlags(short exthdrFlags); /** - * Matches an optical signal ID or lambda. - * - * @param lambda lambda - * @return a selection builder - * @deprecated in Cardinal Release. - * Use {@link #add(Criterion)} with an instance created - * by {@link org.onosproject.net.flow.criteria.Criteria#matchLambda(org.onosproject.net.Lambda)}. - */ - @Deprecated - Builder matchLambda(short lambda); - - /** - * Matches an optical Signal Type. - * - * @param signalType signalType - * @return a selection builder - * @deprecated in Cardinal Release. - * Use {@link #add(Criterion)}} with an instance created - * by {@link org.onosproject.net.flow.criteria.Criteria#matchOchSignalType(org.onosproject.net.OchSignalType)}. - */ - @Deprecated - Builder matchOpticalSignalType(short signalType); - - /** * Builds an immutable traffic selector. * * @return traffic selector diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java index 1ce669c2..33753afa 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java @@ -269,16 +269,6 @@ public interface TrafficTreatment { Builder meter(MeterId meterId); /** - * Sets the next table type to transition to. - * - * @param type the table type - * @return a treatement builder - * @deprecated in Cardinal Release - */ - @Deprecated - Builder transition(FlowRule.Type type); - - /** * Sets the next table id to transition to. * * @param tableId the table table diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java new file mode 100644 index 00000000..a93dc071 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java @@ -0,0 +1,65 @@ +/*
+ * 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.net.flow;
+
+/**
+ * Represents a flow live type for a given flow entry.
+ */
+public interface TypedStoredFlowEntry extends StoredFlowEntry {
+ enum FlowLiveType {
+ /**
+ * Indicates that this rule has been submitted for addition immediately.
+ * Not necessarily collecting flow stats.
+ */
+ IMMEDIATE_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for a short time.
+ * Necessarily collecting flow stats every calAndPollInterval.
+ */
+ SHORT_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for a mid time.
+ * Necessarily collecting flow stats every midPollInterval.
+ */
+ MID_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for a long time.
+ * Necessarily collecting flow stats every longPollInterval.
+ */
+ LONG_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for UNKNOWN or ERROR.
+ * Not necessarily collecting flow stats.
+ */
+ UNKNOWN_FLOW
+ }
+
+ /**
+ * Gets the flow live type for this entry.
+ */
+ FlowLiveType flowLiveType();
+
+ /**
+ * Sets the new flow live type for this entry.
+ * @param liveType new flow live type.
+ */
+ void setFlowLiveType(FlowLiveType liveType);
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java index 0252cfbc..7e1d43a5 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java @@ -461,18 +461,6 @@ public final class Criteria { } /** - * Creates a match on lambda field using the specified value. - * - * @param lambda lambda to match on (16 bits unsigned integer) - * @return match criterion - * @deprecated in Cardinal Release. Use {@link #matchLambda(Lambda)} instead. - */ - @Deprecated - public static Criterion matchLambda(int lambda) { - return new LambdaCriterion(lambda, Type.OCH_SIGID); - } - - /** * Creates a match on lambda using the specified value. * * @param lambda lambda @@ -489,18 +477,6 @@ public final class Criteria { } /** - * Creates a match on optical signal type using the specified value. - * - * @param sigType optical signal type (8 bits unsigned integer) - * @return match criterion - * @deprecated in Cardinal Release - */ - @Deprecated - public static Criterion matchOpticalSignalType(short sigType) { - return new OpticalSignalTypeCriterion(sigType, Type.OCH_SIGTYPE); - } - - /** * Create a match on OCh (Optical Channel) signal type. * * @param signalType OCh signal type diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java index 6f2cac6b..d01ea298 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java @@ -27,9 +27,18 @@ public interface Instruction { /** * Signifies that the traffic should be dropped. */ + @Deprecated DROP, /** + * Signifies that the traffic requires no action. + * + * In OF10, the behavior of NOACTION is DROP. + * In OF13, the behavior depends on current Action Set. + */ + NOACTION, + + /** * Signifies that the traffic should be output to a port. */ OUTPUT, diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java index c5358a29..c9f10685 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java @@ -68,11 +68,21 @@ public final class Instructions { * * @return drop instruction */ + @Deprecated public static DropInstruction createDrop() { return new DropInstruction(); } /** + * Creates a no action instruction. + * + * @return no action instruction + */ + public static NoActionInstruction createNoAction() { + return new NoActionInstruction(); + } + + /** * Creates a group instruction. * * @param groupId Group Id @@ -89,19 +99,6 @@ public final class Instructions { } /** - * Creates a l0 modification. - * - * @param lambda the lambda to modify to - * @return a l0 modification - * @deprecated in Cardinal Release. Use {@link #modL0Lambda(Lambda)} instead. - */ - @Deprecated - public static L0ModificationInstruction modL0Lambda(short lambda) { - checkNotNull(lambda, "L0 lambda cannot be null"); - return new ModLambdaInstruction(L0SubType.LAMBDA, lambda); - } - - /** * Creates an L0 modification with the specified OCh signal. * * @param lambda OCh signal @@ -303,21 +300,6 @@ public final class Instructions { * * @param etherType Ethernet type to set * @return a L2 modification. - * @deprecated in Cardinal Release - */ - @Deprecated - public static Instruction popMpls(int etherType) { - checkNotNull(etherType, "Ethernet type cannot be null"); - return new L2ModificationInstruction.PushHeaderInstructions( - L2ModificationInstruction.L2SubType.MPLS_POP, new EthType(etherType)); - } - - - /** - * Creates a pop MPLS header instruction with a particular ethertype. - * - * @param etherType Ethernet type to set - * @return a L2 modification. */ public static Instruction popMpls(EthType etherType) { checkNotNull(etherType, "Ethernet type cannot be null"); @@ -478,6 +460,7 @@ public final class Instructions { /** * Drop instruction. */ + @Deprecated public static final class DropInstruction implements Instruction { private DropInstruction() {} @@ -510,6 +493,40 @@ public final class Instructions { } /** + * No Action instruction. + */ + public static final class NoActionInstruction implements Instruction { + + private NoActionInstruction() {} + + @Override + public Type type() { + return Type.NOACTION; + } + + @Override + public String toString() { + return toStringHelper(type().toString()).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NoActionInstruction) { + return true; + } + return false; + } + } + + /** * Output Instruction. */ public static final class OutputInstruction implements Instruction { diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java index f7b7c499..068663bd 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java @@ -15,6 +15,7 @@ */ package org.onosproject.net.host; +import org.onlab.packet.IpAddress; import org.onosproject.net.HostId; import org.onosproject.net.provider.ProviderService; @@ -29,6 +30,7 @@ public interface HostProviderService extends ProviderService<HostProvider> { * * @param hostId id of the host that been detected * @param hostDescription description of host and its location + * @deprecated in Drake release */ @Deprecated default void hostDetected(HostId hostId, HostDescription hostDescription) { @@ -52,4 +54,11 @@ public interface HostProviderService extends ProviderService<HostProvider> { */ void hostVanished(HostId hostId); + /** + * Notifies the core when a host is no longer detected on a network. + * + * @param hostId id of the host that vanished + */ + void removeIpFromHost(HostId hostId, IpAddress ipAddress); + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java index 5894fe92..918ced45 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java @@ -55,6 +55,15 @@ public interface HostStore extends Store<HostEvent, HostStoreDelegate> { HostEvent removeHost(HostId hostId); /** + * Removes the specified ip from the host entry. + * + * @param hostId host identification + * @param ipAddress ipAddress to be removed + * @return remove event or null if host was not found + */ + HostEvent removeIp(HostId hostId, IpAddress ipAddress); + + /** * Returns the number of hosts in the store. * * @return host count diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java index 0646a003..2a2d7c78 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java @@ -23,7 +23,6 @@ import org.onosproject.net.NetworkResource; import org.onosproject.net.flow.FlowRule; import java.util.Collection; -import java.util.Collections; import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -38,18 +37,6 @@ public class FlowRuleIntent extends Intent { private final Collection<FlowRule> flowRules; /** - * Creates an flow rule intent with the specified flow rules to be set. - * - * @param appId application id - * @param flowRules flow rules to be set. - * @deprecated in Cardinal Release - */ - @Deprecated - public FlowRuleIntent(ApplicationId appId, List<FlowRule> flowRules) { - this(appId, null, flowRules, Collections.emptyList()); - } - - /** * Creates a flow rule intent with the specified flow rules and resources. * * @param appId application id diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java new file mode 100644 index 00000000..979194c3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java @@ -0,0 +1,118 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import org.onosproject.event.AbstractEvent; +import org.onosproject.net.ConnectPoint; + +import java.util.Optional; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * An entity representing a multicast event. Event either add or remove + * sinks or sources. + */ +@Beta +public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> { + + private final Optional<ConnectPoint> sink; + private final Optional<ConnectPoint> source; + + public enum Type { + /** + * A new mcast route has been added. + */ + ROUTE_ADDED, + + /** + * A mcast route has been removed. + */ + ROUTE_REMOVED, + + /** + * A source for a mcast route (ie. the subject) has been added. + */ + SOURCE_ADDED, + + /** + * A sink for a mcast route (ie. the subject) has been added. + */ + SINK_ADDED, + + /** + * A source for a mcast route (ie. the subject) has been removed. + */ + SINK_REMOVED + } + + private McastEvent(McastEvent.Type type, McastRoute subject) { + super(type, subject); + sink = Optional.empty(); + source = Optional.empty(); + } + + private McastEvent(McastEvent.Type type, McastRoute subject, long time) { + super(type, subject, time); + sink = Optional.empty(); + source = Optional.empty(); + } + + public McastEvent(McastEvent.Type type, McastRoute subject, + ConnectPoint sink, + ConnectPoint source) { + super(type, subject); + this.sink = Optional.ofNullable(sink); + this.source = Optional.ofNullable(source); + } + + public McastEvent(McastEvent.Type type, McastRoute subject, long time, + ConnectPoint sink, + ConnectPoint source) { + super(type, subject, time); + this.sink = Optional.ofNullable(sink); + this.source = Optional.ofNullable(source); + } + + /** + * The sink which has been removed or added. The field may not be set + * if the sink has not been detected yet or has been removed. + * + * @return an optional connect point + */ + public Optional<ConnectPoint> sink() { + return sink; + } + + /** + * The source which has been removed or added. + + * @return an optional connect point + */ + public Optional<ConnectPoint> source() { + return source; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("type", type()) + .add("route", subject()) + .add("source", source) + .add("sinks", sink).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java new file mode 100644 index 00000000..06449b99 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java @@ -0,0 +1,26 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import org.onosproject.event.EventListener; + +/** + * A listener interface for multicast events. + */ +@Beta +public interface McastListener extends EventListener<McastEvent> { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java new file mode 100644 index 00000000..ff1292bf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java @@ -0,0 +1,117 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import org.onlab.packet.IpPrefix; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An entity representing a multicast route consisting of a source + * and a multicast group address. + */ +@Beta +public class McastRoute { + + public enum Type { + /** + * Route originates from PIM. + */ + PIM, + + /** + * Route originates from IGMP. + */ + IGMP, + + /** + * Route originates from other config (ie. REST, CLI). + */ + STATIC + } + + private final IpPrefix source; + private final IpPrefix group; + private final Type type; + + public McastRoute(IpPrefix source, IpPrefix group, Type type) { + checkNotNull(source, "Multicast route must have a source"); + checkNotNull(group, "Multicast route must specify a group address"); + checkNotNull(type, "Must indicate what type of route"); + this.source = source; + this.group = group; + this.type = type; + } + + /** + * Fetches the source address of this route. + * + * @return an ip address + */ + public IpPrefix source() { + return source; + } + + /** + * Fetches the group address of this route. + * + * @return an ip address + */ + public IpPrefix group() { + return group; + } + + /** + * Obtains how this route was created. + * @return a type of route + + */ + public Type type() { + return type; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("source", source) + .add("group", group) + .add("origin", type) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + McastRoute that = (McastRoute) o; + return Objects.equal(source, that.source) && + Objects.equal(group, that.group) && + Objects.equal(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hashCode(source, group, type); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java new file mode 100644 index 00000000..56e87c55 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java @@ -0,0 +1,84 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import org.onosproject.net.ConnectPoint; + +import java.util.List; + +/** + * A service interface for maintaining multicast information. + */ +@Beta +public interface MulticastRouteService { + + /** + * Adds a route to the information base. + * + * @param route a multicast route + */ + void add(McastRoute route); + + /** + * Removes a route from the information base. + * + * @param route a multicast route + */ + void remove(McastRoute route); + + /** + * Adds a source connection to the route from where the + * data stream is originating. + * + * @param route the multicast route + * @param connectPoint a source connect point + */ + void addSource(McastRoute route, ConnectPoint connectPoint); + + /** + * Adds a sink to the route to which a data stream should be + * sent to. + * + * @param route a multicast route + * @param connectPoint a sink connect point + */ + void addSink(McastRoute route, ConnectPoint connectPoint); + + /** + * Removes a sink from the route. + * + * @param route the multicast route + * @param connectPoint a sink connect point + */ + void removeSink(McastRoute route, ConnectPoint connectPoint); + + /** + * Find the data source association for this multicast route. + * + * @param route a multicast route + * @return a connect point + */ + ConnectPoint fetchSource(McastRoute route); + + /** + * Find the list of sinks for this route. + * + * @param route a multicast route + * @return a list of connect points + */ + List<ConnectPoint> fetchSinks(McastRoute route); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java new file mode 100644 index 00000000..e8dcc7b8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/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. + */ + +/** + * External model entities of the multicast RIB. + */ +package org.onosproject.net.mcast;
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java index 94cada47..51394c30 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java @@ -43,7 +43,8 @@ public final class DefaultMeterRequest implements MeterRequest { private DefaultMeterRequest(DeviceId deviceId, ApplicationId appId, Meter.Unit unit, boolean burst, - Collection<Band> bands, MeterContext context, Type op) { + Collection<Band> bands, MeterContext context, + Type op) { this.deviceId = deviceId; this.appId = appId; this.unit = unit; @@ -58,6 +59,7 @@ public final class DefaultMeterRequest implements MeterRequest { return deviceId; } + @Override public ApplicationId appId() { return appId; @@ -107,6 +109,7 @@ public final class DefaultMeterRequest implements MeterRequest { private Collection<Band> bands; private DeviceId deviceId; private MeterContext context; + private Optional<MeterId> desiredId = Optional.empty(); @Override diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java new file mode 100644 index 00000000..5bc01b02 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java @@ -0,0 +1,72 @@ +/* + * 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.net.meter; + +import com.google.common.base.Objects; +import org.onosproject.net.DeviceId; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * A meter key represents a meter uniquely. + */ +public final class MeterKey { + + private final DeviceId deviceId; + private final MeterId id; + + private MeterKey(DeviceId deviceId, MeterId id) { + this.deviceId = deviceId; + this.id = id; + } + + public DeviceId deviceId() { + return deviceId; + } + + public MeterId meterId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MeterKey meterKey = (MeterKey) o; + return Objects.equal(deviceId, meterKey.deviceId) && + Objects.equal(id, meterKey.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(deviceId, id); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("deviceId", deviceId) + .add("meterId", id).toString(); + } + + public static MeterKey key(DeviceId deviceId, MeterId id) { + return new MeterKey(deviceId, id); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java index bdc90eb7..2e07cb67 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java @@ -16,6 +16,7 @@ package org.onosproject.net.meter; import org.onosproject.event.ListenerService; +import org.onosproject.net.DeviceId; import java.util.Collection; @@ -46,10 +47,11 @@ public interface MeterService /** * Fetch the meter by the meter id. * + * @param deviceId a device id * @param id a meter id * @return a meter */ - Meter getMeter(MeterId id); + Meter getMeter(DeviceId deviceId, MeterId id); /** * Fetches all the meters. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java index 5112a4a3..f429e95a 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java @@ -57,12 +57,12 @@ public interface MeterStore extends Store<MeterEvent, MeterStoreDelegate> { void updateMeterState(Meter meter); /** - * Obtains a meter matching the given meter id. + * Obtains a meter matching the given meter key. * - * @param meterId a meter id + * @param key a meter key * @return a meter */ - Meter getMeter(MeterId meterId); + Meter getMeter(MeterKey key); /** * Returns all meters stored in the store. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java index 618042a3..82d84743 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java @@ -125,6 +125,15 @@ public interface ResourceService { boolean release(ResourceConsumer consumer); /** + * Returns resource allocation of the specified resource. + * + * @param resource resource to check the allocation + * @return allocation information enclosed by Optional. + * If the resource is not allocated, the return value is empty. + */ + Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource); + + /** * Returns allocated resources being as children of the specified parent and being the specified resource type. * * @param parent parent resource path diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java new file mode 100644 index 00000000..40386fb7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java @@ -0,0 +1,58 @@ +/* + * 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.net.packet; + +/** + * Packet processor entry tracking the processor, its priority and + * time consumption. + */ +public interface PacketProcessorEntry { + + /** + * Returns the packet processor. + * + * @return packet processor + */ + PacketProcessor processor(); + + /** + * Returns the packet processor priority. + * + * @return processor priority + */ + int priority(); + + /** + * Returns the number of invocations. + * + * @return number of invocations + */ + long invocations(); + + /** + * Returns the total time, in nanoseconds, spent processing packets. + * + * @return total time in nanos + */ + long totalNanos(); + + /** + * Returns the average time, in nanoseconds, spent processing packets. + * + * @return average time in nanos + */ + long averageNanos(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java index 98f4d8e0..2e7a1b91 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java @@ -20,7 +20,6 @@ import org.onosproject.core.ApplicationId; import org.onosproject.net.flow.TrafficSelector; import java.util.List; -import java.util.Map; /** * Service for intercepting data plane packets and for emitting synthetic @@ -52,13 +51,12 @@ public interface PacketService { void removeProcessor(PacketProcessor processor); /** - * Returns priority bindings of all registered packet processors. + * Returns priority bindings of all registered packet processor entries. * - * @return list of existing packet processors + * @return list of existing packet processor entries */ @Beta - // TODO: Consider returning list of PacketProcessorEntry with processor, priority and stats - Map<Integer, PacketProcessor> getProcessors(); + List<PacketProcessorEntry> getProcessors(); /** * Requests that packets matching the given selector are punted from the diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java index 97f7cb55..d83fc9a2 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java @@ -37,17 +37,15 @@ public interface PacketStore extends Store<PacketEvent, PacketStoreDelegate> { * Requests intercept of packets that match the given selector. * * @param request a packet request - * @return true if the first time the given selector was requested */ - boolean requestPackets(PacketRequest request); + void requestPackets(PacketRequest request); /** * Cancels intercept of packets that match the given selector. * * @param request a packet request - * @return true if there is no other application requesting the given selector */ - boolean cancelPackets(PacketRequest request); + void cancelPackets(PacketRequest request); /** * Obtains all existing requests in the system. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java index bf5c3cc0..2e59b19d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java @@ -21,4 +21,20 @@ import org.onosproject.store.StoreDelegate; * Packet store delegate abstraction. */ public interface PacketStoreDelegate extends StoreDelegate<PacketEvent> { + + /** + * Requests that packets matching to following request be collected + * from all switches. + * + * @param request packet request + */ + void requestPackets(PacketRequest request); + + /** + * Requests that packets matching to following request no longer be + * collected from any switches. + * + * @param request packet request + */ + void cancelPackets(PacketRequest request); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java new file mode 100644 index 00000000..67c539df --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java @@ -0,0 +1,47 @@ +/* + * 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.net.resource.device; + +import org.onosproject.net.intent.IntentId; + +import java.util.Set; + +public interface IntentSetMultimap { + + /** + * Allocates the mapping between the given intents. + * + * @param keyIntentId key intent ID + * @param valIntentId value intent ID + * @return true if mapping was successful, false otherwise + */ + boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId); + + /** + * Returns the set of intents mapped to a lower intent. + * + * @param intentId intent ID + * @return set of intent IDs + */ + Set<IntentId> getMapping(IntentId intentId); + + /** + * Releases the mapping of the given intent. + * + * @param intentId intent ID + */ + void releaseMapping(IntentId intentId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java index 91cc3d19..e07309cb 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java @@ -64,7 +64,7 @@ public class BandwidthResourceRequest implements ResourceRequest { if (obj == null || getClass() != obj.getClass()) { return false; } - final BandwidthResourceAllocation other = (BandwidthResourceAllocation) obj; + final BandwidthResourceRequest other = (BandwidthResourceRequest) obj; return Objects.equals(this.bandwidth, other.bandwidth()); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java new file mode 100644 index 00000000..f59670bc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java @@ -0,0 +1,105 @@ +/*
+ * 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.net.statistic;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.instructions.Instruction;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service for obtaining individual flow statistic information about device and link in the system.
+ * Basic statistics are obtained from the StatisticService
+ */
+public interface FlowStatisticService {
+
+ /**
+ * Obtain the summary load list for the device with the given link.
+ *
+ * @param device the Device to query.
+ * @return map of summary flow entry load
+ */
+ Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device);
+
+ /**
+ * Obtain the summary load for the device with the given link or port.
+ *
+ * @param device the Device to query.
+ * @param pNumber the port number to query.
+ * @return summary flow entry load
+ */
+ SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber);
+
+ /**
+ * Obtain the set of the flow type and load list for the device with the given link.
+ *
+ * @param device the Device to query.
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @return map of flow entry load
+ */
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType);
+
+ /**
+ * Obtain the flow type and load list for the device with the given link or port.
+ *
+ * @param device the Device to query.
+ * @param pNumber the port number of the Device to query
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @return list of flow entry load
+ */
+ List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType);
+
+ /**
+ * Obtain the set of the flow type and load topn list for the device with the given link.
+ *
+ * @param device the Device to query.
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @param topn the top number to filter, null means no filtering.
+ * @return map of flow entry load
+ */
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn);
+
+ /**
+ * Obtain the flow type and load topn list for the device with the given link or port.
+ *
+ * @param device the Device to query.
+ * @param pNumber the port number of the Device to query
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @return list of flow entry load
+ */
+ List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn);
+}
+
+
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java new file mode 100644 index 00000000..3c2aa89b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java @@ -0,0 +1,65 @@ +/*
+ * 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.net.statistic;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+
+import java.util.Set;
+
+/**
+ * Flow Store to house the computed statistics.
+ */
+public interface FlowStatisticStore {
+ /**
+ * Remove entries associated with this rule.
+ *
+ * @param rule {@link org.onosproject.net.flow.FlowRule}
+ */
+ void removeFlowStatistic(FlowRule rule);
+
+ /**
+ * Adds a flow stats observation for a flow rule. The previous flow will be removed.
+ *
+ * @param rule a {@link org.onosproject.net.flow.FlowEntry}
+ */
+ void addFlowStatistic(FlowEntry rule);
+
+ /**
+ * Updates a stats observation for a flow rule. The old flow stats will be moved to previous stats.
+ *
+ * @param rule a {@link org.onosproject.net.flow.FlowEntry}
+ */
+ void updateFlowStatistic(FlowEntry rule);
+
+ /**
+ * Fetches the current observed flow stats values.
+ *
+ * @param connectPoint the port to fetch information for
+ * @return set of current flow rules
+ */
+ Set<FlowEntry> getCurrentFlowStatistic(ConnectPoint connectPoint);
+
+ /**
+ * Fetches the current observed flow stats values.
+ *
+ * @param connectPoint the port to fetch information for
+ * @return set of current values
+ */
+ Set<FlowEntry> getPreviousFlowStatistic(ConnectPoint connectPoint);
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java new file mode 100644 index 00000000..60da636a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java @@ -0,0 +1,143 @@ +/*
+ * 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.net.statistic;
+
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Summary Load classified by flow live type.
+ */
+public class SummaryFlowEntryWithLoad {
+ private ConnectPoint cp;
+ private Load totalLoad;
+ private Load immediateLoad;
+ private Load shortLoad;
+ private Load midLoad;
+ private Load longLoad;
+ private Load unknownLoad;
+
+ /**
+ * Creates a new summary flow entry having load for the given connect point and total load.
+ *
+ * @param cp connect point
+ * @param totalLoad total load
+ */
+ public SummaryFlowEntryWithLoad(ConnectPoint cp, Load totalLoad) {
+ this.cp = cp;
+ this.totalLoad = totalLoad;
+ this.immediateLoad = new DefaultLoad();
+ this.shortLoad = new DefaultLoad();
+ this.midLoad = new DefaultLoad();
+ this.longLoad = new DefaultLoad();
+ this.unknownLoad = new DefaultLoad();
+ }
+
+ /**
+ * Creates a new summary flow entry having load for the given connect point
+ * and total, immediate, short, mid, and long load.
+ *
+ * @param cp connect point
+ * @param totalLoad total load
+ * @param immediateLoad immediate load
+ * @param shortLoad short load
+ * @param midLoad mid load
+ * @param longLoad long load
+ */
+ public SummaryFlowEntryWithLoad(ConnectPoint cp,
+ Load totalLoad, Load immediateLoad, Load shortLoad, Load midLoad, Load longLoad) {
+ this.cp = cp;
+ this.totalLoad = totalLoad;
+ this.immediateLoad = immediateLoad;
+ this.shortLoad = shortLoad;
+ this.midLoad = midLoad;
+ this.longLoad = longLoad;
+ this.unknownLoad = new DefaultLoad();
+ }
+
+ /**
+ * Creates a new summary flow entry having load for the given connect point
+ * and total, immediate, short, mid, long, and unknown load.
+ *
+ * @param cp connect point
+ * @param totalLoad total load
+ * @param immediateLoad immediate load
+ * @param shortLoad short load
+ * @param midLoad mid load
+ * @param longLoad long load
+ * @param unknownLoad long load
+ */
+ public SummaryFlowEntryWithLoad(ConnectPoint cp,
+ Load totalLoad, Load immediateLoad,
+ Load shortLoad, Load midLoad, Load longLoad, Load unknownLoad) {
+ this.cp = cp;
+ this.totalLoad = totalLoad;
+ this.immediateLoad = immediateLoad;
+ this.shortLoad = shortLoad;
+ this.midLoad = midLoad;
+ this.longLoad = longLoad;
+ this.unknownLoad = unknownLoad;
+ }
+
+ /**
+ * Returns connect point.
+ */
+ public ConnectPoint connectPoint() {
+ return cp;
+ }
+
+ /**
+ * Returns total load of connect point.
+ */
+ public Load totalLoad() {
+ return totalLoad;
+ }
+
+ /**
+ * Returns immediate load of connect point.
+ */
+ public Load immediateLoad() {
+ return immediateLoad;
+ }
+
+ /**
+ * Returns short load of connect point.
+ */
+ public Load shortLoad() {
+ return shortLoad;
+ }
+
+ /**
+ * Returns mid load of connect point.
+ */
+ public Load midLoad() {
+ return midLoad;
+ }
+
+ /**
+ * Returns long load of connect point.
+ */
+ public Load longLoad() {
+ return longLoad;
+ }
+
+ /**
+ * Returns unknown load of connect point.
+ */
+ public Load unknownLoad() {
+ return unknownLoad;
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java new file mode 100644 index 00000000..3e2dbdf8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java @@ -0,0 +1,143 @@ +/*
+ * 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.net.statistic;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.DefaultTypedFlowEntry;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Load of flow entry of flow live type.
+ */
+public class TypedFlowEntryWithLoad {
+ private ConnectPoint cp;
+ private TypedStoredFlowEntry tfe;
+ private Load load;
+
+ //TODO: make this variables class, and share with NewAdaptivceFlowStatsCollector class
+ private static final int CAL_AND_POLL_INTERVAL = 5; // means SHORT_POLL_INTERVAL
+ private static final int MID_POLL_INTERVAL = 10;
+ private static final int LONG_POLL_INTERVAL = 15;
+
+
+ public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe, Load load) {
+ this.cp = cp;
+ this.tfe = tfe;
+ this.load = load;
+ }
+
+ public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe) {
+ this.cp = cp;
+ this.tfe = tfe;
+ this.load = new DefaultLoad(tfe.bytes(), 0, typedPollInterval(tfe));
+ }
+
+ public TypedFlowEntryWithLoad(ConnectPoint cp, FlowEntry fe) {
+ this.cp = cp;
+ this.tfe = newTypedStoredFlowEntry(fe);
+ this.load = new DefaultLoad(fe.bytes(), 0, typedPollInterval(this.tfe));
+ }
+
+ public ConnectPoint connectPoint() {
+ return cp;
+ }
+ public TypedStoredFlowEntry typedStoredFlowEntry() {
+ return tfe;
+ }
+ public Load load() {
+ return load;
+ }
+ public void setLoad(Load load) {
+ this.load = load;
+ }
+
+ /**
+ * Returns short polling interval.
+ */
+ public static int shortPollInterval() {
+ return CAL_AND_POLL_INTERVAL;
+ }
+
+ /**
+ * Returns mid polling interval.
+ */
+ public static int midPollInterval() {
+ return MID_POLL_INTERVAL;
+ }
+
+ /**
+ * Returns long polling interval.
+ */
+ public static int longPollInterval() {
+ return LONG_POLL_INTERVAL;
+ }
+
+ /**
+ * Returns average polling interval.
+ */
+ public static int avgPollInterval() {
+ return (CAL_AND_POLL_INTERVAL + MID_POLL_INTERVAL + LONG_POLL_INTERVAL) / 3;
+ }
+
+ /**
+ * Returns current typed flow entry's polling interval.
+ *
+ * @param tfe typed flow entry
+ */
+ public static long typedPollInterval(TypedStoredFlowEntry tfe) {
+ checkNotNull(tfe, "TypedStoredFlowEntry cannot be null");
+
+ switch (tfe.flowLiveType()) {
+ case LONG_FLOW:
+ return LONG_POLL_INTERVAL;
+ case MID_FLOW:
+ return MID_POLL_INTERVAL;
+ case SHORT_FLOW:
+ case IMMEDIATE_FLOW:
+ default:
+ return CAL_AND_POLL_INTERVAL;
+ }
+ }
+
+ /**
+ * Creates a new typed flow entry with the given flow entry fe.
+ *
+ * @param fe flow entry
+ */
+ public static TypedStoredFlowEntry newTypedStoredFlowEntry(FlowEntry fe) {
+ if (fe == null) {
+ return null;
+ }
+
+ long life = fe.life();
+
+ if (life >= LONG_POLL_INTERVAL) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.LONG_FLOW);
+ } else if (life >= MID_POLL_INTERVAL) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.MID_FLOW);
+ } else if (life >= CAL_AND_POLL_INTERVAL) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW);
+ } else if (life >= 0) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW);
+ } else { // life < 0
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW);
+ }
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java index f1e20dac..965c05d4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java @@ -50,23 +50,6 @@ public class DefaultGraphDescription extends AbstractDescription * and process the topology graph. * * @param nanos time in nanos of when the topology description was created - * @param devices collection of infrastructure devices - * @param links collection of infrastructure links - * @param annotations optional key/value annotations map - * @deprecated in Cardinal Release - */ - @Deprecated - public DefaultGraphDescription(long nanos, Iterable<Device> devices, - Iterable<Link> links, - SparseAnnotations... annotations) { - this(nanos, System.currentTimeMillis(), devices, links, annotations); - } - - /** - * Creates a minimal topology graph description to allow core to construct - * and process the topology graph. - * - * @param nanos time in nanos of when the topology description was created * @param millis time in millis of when the topology description was created * @param devices collection of infrastructure devices * @param links collection of infrastructure links diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java index be8c7cfc..0bd4d75d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java @@ -15,9 +15,12 @@ */ package org.onosproject.net.topology; +import org.onosproject.net.DisjointPath; import org.onosproject.net.ElementId; +import org.onosproject.net.Link; import org.onosproject.net.Path; +import java.util.Map; import java.util.Set; /** @@ -41,11 +44,58 @@ public interface PathService { * edge-weight entity, between the specified source and destination * network elements. * - * @param src source element - * @param dst destination element + * @param src source element + * @param dst destination element * @param weight edge-weight entity * @return set of all shortest paths between the two element */ Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight); + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst); + + /** + * Returns the set of all disjoint shortest path pairs, computed using the supplied + * edge-weight entity, between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, + LinkWeight weight); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, + Map<Link, Object> riskProfile); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, + LinkWeight weight, Map<Link, Object> riskProfile); + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java index 41eac2c4..466e4f9b 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java @@ -18,16 +18,18 @@ package org.onosproject.net.topology; import org.onosproject.event.ListenerService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; +import java.util.Map; import java.util.Set; /** * Service for providing network topology information. */ public interface TopologyService - extends ListenerService<TopologyEvent, TopologyListener> { + extends ListenerService<TopologyEvent, TopologyListener> { /** * Returns the current topology descriptor. @@ -72,8 +74,8 @@ public interface TopologyService /** * Returns the set of devices that belong to the specified cluster. * - * @param topology topology descriptor - * @param cluster topology cluster + * @param topology topology descriptor + * @param cluster topology cluster * @return set of cluster devices */ Set<DeviceId> getClusterDevices(Topology topology, TopologyCluster cluster); @@ -81,8 +83,8 @@ public interface TopologyService /** * Returns the set of links that form the specified cluster. * - * @param topology topology descriptor - * @param cluster topology cluster + * @param topology topology descriptor + * @param cluster topology cluster * @return set of cluster links */ Set<Link> getClusterLinks(Topology topology, TopologyCluster cluster); @@ -112,6 +114,57 @@ public interface TopologyService LinkWeight weight); /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst); + + /** + * Returns the set of all disjoint shortest path pairs, computed using the supplied + * edge-weight entity, between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map<Link, Object> riskProfile); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map<Link, Object> riskProfile); + + /** * Indicates whether the specified connection point is part of the network * infrastructure or part of network edge. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java index 983e616e..039a205c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java @@ -20,11 +20,13 @@ import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; import org.onosproject.net.Path; +import org.onosproject.net.DisjointPath; import org.onosproject.net.provider.ProviderId; import org.onosproject.store.Store; import java.util.List; import java.util.Set; +import java.util.Map; /** * Manages inventory of topology snapshots; not intended for direct use. @@ -112,6 +114,59 @@ public interface TopologyStore extends Store<TopologyEvent, TopologyStoreDelegat LinkWeight weight); /** + * Computes and returns the set of disjoint shortest path pairs + * between src and dst. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight link weight function + * @return set of shortest paths + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight); + + /** + * Computes and returns the set of disjoint shortest path pairs + * between src and dst. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @return set of shortest paths + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst); + + /** + * Computes and returns the set of SRLG disjoint shortest path pairs between source + * and dst, given a mapping of edges to SRLG risk groups. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight link weight function + * @param riskProfile map of edges to objects. Edges that map to the same object will + * be treated as if they were in the same risk group. + * @return set of shortest paths + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map<Link, Object> riskProfile); + + /** + * Returns the set of pre-computed SRLG shortest paths between src and dest. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param riskProfile map of edges to objects. Edges that map to the same object will + * be treated as if they were in the same risk group. + * @return set of shortest paths + */ + Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map<Link, Object> riskProfile); + + + /** * Indicates whether the given connect point is part of the network fabric. * * @param topology topology descriptor diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java index a879cc59..c0df7134 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java @@ -58,4 +58,21 @@ public interface AsyncAtomicCounter { * @return current value */ CompletableFuture<Long> get(); + + + /** + * Atomically sets the given value to the current value. + * + * @return future void + */ + CompletableFuture<Void> set(long value); + + /** + * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise + * no change occurs. + * @param expectedValue the expected current value of the counter + * @param updateValue the new value to be set + * @return true if the update occurred and the expected value was equal to the current value, false otherwise + */ + CompletableFuture<Boolean> compareAndSet(long expectedValue, long updateValue); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java index f620e082..3c9e02c8 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java @@ -51,6 +51,22 @@ public interface AtomicCounter { long addAndGet(long delta); /** + * Atomically sets the given value to the current value. + * + * @param value the value to set + */ + void set(long value); + + /** + * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise + * no change occurs. + * @param expectedValue the expected current value of the counter + * @param updateValue the new value to be set + * @return true if the update occurred and the expected value was equal to the current value, false otherwise + */ + boolean compareAndSet(long expectedValue, long updateValue); + + /** * Returns the current value of the counter without modifying it. * * @return current value diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java new file mode 100644 index 00000000..d05f3b91 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java @@ -0,0 +1,34 @@ +/* + * 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.store.service; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +/** + * Service for mutually exclusive job execution. + */ +public interface MutexExecutionService { + + /** + * Runs the specified task in a mutually exclusive fashion. + * @param task task to run + * @param exclusionPath path on which different instances synchronize + * @param executor executor to use for running the task + * @return future that is completed when the task execution completes. + */ + CompletableFuture<Void> execute(MutexTask task, String exclusionPath, Executor executor); +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java new file mode 100644 index 00000000..ba5ee47f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java @@ -0,0 +1,39 @@ +/* + * 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.store.service; + +/** + * The MutexTask interface should be implemented by any class whose + * instances distributed across controllers are intended to be executed + * in a mutually exclusive fashion. + */ +public interface MutexTask { + + /** + * Begins the execution of a mutually exclusive task. + * The start method will be called once the "lock" is acquired. + * After the start method returns the lock is released and some other + * instance can take over execution. + */ + void start(); + + /** + * This method will be called when exclusivity of task execution + * can no longer be guaranteed. The implementation should take necessary steps + * to halt task execution in order to ensure correctness. + */ + void stop(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java new file mode 100644 index 00000000..76f42466 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java @@ -0,0 +1,50 @@ +/* + * 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.ui.table.cell; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * Formats number using the specified format string". + */ +public final class NumberFormatter extends AbstractCellFormatter { + + private final NumberFormat format; + + /** + * Creates a formatter using a default decimal format. + */ + public NumberFormatter() { + this(new DecimalFormat("#,##0.00000")); + } + + /** + * Creates a formatter using the specified format. + * + * @param format number format + */ + public NumberFormatter(NumberFormat format) { + this.format = format; + } + + @Override + protected String nonNullFormat(Object value) { + return format.format(value); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java index a1abd188..0fccef81 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java @@ -17,10 +17,13 @@ package org.onosproject.cfg; import java.util.Set; +import com.google.common.collect.ImmutableSet; + /** * Adapter for testing against component configuration service. */ public class ComponentConfigAdapter implements ComponentConfigService { + @Override public Set<String> getComponentNames() { return null; @@ -38,7 +41,7 @@ public class ComponentConfigAdapter implements ComponentConfigService { @Override public Set<ConfigProperty> getProperties(String componentName) { - return null; + return ImmutableSet.of(); } @Override @@ -47,6 +50,10 @@ public class ComponentConfigAdapter implements ComponentConfigService { } @Override + public void preSetProperty(String componentName, String name, String value) { + } + + @Override public void unsetProperty(String componentName, String name) { } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java new file mode 100644 index 00000000..ece7f199 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java @@ -0,0 +1,112 @@ +/* + * 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.net.behaviour; + + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onlab.packet.IpAddress; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Test for ControllerInfo class. + */ +public class ControllerInfoTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void tcpSslFormat() { + String target = "tcp:192.168.1.1:6653"; + ControllerInfo controllerInfo = new ControllerInfo(target); + assertEquals("wrong type", controllerInfo.type(), "tcp"); + assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1")); + assertEquals("wrong port", controllerInfo.port(), 6653); + + } + + @Test + public void ptcpPsslFormat() { + String target = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo = new ControllerInfo(target); + assertEquals("wrong type", controllerInfo.type(), "ptcp"); + assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1")); + assertEquals("wrong port", controllerInfo.port(), 6653); + + } + + @Test + public void unixFormat() { + String target = "unix:file"; + thrown.expect(IllegalArgumentException.class); + ControllerInfo controllerInfo = new ControllerInfo(target); + assertTrue("wrong type", controllerInfo.type().contains("unix")); + assertNull("wrong ip", controllerInfo.ip()); + assertEquals("wrong port", controllerInfo.port(), -1); + + } + + @Test + public void defaultValues() { + String target = "tcp:192.168.1.1"; + ControllerInfo controllerInfo = new ControllerInfo(target); + assertEquals("wrong type", controllerInfo.type(), "tcp"); + assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1")); + assertEquals("wrong port", controllerInfo.port(), 6653); + String target1 = "ptcp:5000:"; + ControllerInfo controllerInfo2 = new ControllerInfo(target1); + assertEquals("wrong type", controllerInfo2.type(), "ptcp"); + assertEquals("wrong ip", controllerInfo2.ip(), IpAddress.valueOf("0.0.0.0")); + assertEquals("wrong port", controllerInfo2.port(), 5000); + String target2 = "ptcp:"; + ControllerInfo controllerInfo3 = new ControllerInfo(target2); + assertEquals("wrong type", controllerInfo3.type(), "ptcp"); + assertEquals("wrong ip", controllerInfo3.ip(), IpAddress.valueOf("0.0.0.0")); + assertEquals("wrong port", controllerInfo3.port(), 6653); + } + + + @Test + public void testEquals() { + String target1 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo1 = new ControllerInfo(target1); + String target2 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo2 = new ControllerInfo(target2); + assertTrue("wrong equals method", controllerInfo1.equals(controllerInfo2)); + } + + @Test + public void testListEquals() { + String target1 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo1 = new ControllerInfo(target1); + String target2 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo2 = new ControllerInfo(target2); + String target3 = "tcp:192.168.1.1:6653"; + ControllerInfo controllerInfo3 = new ControllerInfo(target3); + String target4 = "tcp:192.168.1.1:6653"; + ControllerInfo controllerInfo4 = new ControllerInfo(target4); + List<ControllerInfo> list1 = new ArrayList<>(Arrays.asList(controllerInfo1, controllerInfo3)); + List<ControllerInfo> list2 = new ArrayList<>(Arrays.asList(controllerInfo2, controllerInfo4)); + assertTrue("wrong equals list method", list1.equals(list2)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java index b70d14e8..73072583 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java @@ -29,7 +29,7 @@ public class NetworkConfigServiceAdapter implements NetworkConfigService { } @Override - public SubjectFactory getSubjectFactory(String subjectKey) { + public SubjectFactory getSubjectFactory(String subjectClassKey) { return null; } @@ -39,7 +39,7 @@ public class NetworkConfigServiceAdapter implements NetworkConfigService { } @Override - public Class<? extends Config> getConfigClass(String subjectKey, String configKey) { + public Class<? extends Config> getConfigClass(String subjectClassKey, String configKey) { return null; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java index b871397b..10c5a637 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java @@ -267,29 +267,5 @@ public class DefaultTrafficSelectorTest { selector = DefaultTrafficSelector.builder() .add(Criteria.matchLambda(new IndexedLambda(shortValue))).build(); assertThat(selector, hasCriterionWithType(Type.OCH_SIGID)); - - selector = DefaultTrafficSelector.builder() - .add(Criteria.matchOpticalSignalType(shortValue)).build(); - assertThat(selector, hasCriterionWithType(Type.OCH_SIGTYPE)); - } - - /** - * Tests the traffic selector builder. - */ - @Test - public void testTrafficSelectorBuilder() { - TrafficSelector selector; - final short shortValue = 33; - - final TrafficSelector baseSelector = DefaultTrafficSelector.builder() - .add(Criteria.matchLambda(new IndexedLambda(shortValue))).build(); - selector = DefaultTrafficSelector.builder(baseSelector) - .build(); - assertThat(selector, hasCriterionWithType(Type.OCH_SIGID)); - - final Criterion criterion = Criteria.matchLambda(shortValue); - selector = DefaultTrafficSelector.builder() - .add(criterion).build(); - assertThat(selector, hasCriterionWithType(Type.OCH_SIGID)); } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java index c7b78791..56e59118 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java @@ -35,17 +35,14 @@ public class FlowRuleServiceAdapter implements FlowRuleService { @Override public void applyFlowRules(FlowRule... flowRules) { - } @Override public void removeFlowRules(FlowRule... flowRules) { - } @Override public void removeFlowRulesById(ApplicationId appId) { - } @Override @@ -60,16 +57,18 @@ public class FlowRuleServiceAdapter implements FlowRuleService { @Override public void apply(FlowRuleOperations ops) { - } @Override public void addListener(FlowRuleListener listener) { - } @Override public void removeListener(FlowRuleListener listener) { + } + @Override + public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) { + return null; } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java index ee294f6f..95d605c6 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java @@ -225,12 +225,6 @@ public class CriteriaTest { Criterion matchIpv6ExthdrFlags2 = Criteria.matchIPv6ExthdrFlags(ipv6ExthdrFlags2); - int lambda1 = 1; - int lambda2 = 2; - Criterion matchLambda1 = Criteria.matchLambda(lambda1); - Criterion sameAsMatchLambda1 = Criteria.matchLambda(lambda1); - Criterion matchLambda2 = Criteria.matchLambda(lambda2); - Criterion matchOchSignalType1 = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID); Criterion sameAsMatchOchSignalType1 = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID); Criterion matchOchSignalType2 = Criteria.matchOchSignalType(OchSignalType.FLEX_GRID); @@ -239,12 +233,6 @@ public class CriteriaTest { Criterion sameAsMatchIndexedLambda1 = Criteria.matchLambda(Lambda.indexedLambda(1)); Criterion matchIndexedLambda2 = Criteria.matchLambda(Lambda.indexedLambda(2)); - short signalLambda1 = 1; - short signalLambda2 = 2; - Criterion matchSignalLambda1 = Criteria.matchOpticalSignalType(signalLambda1); - Criterion sameAsMatchSignalLambda1 = Criteria.matchOpticalSignalType(signalLambda1); - Criterion matchSignalLambda2 = Criteria.matchOpticalSignalType(signalLambda2); - Criterion matchOchSignal1 = Criteria.matchLambda(Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8)); Criterion sameAsMatchOchSignal1 = @@ -306,7 +294,6 @@ public class CriteriaTest { assertThatClassIsImmutable(MplsCriterion.class); assertThatClassIsImmutable(IPv6ExthdrFlagsCriterion.class); assertThatClassIsImmutable(LambdaCriterion.class); - assertThatClassIsImmutable(OpticalSignalTypeCriterion.class); } // PortCriterion class @@ -1057,32 +1044,6 @@ public class CriteriaTest { .testEquals(); } - // LambdaCriterion class - - /** - * Test the matchLambda method. - */ - @Test - public void testMatchLambdaMethod() { - Criterion matchLambda = Criteria.matchLambda(lambda1); - LambdaCriterion lambdaCriterion = - checkAndConvert(matchLambda, - Criterion.Type.OCH_SIGID, - LambdaCriterion.class); - assertThat(lambdaCriterion.lambda(), is(equalTo(lambda1))); - } - - /** - * Test the equals() method of the LambdaCriterion class. - */ - @Test - public void testLambdaCriterionEquals() { - new EqualsTester() - .addEqualityGroup(matchLambda1, sameAsMatchLambda1) - .addEqualityGroup(matchLambda2) - .testEquals(); - } - @Test public void testIndexedLambdaCriterionEquals() { new EqualsTester() @@ -1109,30 +1070,4 @@ public class CriteriaTest { .addEqualityGroup(matchOchSignalType2) .testEquals(); } - - // OpticalSignalTypeCriterion class - - /** - * Test the matchOpticalSignalType method. - */ - @Test - public void testMatchOpticalSignalTypeMethod() { - Criterion matchLambda = Criteria.matchOpticalSignalType(signalLambda1); - OpticalSignalTypeCriterion opticalSignalTypeCriterion = - checkAndConvert(matchLambda, - Criterion.Type.OCH_SIGTYPE, - OpticalSignalTypeCriterion.class); - assertThat(opticalSignalTypeCriterion.signalType(), is(equalTo(signalLambda1))); - } - - /** - * Test the equals() method of the OpticalSignalTypeCriterion class. - */ - @Test - public void testOpticalSignalTypeCriterionEquals() { - new EqualsTester() - .addEqualityGroup(matchSignalLambda1, sameAsMatchSignalLambda1) - .addEqualityGroup(matchSignalLambda2) - .testEquals(); - } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java index ac4ecff3..d42e22fa 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java @@ -17,7 +17,6 @@ package org.onosproject.net.intent; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableSet; - import org.onlab.util.Bandwidth; import org.onosproject.core.DefaultGroupId; import org.onosproject.core.GroupId; @@ -37,6 +36,9 @@ import org.onosproject.net.flow.criteria.Criterion.Type; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; import org.onosproject.net.resource.link.BandwidthResource; import org.onosproject.net.resource.link.BandwidthResourceRequest; import org.onosproject.net.resource.link.LambdaResource; @@ -48,13 +50,10 @@ import org.onosproject.net.resource.link.LinkResourceRequest; import org.onosproject.net.resource.link.LinkResourceService; import org.onosproject.net.resource.link.MplsLabel; import org.onosproject.net.resource.link.MplsLabelResourceAllocation; -import org.onosproject.net.resource.ResourceAllocation; -import org.onosproject.net.resource.ResourceRequest; -import org.onosproject.net.resource.ResourceType; import org.onosproject.net.topology.DefaultTopologyEdge; import org.onosproject.net.topology.DefaultTopologyVertex; import org.onosproject.net.topology.LinkWeight; -import org.onosproject.net.topology.PathService; +import org.onosproject.net.topology.PathServiceAdapter; import org.onosproject.net.topology.TopologyVertex; import org.onosproject.store.Timestamp; @@ -68,9 +67,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; -import static org.onosproject.net.NetTestTools.createPath; -import static org.onosproject.net.NetTestTools.did; -import static org.onosproject.net.NetTestTools.link; +import static org.onosproject.net.NetTestTools.*; /** * Common mocks used by the intent framework tests. @@ -134,7 +131,7 @@ public class IntentTestsMocks { /** * Mock path service for creating paths within the test. */ - public static class MockPathService implements PathService { + public static class MockPathService extends PathServiceAdapter { final String[] pathHops; final String[] reversePathHops; @@ -424,7 +421,7 @@ public class IntentTestsMocks { } final MockFlowRule other = (MockFlowRule) obj; return Objects.equals(this.timestamp, other.timestamp) && - this.id == other.id; + this.id == other.id; } @Override @@ -450,7 +447,7 @@ public class IntentTestsMocks { public MockIntent(Long number) { super(NetTestTools.APP_ID, null, Collections.emptyList(), - Intent.DEFAULT_INTENT_PRIORITY); + Intent.DEFAULT_INTENT_PRIORITY); this.number = number; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java index c4386593..2993ce6b 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java @@ -19,7 +19,6 @@ import org.onosproject.core.ApplicationId; import org.onosproject.net.flow.TrafficSelector; import java.util.List; -import java.util.Map; /** * Test adapter for packet service. @@ -34,7 +33,7 @@ public class PacketServiceAdapter implements PacketService { } @Override - public Map<Integer, PacketProcessor> getProcessors() { + public List<PacketProcessorEntry> getProcessors() { return null; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java index 8b0f8f05..f3958491 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java @@ -41,7 +41,7 @@ public class DefaultGraphDescriptionTest { @Test public void basics() { DefaultGraphDescription desc = - new DefaultGraphDescription(4321L, ImmutableSet.of(DEV1, DEV2, DEV3), + new DefaultGraphDescription(4321L, System.currentTimeMillis(), ImmutableSet.of(DEV1, DEV2, DEV3), ImmutableSet.of(L1, L2)); assertEquals("incorrect time", 4321L, desc.timestamp()); assertEquals("incorrect vertex count", 3, desc.vertexes().size()); @@ -50,7 +50,7 @@ public class DefaultGraphDescriptionTest { @Test public void missingVertex() { - GraphDescription desc = new DefaultGraphDescription(4321L, + GraphDescription desc = new DefaultGraphDescription(4321L, System.currentTimeMillis(), ImmutableSet.of(DEV1, DEV3), ImmutableSet.of(L1, L2)); assertEquals("incorrect time", 4321L, desc.timestamp()); diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java new file mode 100644 index 00000000..6a8e586f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java @@ -0,0 +1,62 @@ +/* + * 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.net.topology; + +import org.onosproject.net.DisjointPath; +import org.onosproject.net.ElementId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +import java.util.Map; +import java.util.Set; + +/** + * Test adapter for path service. + */ +public class PathServiceAdapter implements PathService { + @Override + public Set<Path> getPaths(ElementId src, ElementId dst) { + return null; + } + + @Override + public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) { + return null; + } + + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst) { + return null; + } + + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) { + return null; + } + + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, + Map<Link, Object> riskProfile) { + return null; + } + + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, + LinkWeight weight, + Map<Link, Object> riskProfile) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java index 07e67842..72cc67d7 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java @@ -17,9 +17,11 @@ package org.onosproject.net.topology; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; +import java.util.Map; import java.util.Set; /** @@ -89,4 +91,28 @@ public class TopologyServiceAdapter implements TopologyService { public void removeListener(TopologyListener listener) { } + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + return null; + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight) { + return null; + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map<Link, Object> riskProfile) { + return null; + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight, + Map<Link, Object> riskProfile) { + return null; + } + } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java index 01209be2..8c577df9 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java @@ -48,6 +48,16 @@ public final class TestAtomicCounter implements AtomicCounter { } @Override + public void set(long value) { + this.value.set(value); + } + + @Override + public boolean compareAndSet(long expectedValue, long updateValue) { + return value.compareAndSet(expectedValue, updateValue); + } + + @Override public long get() { return value.get(); } diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java index eb53152e..3433b3b7 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java @@ -16,6 +16,7 @@ package org.onosproject.codec.impl; import com.google.common.collect.ImmutableSet; + import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -36,6 +37,7 @@ import org.onosproject.net.Port; import org.onosproject.net.driver.Driver; import org.onosproject.net.flow.FlowEntry; import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criterion; @@ -99,6 +101,7 @@ public class CodecManager implements CodecService { registerCodec(Driver.class, new DriverCodec()); registerCodec(GroupBucket.class, new GroupBucketCodec()); registerCodec(Load.class, new LoadCodec()); + registerCodec(TableStatisticsEntry.class, new TableStatisticsEntryCodec()); log.info("Started"); } diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java index d61cf38b..d12e4ad8 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java @@ -215,6 +215,7 @@ public final class EncodeInstructionCodecHelper { break; case DROP: + case NOACTION: break; case L0MODIFICATION: diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java new file mode 100644 index 00000000..7834ceb1 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java @@ -0,0 +1,46 @@ +/* + * 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.codec.impl; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.flow.TableStatisticsEntry; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Table statistics entry JSON codec. + */ +public final class TableStatisticsEntryCodec extends JsonCodec<TableStatisticsEntry> { + + @Override + public ObjectNode encode(TableStatisticsEntry entry, CodecContext context) { + checkNotNull(entry, "Table Statistics entry cannot be null"); + + final ObjectNode result = context.mapper().createObjectNode() + .put("tableId", entry.tableId()) + .put("deviceId", entry.deviceId().toString()) + .put("activeEntries", entry.activeFlowEntries()) + .put("packetsLookedUp", entry.packetsLookedup()) + .put("packetsMatched", entry.packetsMatched()); + + return result; + } + +} + diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java index bdf7d732..3c5c540d 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java @@ -23,14 +23,19 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSetMultimap.Builder; import org.onlab.graph.DijkstraGraphSearch; +import org.onlab.graph.DisjointPathPair; import org.onlab.graph.GraphPathSearch; import org.onlab.graph.GraphPathSearch.Result; +import org.onlab.graph.SRLGGraphSearch; +import org.onlab.graph.SuurballeGraphSearch; import org.onlab.graph.TarjanGraphSearch; import org.onlab.graph.TarjanGraphSearch.SCCResult; import org.onosproject.net.AbstractModel; import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultDisjointPath; import org.onosproject.net.DefaultPath; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; import org.onosproject.net.provider.ProviderId; @@ -45,10 +50,11 @@ import org.onosproject.net.topology.TopologyEdge; import org.onosproject.net.topology.TopologyGraph; import org.onosproject.net.topology.TopologyVertex; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Preconditions.checkArgument; @@ -67,6 +73,9 @@ public class DefaultTopology extends AbstractModel implements Topology { private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>(); private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>(); + private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE = + new SuurballeGraphSearch<>(); + private final long time; private final long creationTime; @@ -315,15 +324,135 @@ public class DefaultTopology extends AbstractModel implements Topology { return builder.build(); } + /** + * /** + * Returns the set of pre-computed shortest disjoint path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @return set of shortest disjoint path pairs + */ + public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) { + return getDisjointPaths(src, dst, (LinkWeight) null); + } + + /** + * Computes on-demand the set of shortest disjoint path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param weight link weight function + * @return set of disjoint shortest path pairs + */ + public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) { + final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); + final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); + Set<TopologyVertex> vertices = graph.getVertexes(); + if (!vertices.contains(srcV) || !vertices.contains(dstV)) { + // src or dst not part of the current graph + return ImmutableSet.of(); + } + + GraphPathSearch.Result<TopologyVertex, TopologyEdge> result = + SUURBALLE.search(graph, srcV, dstV, weight, ALL_PATHS); + ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder(); + for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) { + builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path)); + } + return builder.build(); + } + + /** + * Computes on-demand the set of shortest disjoint risk groups path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge weight object + * @param riskProfile map representing risk groups for each edge + * @return set of shortest disjoint paths + */ + private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight, + Map<TopologyEdge, Object> riskProfile) { + DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); + DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); + + Set<TopologyVertex> vertices = graph.getVertexes(); + if (!vertices.contains(srcV) || !vertices.contains(dstV)) { + // src or dst not part of the current graph + return ImmutableSet.of(); + } + + SRLGGraphSearch<TopologyVertex, TopologyEdge> srlg = new SRLGGraphSearch<>(riskProfile); + GraphPathSearch.Result<TopologyVertex, TopologyEdge> result = + srlg.search(graph, srcV, dstV, weight, ALL_PATHS); + ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder(); + for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) { + builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path)); + } + return builder.build(); + } + + /** + * Computes on-demand the set of shortest disjoint risk groups path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge weight object + * @param riskProfile map representing risk groups for each link + * @return set of shortest disjoint paths + */ + public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight, + Map<Link, Object> riskProfile) { + Map<TopologyEdge, Object> riskProfile2 = new HashMap<>(); + for (Link l : riskProfile.keySet()) { + riskProfile2.put(new TopologyEdge() { + Link cur = l; + + public Link link() { + return cur; + } + + public TopologyVertex src() { + return () -> src; + } + + public TopologyVertex dst() { + return () -> dst; + } + }, riskProfile.get(l)); + } + return disjointPaths(src, dst, weight, riskProfile2); + } + + /** + * Computes on-demand the set of shortest disjoint risk groups path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param riskProfile map representing risk groups for each link + * @return set of shortest disjoint paths + */ + public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) { + return getDisjointPaths(src, dst, null, riskProfile); + } + // Converts graph path to a network path with the same cost. private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) { - List<Link> links = new ArrayList<>(); - for (TopologyEdge edge : path.edges()) { - links.add(edge.link()); - } + List<Link> links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList()); return new DefaultPath(CORE_PROVIDER_ID, links, path.cost()); } + private DisjointPath networkDisjointPath(DisjointPathPair<TopologyVertex, TopologyEdge> path) { + return new DefaultDisjointPath(CORE_PROVIDER_ID, + (DefaultPath) networkPath(path.primary()), + (DefaultPath) networkPath(path.secondary())); + } + // Searches for SCC clusters in the network topology graph using Tarjan // algorithm. private SCCResult<TopologyVertex, TopologyEdge> searchForClusters() { @@ -334,6 +463,7 @@ public class DefaultTopology extends AbstractModel implements Topology { private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() { ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder(); SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get(); + // Extract both vertexes and edges from the results; the lists form // pairs along the same index. List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes(); diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java index 6bf46803..54e1146b 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java @@ -38,10 +38,8 @@ import org.onosproject.net.flow.criteria.Criterion; import com.fasterxml.jackson.databind.node.ObjectNode; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.onlab.junit.TestUtils.getField; -import static org.onlab.junit.TestUtils.setField; import static org.onosproject.codec.impl.CriterionJsonMatcher.matchesCriterion; /** @@ -429,17 +427,4 @@ public class CriterionCodecTest { ObjectNode result = criterionCodec.encode(criterion, context); assertThat(result, matchesCriterion(criterion)); } - - /** - * Tests that an unimplemented criterion type only returns the type and - * no other data. - */ - @Test - public void matchUnknownTypeTest() throws Exception { - Criterion criterion = Criteria.matchOpticalSignalType((byte) 250); - setField(criterion, "type", Criterion.Type.UNASSIGNED_40); - ObjectNode result = criterionCodec.encode(criterion, context); - assertThat(result.get("type").textValue(), is(criterion.type().toString())); - assertThat(result.size(), is(1)); - } } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java index 72081e6c..c3cdca0f 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java @@ -416,6 +416,8 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json description); } else if (instruction instanceof ModMplsLabelInstruction) { return matchModMplsLabelInstruction(jsonInstruction, description); + } else if (instruction instanceof NoActionInstruction) { + return true; } return false; diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java index 4d435cfe..ef0f3324 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java @@ -73,7 +73,7 @@ public class DefaultTopologyTest { link("1", 3, "4", 3), link("4", 3, "1", 3), link("3", 4, "4", 4), link("4", 4, "3", 4)); GraphDescription graphDescription = - new DefaultGraphDescription(now, devices, links); + new DefaultGraphDescription(now, System.currentTimeMillis(), devices, links); dt = new DefaultTopology(PID, graphDescription); assertEquals("incorrect supplier", PID, dt.providerId()); diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java index c8c92aa5..bed32a2d 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java @@ -20,8 +20,10 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.google.common.util.concurrent.SettableFuture; + import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -44,6 +46,7 @@ import org.onosproject.net.flow.FlowRuleEvent.Type; import org.onosproject.net.flow.FlowRuleStore; import org.onosproject.net.flow.FlowRuleStoreDelegate; import org.onosproject.net.flow.StoredFlowEntry; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.store.AbstractStore; import org.slf4j.Logger; @@ -79,6 +82,9 @@ public class SimpleFlowRuleStore private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, List<StoredFlowEntry>>> flowEntries = new ConcurrentHashMap<>(); + private final ConcurrentMap<DeviceId, List<TableStatisticsEntry>> + deviceTableStats = new ConcurrentHashMap<>(); + private final AtomicInteger localBatchIdGen = new AtomicInteger(); // TODO: make this configurable @@ -97,6 +103,7 @@ public class SimpleFlowRuleStore @Deactivate public void deactivate() { + deviceTableStats.clear(); flowEntries.clear(); log.info("Stopped"); } @@ -315,4 +322,20 @@ public class SimpleFlowRuleStore } } } + + @Override + public FlowRuleEvent updateTableStatistics(DeviceId deviceId, + List<TableStatisticsEntry> tableStats) { + deviceTableStats.put(deviceId, tableStats); + return null; + } + + @Override + public Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId) { + List<TableStatisticsEntry> tableStats = deviceTableStats.get(deviceId); + if (tableStats == null) { + return Collections.emptyList(); + } + return ImmutableList.copyOf(tableStats); + } } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java index 264d0493..72ec98ca 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java @@ -160,6 +160,11 @@ public class SimpleHostStore } @Override + public HostEvent removeIp(HostId hostId, IpAddress ipAddress) { + return null; + } + + @Override public int getHostCount() { return hosts.size(); } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java index f8359262..7dda12c8 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java @@ -15,10 +15,13 @@ */ package org.onosproject.store.trivial; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketEvent; import org.onosproject.net.packet.PacketEvent.Type; @@ -27,7 +30,9 @@ import org.onosproject.net.packet.PacketStore; import org.onosproject.net.packet.PacketStoreDelegate; import org.onosproject.store.AbstractStore; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -39,7 +44,7 @@ public class SimplePacketStore extends AbstractStore<PacketEvent, PacketStoreDelegate> implements PacketStore { - private Set<PacketRequest> requests = Sets.newConcurrentHashSet(); + private Map<TrafficSelector, Set<PacketRequest>> requests = Maps.newConcurrentMap(); @Override public void emit(OutboundPacket packet) { @@ -47,18 +52,50 @@ public class SimplePacketStore } @Override - public boolean requestPackets(PacketRequest request) { - return requests.add(request); + public void requestPackets(PacketRequest request) { + requests.compute(request.selector(), (s, existingRequests) -> { + if (existingRequests == null) { + return ImmutableSet.of(request); + } else if (!existingRequests.contains(request)) { + if (delegate != null) { + delegate.requestPackets(request); + } + return ImmutableSet.<PacketRequest>builder() + .addAll(existingRequests) + .add(request) + .build(); + } else { + return existingRequests; + } + }); } @Override - public boolean cancelPackets(PacketRequest request) { - return requests.remove(request); + public void cancelPackets(PacketRequest request) { + requests.computeIfPresent(request.selector(), (s, existingRequests) -> { + if (existingRequests.contains(request)) { + HashSet<PacketRequest> newRequests = Sets.newHashSet(existingRequests); + newRequests.remove(request); + if (newRequests.size() > 0) { + return ImmutableSet.copyOf(newRequests); + } else { + if (delegate != null) { + delegate.cancelPackets(request); + } + return null; + } + } else { + return existingRequests; + } + }); } @Override public List<PacketRequest> existingRequests() { - return ImmutableList.copyOf(requests); + List<PacketRequest> list = Lists.newArrayList(); + requests.values().forEach(list::addAll); + list.sort((o1, o2) -> o1.priority().priorityValue() - o2.priority().priorityValue()); + return list; } } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java index 6a89c019..29c5d844 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java @@ -23,6 +23,7 @@ import org.onosproject.common.DefaultTopology; import org.onosproject.event.Event; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; import org.onosproject.net.provider.ProviderId; @@ -39,6 +40,7 @@ import org.onosproject.store.AbstractStore; import org.slf4j.Logger; import java.util.List; +import java.util.Map; import java.util.Set; import static org.slf4j.LoggerFactory.getLogger; @@ -114,6 +116,29 @@ public class SimpleTopologyStore } @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + return defaultTopology(topology).getDisjointPaths(src, dst); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map<Link, Object> riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, riskProfile); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map<Link, Object> riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight, riskProfile); + } + + @Override public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { return defaultTopology(topology).isInfrastructure(connectPoint); } diff --git a/framework/src/onos/core/net/pom.xml b/framework/src/onos/core/net/pom.xml index 9ea00070..c5d31263 100644 --- a/framework/src/onos/core/net/pom.xml +++ b/framework/src/onos/core/net/pom.xml @@ -52,6 +52,20 @@ <dependency> <groupId>org.onosproject</groupId> + <version>${project.version}</version> + <artifactId>onos-cli</artifactId> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-cli</artifactId> + <version>${project.version}</version> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> <artifactId>onos-core-common</artifactId> <version>${project.version}</version> <classifier>tests</classifier> diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java new file mode 100644 index 00000000..6678db27 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java @@ -0,0 +1,74 @@ +/* + * 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.cfg.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.cfg.ComponentConfigService; +import org.slf4j.Logger; + +import java.io.File; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Component responsible for automatically loading configuration file from + * configuration directory. + */ +@Component(immediate = true) +public class ComponentConfigLoader { + + private static final String CFG_JSON = "../config/component-cfg.json"; + static File cfgFile = new File(CFG_JSON); + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService configService; + + private ObjectNode root; + + @Activate + protected void activate() { + this.loadConfigs(); + log.info("Started"); + } + + // Loads the configurations for each component from the file in + // ../config/component-cfg.json, using the preSetProperty method. + private void loadConfigs() { + try { + if (cfgFile.exists()) { + root = (ObjectNode) new ObjectMapper().readTree(cfgFile); + root.fieldNames(). + forEachRemaining(component -> root.path(component).fieldNames() + .forEachRemaining(k -> configService + .preSetProperty(component, k, + root.path(component).path(k) + .asText()))); + log.info("Loaded initial component configuration from {}", cfgFile); + } + } catch (Exception e) { + log.warn("Unable to load initial component configuration from {}", + cfgFile, e); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java index 1933ee55..b3b22c76 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java @@ -61,6 +61,9 @@ public class ComponentConfigManager implements ComponentConfigService { private static final String COMPONENT_NULL = "Component name cannot be null"; private static final String PROPERTY_NULL = "Property name cannot be null"; + private static final String COMPONENT_MISSING = "Component %s is not registered"; + private static final String PROPERTY_MISSING = "Property %s does not exist for %s"; + //Symbolic constants for use with the accumulator private static final int MAX_ITEMS = 100; @@ -160,6 +163,22 @@ public class ComponentConfigManager implements ComponentConfigService { checkNotNull(componentName, COMPONENT_NULL); checkNotNull(name, PROPERTY_NULL); + + checkArgument(properties.containsKey(componentName), + COMPONENT_MISSING, componentName); + checkArgument(properties.get(componentName).containsKey(name), + PROPERTY_MISSING, name, componentName); + store.setProperty(componentName, name, value); + } + + @Override + public void preSetProperty(String componentName, String name, String value) { + + checkPermission(CONFIG_WRITE); + + checkNotNull(componentName, COMPONENT_NULL); + checkNotNull(name, PROPERTY_NULL); + store.setProperty(componentName, name, value); } @@ -169,6 +188,11 @@ public class ComponentConfigManager implements ComponentConfigService { checkNotNull(componentName, COMPONENT_NULL); checkNotNull(name, PROPERTY_NULL); + + checkArgument(properties.containsKey(componentName), + COMPONENT_MISSING, componentName); + checkArgument(properties.get(componentName).containsKey(name), + PROPERTY_MISSING, name, componentName); store.unsetProperty(componentName, name); } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java index 8a441f61..f4d560a4 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java @@ -24,7 +24,6 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.util.SharedExecutors; -import org.onlab.util.Tools; import org.onosproject.cfg.ComponentConfigService; import org.onosproject.core.ApplicationId; import org.onosproject.core.ApplicationIdStore; @@ -38,6 +37,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Dictionary; import java.util.List; import java.util.Set; @@ -87,9 +90,15 @@ public class CoreManager implements CoreService { public void activate() { registerApplication(CORE_APP_NAME); cfgService.registerProperties(getClass()); - List<String> versionLines = Tools.slurp(VERSION_FILE); - if (versionLines != null && !versionLines.isEmpty()) { - version = Version.version(versionLines.get(0)); + try { + Path path = Paths.get(VERSION_FILE.getPath()); + List<String> versionLines = Files.readAllLines(path); + if (versionLines != null && !versionLines.isEmpty()) { + version = Version.version(versionLines.get(0)); + } + } catch (IOException e) { + // version file not found, using default + log.trace("Version file not found", e); } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java index 5cd96cab..db484eea 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java @@ -96,7 +96,7 @@ public class NetworkConfigManager configClasses.put(identifier(configFactory), configFactory.configClass()); SubjectFactory subjectFactory = configFactory.subjectFactory(); - subjectClasses.putIfAbsent(subjectFactory.subjectKey(), subjectFactory); + subjectClasses.putIfAbsent(subjectFactory.subjectClassKey(), subjectFactory); subjectClassKeys.putIfAbsent(subjectFactory.subjectClass(), subjectFactory); store.addConfigFactory(configFactory); @@ -145,8 +145,8 @@ public class NetworkConfigManager } @Override - public SubjectFactory getSubjectFactory(String subjectKey) { - return subjectClasses.get(subjectKey); + public SubjectFactory getSubjectFactory(String subjectClassKey) { + return subjectClasses.get(subjectClassKey); } @Override @@ -155,8 +155,8 @@ public class NetworkConfigManager } @Override - public Class<? extends Config> getConfigClass(String subjectKey, String configKey) { - return configClasses.get(new ConfigIdentifier(subjectKey, configKey)); + public Class<? extends Config> getConfigClass(String subjectClassKey, String configKey) { + return configClasses.get(new ConfigIdentifier(subjectClassKey, configKey)); } @Override @@ -255,7 +255,7 @@ public class NetworkConfigManager } private static ConfigIdentifier identifier(ConfigFactory factory) { - return new ConfigIdentifier(factory.subjectFactory().subjectKey(), factory.configKey()); + return new ConfigIdentifier(factory.subjectFactory().subjectClassKey(), factory.configKey()); } static final class ConfigIdentifier { diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java index 7900d185..fa90eb65 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java @@ -15,21 +15,21 @@ */ package org.onosproject.net.device.impl; -import static org.slf4j.LoggerFactory.getLogger; -import static com.google.common.base.Preconditions.checkNotNull; - -import org.onosproject.net.config.ConfigOperator; -import org.onosproject.net.config.basics.BasicDeviceConfig; import org.onosproject.net.AnnotationKeys; import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.Device; import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.config.ConfigOperator; +import org.onosproject.net.config.basics.BasicDeviceConfig; import org.onosproject.net.device.DefaultDeviceDescription; import org.onosproject.net.device.DeviceDescription; import org.slf4j.Logger; import java.util.Objects; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + /** * Implementations of merge policies for various sources of device configuration * information. This includes applications, provides, and network configurations. @@ -46,7 +46,7 @@ public final class BasicDeviceOperator implements ConfigOperator { * Generates a DeviceDescription containing fields from a DeviceDescription and * a DeviceConfig. * - * @param bdc the device config entity from network config + * @param bdc the device config entity from network config * @param descr a DeviceDescription * @return DeviceDescription based on both sources */ @@ -70,7 +70,7 @@ public final class BasicDeviceOperator implements ConfigOperator { * Generates an annotation from an existing annotation and DeviceConfig. * * @param bdc the device config entity from network config - * @param an the annotation + * @param an the annotation * @return annotation combining both sources */ public static SparseAnnotations combine(BasicDeviceConfig bdc, SparseAnnotations an) { @@ -93,6 +93,9 @@ public final class BasicDeviceOperator implements ConfigOperator { if (bdc.owner() != null) { newBuilder.set(AnnotationKeys.OWNER, bdc.owner()); } + if (bdc.managementAddress() != null) { + newBuilder.set(AnnotationKeys.MANAGEMENT_ADDRESS, bdc.managementAddress()); + } DefaultAnnotations newAnnotations = newBuilder.build(); return DefaultAnnotations.union(an, newAnnotations); } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java index b0b3abe2..e35dc0c5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java @@ -15,8 +15,26 @@ */ package org.onosproject.net.device.impl; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Futures; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.net.MastershipRole.MASTER; +import static org.onosproject.net.MastershipRole.NONE; +import static org.onosproject.net.MastershipRole.STANDBY; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.DEVICE_READ; +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; @@ -26,12 +44,6 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onosproject.cluster.ClusterService; import org.onosproject.cluster.NodeId; -import org.onosproject.net.provider.AbstractListenerProviderRegistry; -import org.onosproject.net.config.NetworkConfigEvent; -import org.onosproject.net.config.NetworkConfigListener; -import org.onosproject.net.config.NetworkConfigService; -import org.onosproject.net.config.basics.BasicDeviceConfig; -import org.onosproject.net.config.basics.OpticalPortConfig; import org.onosproject.mastership.MastershipEvent; import org.onosproject.mastership.MastershipListener; import org.onosproject.mastership.MastershipService; @@ -44,6 +56,11 @@ import org.onosproject.net.DeviceId; import org.onosproject.net.MastershipRole; import org.onosproject.net.Port; import org.onosproject.net.PortNumber; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; +import org.onosproject.net.config.NetworkConfigService; +import org.onosproject.net.config.basics.BasicDeviceConfig; +import org.onosproject.net.config.basics.OpticalPortConfig; import org.onosproject.net.device.DefaultDeviceDescription; import org.onosproject.net.device.DefaultPortDescription; import org.onosproject.net.device.DeviceAdminService; @@ -58,27 +75,11 @@ import org.onosproject.net.device.DeviceStore; import org.onosproject.net.device.DeviceStoreDelegate; import org.onosproject.net.device.PortDescription; import org.onosproject.net.device.PortStatistics; +import org.onosproject.net.provider.AbstractListenerProviderRegistry; import org.onosproject.net.provider.AbstractProviderService; import org.slf4j.Logger; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; -import static org.onlab.util.Tools.groupedThreads; -import static org.onosproject.net.MastershipRole.*; -import static org.onosproject.security.AppGuard.checkPermission; -import static org.slf4j.LoggerFactory.getLogger; -import static org.onosproject.security.AppPermission.Type.*; +import com.google.common.util.concurrent.Futures; /** * Provides implementation of the device SB & NB APIs. @@ -347,11 +348,15 @@ public class DeviceManager log.info("Device {} disconnected from this node", deviceId); List<Port> ports = store.getPorts(deviceId); - List<PortDescription> descs = Lists.newArrayList(); - ports.forEach(port -> - descs.add(new DefaultPortDescription(port.number(), - false, port.type(), - port.portSpeed()))); + final Device device = getDevice(deviceId); + + List<PortDescription> descs = ports.stream().map( + port -> (!(Device.Type.ROADM.equals(device.type()))) ? + new DefaultPortDescription(port.number(), false, + port.type(), port.portSpeed()) : + OpticalPortOperator.descriptionOf(port, false) + ).collect(Collectors.toList()); + store.updatePorts(this.provider().id(), deviceId, descs); try { if (mastershipService.isLocalMaster(deviceId)) { @@ -430,6 +435,12 @@ public class DeviceManager portDescription); return; } + final Device device = getDevice(deviceId); + if ((Device.Type.ROADM.equals(device.type()))) { + Port port = getPort(deviceId, portDescription.portNumber()); + portDescription = OpticalPortOperator.descriptionOf(port, portDescription.isEnabled()); + } + portDescription = consolidate(deviceId, portDescription); final DeviceEvent event = store.updatePortStatus(this.provider().id(), deviceId, portDescription); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java index b2fd02c7..8f2bda01 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java @@ -151,8 +151,25 @@ public final class OpticalPortOperator implements ConfigOperator { */ public static PortDescription descriptionOf(Port port) { checkNotNull(port, "Must supply non-null Port"); + final boolean isUp = port.isEnabled(); + return descriptionOfPort(port, isUp); + } + + /** + * Returns a description built from an existing port and reported status. + * + * @param port + * @param isEnabled + * @return a PortDescription based on the port + */ + static PortDescription descriptionOf(Port port, boolean isEnabled) { + checkNotNull(port, "Must supply non-null Port"); + final boolean isup = isEnabled; + return descriptionOfPort(port, isup); + } + + private static PortDescription descriptionOfPort(Port port, final boolean isup) { final PortNumber ptn = port.number(); - final boolean isup = port.isEnabled(); final SparseAnnotations an = (SparseAnnotations) port.annotations(); switch (port.type()) { case OMS: diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java index a1d046c5..5958d1f5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java @@ -22,6 +22,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; + import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -58,6 +59,7 @@ import org.onosproject.net.flow.FlowRuleProviderService; import org.onosproject.net.flow.FlowRuleService; import org.onosproject.net.flow.FlowRuleStore; import org.onosproject.net.flow.FlowRuleStoreDelegate; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.net.provider.AbstractProviderService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; @@ -388,6 +390,16 @@ public class FlowRuleManager @Override public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries) { + pushFlowMetricsInternal(deviceId, flowEntries, true); + } + + @Override + public void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries) { + pushFlowMetricsInternal(deviceId, flowEntries, false); + } + + private void pushFlowMetricsInternal(DeviceId deviceId, Iterable<FlowEntry> flowEntries, + boolean useMissingFlow) { Map<FlowEntry, FlowEntry> storedRules = Maps.newHashMap(); store.getFlowEntries(deviceId).forEach(f -> storedRules.put(f, f)); @@ -415,17 +427,20 @@ public class FlowRuleManager continue; } } - for (FlowEntry rule : storedRules.keySet()) { - try { - // there are rules in the store that aren't on the switch - log.debug("Adding rule in store, but not on switch {}", rule); - flowMissing(rule); - } catch (Exception e) { - log.debug("Can't add missing flow rule {}", e.getMessage()); - continue; + + // DO NOT reinstall + if (useMissingFlow) { + for (FlowEntry rule : storedRules.keySet()) { + try { + // there are rules in the store that aren't on the switch + log.debug("Adding rule in store, but not on switch {}", rule); + flowMissing(rule); + } catch (Exception e) { + log.debug("Can't add missing flow rule {}", e.getMessage()); + continue; + } } } - } @Override @@ -435,6 +450,12 @@ public class FlowRuleManager operation )); } + + @Override + public void pushTableStatistics(DeviceId deviceId, + List<TableStatisticsEntry> tableStats) { + store.updateTableStatistics(deviceId, tableStats); + } } // Store delegate to re-post events emitted from the store. @@ -590,4 +611,10 @@ public class FlowRuleManager } } + + @Override + public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) { + checkPermission(FLOWRULE_READ); + return store.getTableStatistics(deviceId); + } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java index 43f346b7..1473f33f 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java @@ -236,6 +236,16 @@ public class HostManager post(event); } } + + @Override + public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { + checkNotNull(hostId, HOST_ID_NULL); + checkValidity(); + HostEvent event = store.removeIp(hostId, ipAddress); + if (event != null) { + post(event); + } + } } // Store delegate to re-post events emitted from the store. diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java index 44f8cbf0..4dc93a51 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java @@ -84,6 +84,7 @@ public class HostMonitor implements TimerTask { * @param hostManager host manager used to look up host information and * probe existing hosts * @param interfaceService interface service for interface information + * @param edgePortService edge port service */ public HostMonitor(PacketService packetService, HostManager hostManager, InterfaceService interfaceService, diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java index d7fa3223..417627ad 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java @@ -196,7 +196,7 @@ public class IntentCleanup implements Runnable, IntentListener { service.withdraw(intentData.intent()); break; default: - log.warn("Trying to resubmit pending intent {} in state {} with request {}", + log.warn("Failed to resubmit pending intent {} in state {} with request {}", intentData.key(), intentData.state(), intentData.request()); break; } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java index 4c828e77..baa3bf4d 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java @@ -256,15 +256,16 @@ public class IntentManager submit(intent); } - // If required, compile all currently failed intents. - for (Intent intent : getIntents()) { - IntentState state = getIntentState(intent.key()); - if ((compileAllFailed && RECOMPILE.contains(state)) - || intentAllowsPartialFailure(intent)) { - if (WITHDRAW.contains(state)) { - withdraw(intent); - } else { - submit(intent); + if (compileAllFailed) { + // If required, compile all currently failed intents. + for (Intent intent : getIntents()) { + IntentState state = getIntentState(intent.key()); + if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) { + if (WITHDRAW.contains(state)) { + withdraw(intent); + } else { + submit(intent); + } } } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java index 5710aced..5ebc812e 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java @@ -16,8 +16,8 @@ package org.onosproject.net.intent.impl; import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.common.collect.SetMultimap; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; @@ -61,7 +61,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -91,8 +90,6 @@ public class ObjectiveTracker implements ObjectiveTrackerService { private final Logger log = getLogger(getClass()); - private final ConcurrentMap<Key, Intent> intents = Maps.newConcurrentMap(); - private final SetMultimap<LinkKey, Key> intentsByLink = //TODO this could be slow as a point of synchronization synchronizedSetMultimap(HashMultimap.<LinkKey, Key>create()); @@ -378,7 +375,12 @@ public class ObjectiveTracker implements ObjectiveTrackerService { } // TODO should we recompile on available==true? - delegate.triggerCompile(intentsByDevice.get(id), available); + + final ImmutableSet<Key> snapshot; + synchronized (intentsByDevice) { + snapshot = ImmutableSet.copyOf(intentsByDevice.get(id)); + } + delegate.triggerCompile(snapshot, available); } } @@ -415,9 +417,17 @@ public class ObjectiveTracker implements ObjectiveTrackerService { @Override public void event(HostEvent event) { HostId id = event.subject().id(); - HostEvent.Type type = event.type(); - boolean available = (type == HostEvent.Type.HOST_ADDED); - executorService.execute(new DeviceAvailabilityHandler(id, available)); + switch (event.type()) { + case HOST_ADDED: + case HOST_MOVED: + case HOST_REMOVED: + executorService.execute(new DeviceAvailabilityHandler(id, false)); + break; + case HOST_UPDATED: + default: + // DO NOTHING + break; + } } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java index 99f58df7..c6eb7c5a 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java @@ -15,10 +15,8 @@ */ package org.onosproject.net.intent.impl.compiler; -import com.google.common.collect.Sets; import org.apache.commons.lang3.tuple.Pair; 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.Modified; import org.apache.felix.scr.annotations.Property; @@ -50,7 +48,10 @@ import org.onosproject.net.intent.IntentService; import org.onosproject.net.intent.OpticalCircuitIntent; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.impl.IntentCompilationException; -import org.onosproject.net.resource.device.DeviceResourceService; +import org.onosproject.net.newresource.ResourceAllocation; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; +import org.onosproject.net.resource.device.IntentSetMultimap; import org.onosproject.net.resource.link.LinkResourceAllocations; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; @@ -60,6 +61,7 @@ import java.util.Collections; import java.util.Dictionary; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; @@ -67,7 +69,8 @@ import static com.google.common.base.Preconditions.checkArgument; /** * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}. */ -@Component(immediate = true) +// For now, remove component designation until dependency on the new resource manager is available. +// @Component(immediate = true) public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> { private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class); @@ -92,7 +95,10 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu protected DeviceService deviceService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected DeviceResourceService deviceResourceService; + protected ResourceService resourceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentSetMultimap intentSetMultimap; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected IntentService intentService; @@ -153,7 +159,10 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu log.debug("Compiling optical circuit intent between {} and {}", src, dst); // Reserve OduClt ports - if (!deviceResourceService.requestPorts(Sets.newHashSet(srcPort, dstPort), intent)) { + ResourcePath srcPortPath = new ResourcePath(src.deviceId(), src.port()); + ResourcePath dstPortPath = new ResourcePath(dst.deviceId(), dst.port()); + List<ResourceAllocation> allocation = resourceService.allocate(intent.id(), srcPortPath, dstPortPath); + if (allocation.isEmpty()) { throw new IntentCompilationException("Unable to reserve ports for intent " + intent); } @@ -199,7 +208,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu circuitIntent = new FlowRuleIntent(appId, rules, intent.resources()); // Save circuit to connectivity intent mapping - deviceResourceService.requestMapping(connIntent.id(), intent.id()); + intentSetMultimap.allocateMapping(connIntent.id(), intent.id()); intents.add(circuitIntent); return intents; @@ -209,16 +218,15 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu * Checks if current allocations on given resource can satisfy request. * If the resource is null, return true. * - * @param request the intent making the request * @param resource the resource on which to map the intent * @return true if the resource can accept the request, false otherwise */ - private boolean isAvailable(Intent request, IntentId resource) { + private boolean isAvailable(IntentId resource) { if (resource == null) { return true; } - Set<IntentId> mapping = deviceResourceService.getMapping(resource); + Set<IntentId> mapping = intentSetMultimap.getMapping(resource); if (mapping == null) { return true; @@ -271,7 +279,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu continue; } - if (isAvailable(circuitIntent, connIntent.id())) { + if (isAvailable(connIntent.id())) { return connIntent; } } @@ -296,14 +304,19 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu return null; } - private OchPort findAvailableOchPort(ConnectPoint oduPort, OpticalCircuitIntent circuitIntent) { + private OchPort findAvailableOchPort(ConnectPoint oduPort) { // First see if the port mappings are constrained ConnectPoint ochCP = staticPort(oduPort); if (ochCP != null) { OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port()); - IntentId intentId = deviceResourceService.getAllocations(ochPort); - if (isAvailable(circuitIntent, intentId)) { + Optional<IntentId> intentId = + resourceService.getResourceAllocation(new ResourcePath(ochCP.deviceId(), ochCP.port())) + .map(ResourceAllocation::consumer) + .filter(x -> x instanceof IntentId) + .map(x -> (IntentId) x); + + if (isAvailable(intentId.orElse(null))) { return ochPort; } } @@ -316,8 +329,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu continue; } - IntentId intentId = deviceResourceService.getAllocations(port); - if (isAvailable(circuitIntent, intentId)) { + Optional<IntentId> intentId = + resourceService.getResourceAllocation(new ResourcePath(oduPort.deviceId(), port.number())) + .map(ResourceAllocation::consumer) + .filter(x -> x instanceof IntentId) + .map(x -> (IntentId) x); + if (isAvailable(intentId.orElse(null))) { return (OchPort) port; } } @@ -327,12 +344,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) { - OchPort srcPort = findAvailableOchPort(intent.getSrc(), intent); + OchPort srcPort = findAvailableOchPort(intent.getSrc()); if (srcPort == null) { return null; } - OchPort dstPort = findAvailableOchPort(intent.getDst(), intent); + OchPort dstPort = findAvailableOchPort(intent.getDst()); if (dstPort == null) { return null; } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java index 05a20f96..eb5b4af8 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java @@ -16,9 +16,7 @@ package org.onosproject.net.intent.impl.compiler; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; 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; @@ -40,9 +38,9 @@ import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.OpticalPathIntent; import org.onosproject.net.intent.impl.IntentCompilationException; -import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; import org.onosproject.net.resource.ResourceType; -import org.onosproject.net.resource.device.DeviceResourceService; import org.onosproject.net.resource.link.DefaultLinkResourceRequest; import org.onosproject.net.resource.link.LambdaResource; import org.onosproject.net.resource.link.LambdaResourceAllocation; @@ -57,13 +55,15 @@ import org.slf4j.LoggerFactory; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; /** * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}. */ -@Component(immediate = true) +// For now, remove component designation until dependency on the new resource manager is available. +// @Component(immediate = true) public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> { protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class); @@ -78,10 +78,10 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical protected DeviceService deviceService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkResourceService linkResourceService; + protected ResourceService resourceService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected DeviceResourceService deviceResourceService; + protected LinkResourceService linkResourceService; @Activate public void activate() { @@ -108,7 +108,11 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical log.debug("Compiling optical connectivity intent between {} and {}", src, dst); // Reserve OCh ports - if (!deviceResourceService.requestPorts(ImmutableSet.of(srcPort, dstPort), intent)) { + ResourcePath srcPortPath = new ResourcePath(src.deviceId(), src.port()); + ResourcePath dstPortPath = new ResourcePath(dst.deviceId(), dst.port()); + List<org.onosproject.net.newresource.ResourceAllocation> allocation = + resourceService.allocate(intent.id(), srcPortPath, dstPortPath); + if (allocation.isEmpty()) { throw new IntentCompilationException("Unable to reserve ports for intent " + intent); } @@ -161,7 +165,7 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical } // Release port allocations if unsuccessful - deviceResourceService.releasePorts(intent.id()); + resourceService.release(intent.id()); throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent); } @@ -174,15 +178,12 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical * @return lambda allocated to the given path */ private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) { - for (Link link : path.links()) { - for (ResourceAllocation alloc : linkAllocs.getResourceAllocation(link)) { - if (alloc.type() == ResourceType.LAMBDA) { - return (LambdaResourceAllocation) alloc; - } - } - } - - return null; + return path.links().stream() + .flatMap(x -> linkAllocs.getResourceAllocation(x).stream()) + .filter(x -> x.type() == ResourceType.LAMBDA) + .findFirst() + .map(x -> (LambdaResourceAllocation) x) + .orElse(null); } /** @@ -215,23 +216,23 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical return false; } - LambdaResource lambda = null; + List<LambdaResource> lambdas = path.links().stream() + .flatMap(x -> allocations.getResourceAllocation(x).stream()) + .filter(x -> x.type() == ResourceType.LAMBDA) + .map(x -> ((LambdaResourceAllocation) x).lambda()) + .collect(Collectors.toList()); - for (Link link : path.links()) { - for (ResourceAllocation alloc : allocations.getResourceAllocation(link)) { - if (alloc.type() == ResourceType.LAMBDA) { - LambdaResource nextLambda = ((LambdaResourceAllocation) alloc).lambda(); - if (nextLambda == null) { - return false; - } - if (lambda == null) { - lambda = nextLambda; - continue; - } - if (!lambda.equals(nextLambda)) { - return false; - } - } + LambdaResource lambda = null; + for (LambdaResource nextLambda: lambdas) { + if (nextLambda == null) { + return false; + } + if (lambda == null) { + lambda = nextLambda; + continue; + } + if (!lambda.equals(nextLambda)) { + return false; } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java index ca9ae5cc..2cc45e79 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java @@ -39,7 +39,6 @@ import org.onosproject.net.intent.IntentCompiler; import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.OpticalPathIntent; import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +58,6 @@ public class OpticalPathIntentCompiler implements IntentCompiler<OpticalPathInte @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected CoreService coreService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkResourceService resourceService; - private ApplicationId appId; @Activate diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java index 2cd1a2e0..5226967f 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java @@ -91,6 +91,14 @@ public final class ResourceManager implements ResourceService, ResourceAdminServ } @Override + public Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource) { + checkNotNull(resource); + + Optional<ResourceConsumer> consumer = store.getConsumer(resource); + return consumer.map(x -> new ResourceAllocation(resource, x)); + } + + @Override public <T> Collection<ResourceAllocation> getResourceAllocations(ResourcePath parent, Class<T> cls) { checkNotNull(parent); checkNotNull(cls); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java index a0bc693c..8e87a07d 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java @@ -15,7 +15,8 @@ */ package org.onosproject.net.packet.impl; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -43,6 +44,7 @@ import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketEvent; import org.onosproject.net.packet.PacketPriority; import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketProcessorEntry; import org.onosproject.net.packet.PacketProvider; import org.onosproject.net.packet.PacketProviderRegistry; import org.onosproject.net.packet.PacketProviderService; @@ -55,8 +57,6 @@ import org.onosproject.net.provider.AbstractProviderService; import org.slf4j.Logger; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -102,18 +102,18 @@ public class PacketManager private final DeviceListener deviceListener = new InternalDeviceListener(); - private final Map<Integer, PacketProcessor> processors = new ConcurrentHashMap<>(); + private final List<ProcessorEntry> processors = Lists.newCopyOnWriteArrayList(); private ApplicationId appId; @Activate public void activate() { eventHandlingExecutor = Executors.newSingleThreadExecutor( - groupedThreads("onos/net/packet", "event-handler")); + groupedThreads("onos/net/packet", "event-handler")); appId = coreService.getAppId(CoreService.CORE_APP_NAME); store.setDelegate(delegate); deviceService.addListener(deviceListener); - // TODO: Should we request packets for all existing devices? I believe we should. + store.existingRequests().forEach(this::pushToAllDevices); log.info("Started"); } @@ -129,19 +129,35 @@ public class PacketManager public void addProcessor(PacketProcessor processor, int priority) { checkPermission(PACKET_EVENT); checkNotNull(processor, "Processor cannot be null"); - processors.put(priority, processor); + ProcessorEntry entry = new ProcessorEntry(processor, priority); + + // Insert the new processor according to its priority. + int i = 0; + for (; i < processors.size(); i++) { + if (priority < processors.get(i).priority()) { + break; + } + } + processors.add(i, entry); } @Override public void removeProcessor(PacketProcessor processor) { checkPermission(PACKET_EVENT); checkNotNull(processor, "Processor cannot be null"); - processors.values().remove(processor); + + // Remove the processor entry. + for (int i = 0; i < processors.size(); i++) { + if (processors.get(i).processor() == processor) { + processors.remove(i); + break; + } + } } @Override - public Map<Integer, PacketProcessor> getProcessors() { - return ImmutableMap.copyOf(processors); + public List<PacketProcessorEntry> getProcessors() { + return ImmutableList.copyOf(processors); } @Override @@ -152,9 +168,7 @@ public class PacketManager checkNotNull(appId, "Application ID cannot be null"); PacketRequest request = new DefaultPacketRequest(selector, priority, appId); - if (store.requestPackets(request)) { - pushToAllDevices(request); - } + store.requestPackets(request); } @Override @@ -165,9 +179,7 @@ public class PacketManager checkNotNull(appId, "Application ID cannot be null"); PacketRequest request = new DefaultPacketRequest(selector, priority, appId); - if (store.cancelPackets(request)) { - removeFromAllDevices(request); - } + store.cancelPackets(request); } @Override @@ -176,6 +188,18 @@ public class PacketManager } /** + * Pushes all rules to the specified device. + * + * @param device device on which to install packet request flows + */ + private void pushRulesToDevice(Device device) { + log.debug("Pushing packet requests to device {}", device.id()); + for (PacketRequest request : store.existingRequests()) { + pushRule(device, request); + } + } + + /** * Pushes a packet request flow rule to all devices. * * @param request the packet request @@ -187,16 +211,13 @@ public class PacketManager } } - /** * Removes packet request flow rule from all devices. * * @param request the packet request */ private void removeFromAllDevices(PacketRequest request) { - for (Device device : deviceService.getDevices()) { - removeRule(device, request); - } + deviceService.getAvailableDevices().forEach(d -> removeRule(d, request)); } /** @@ -232,7 +253,6 @@ public class PacketManager if (!device.type().equals(Device.Type.SWITCH)) { return; } - ForwardingObjective forwarding = createBuilder(request) .remove(new ObjectiveContext() { @Override @@ -241,7 +261,6 @@ public class PacketManager request, device.id(), error); } }); - objectiveService.forward(device.id(), forwarding); } @@ -263,12 +282,10 @@ public class PacketManager } private void localEmit(OutboundPacket packet) { - final Device device = deviceService.getDevice(packet.sendThrough()); - + Device device = deviceService.getDevice(packet.sendThrough()); if (device == null) { return; } - PacketProvider packetProvider = getProvider(device.providerId()); if (packetProvider != null) { packetProvider.emit(packet); @@ -280,7 +297,9 @@ public class PacketManager return new InternalPacketProviderService(provider); } - // Personalized packet provider service issued to the supplied provider. + /** + * Personalized packet provider service issued to the supplied provider. + */ private class InternalPacketProviderService extends AbstractProviderService<PacketProvider> implements PacketProviderService { @@ -292,8 +311,10 @@ public class PacketManager @Override public void processPacket(PacketContext context) { // TODO filter packets sent to processors based on registrations - for (PacketProcessor processor : processors.values()) { - processor.process(context); + for (ProcessorEntry entry : processors) { + long start = System.nanoTime(); + entry.processor().process(context); + entry.addNanos(System.nanoTime() - start); } } @@ -307,6 +328,16 @@ public class PacketManager public void notify(PacketEvent event) { localEmit(event.subject()); } + + @Override + public void requestPackets(PacketRequest request) { + pushToAllDevices(request); + } + + @Override + public void cancelPackets(PacketRequest request) { + removeFromAllDevices(request); + } } /** @@ -319,17 +350,14 @@ public class PacketManager try { Device device = event.subject(); switch (event.type()) { - case DEVICE_ADDED: - case DEVICE_AVAILABILITY_CHANGED: - if (deviceService.isAvailable(event.subject().id())) { - log.debug("Pushing packet requests to device {}", event.subject().id()); - for (PacketRequest request : store.existingRequests()) { - pushRule(device, request); + case DEVICE_ADDED: + case DEVICE_AVAILABILITY_CHANGED: + if (deviceService.isAvailable(event.subject().id())) { + pushRulesToDevice(device); } - } - break; - default: - break; + break; + default: + break; } } catch (Exception e) { log.warn("Failed to process {}", event, e); @@ -338,4 +366,48 @@ public class PacketManager } } + /** + * Entity for tracking stats for a packet processor. + */ + private class ProcessorEntry implements PacketProcessorEntry { + private final PacketProcessor processor; + private final int priority; + private long invocations = 0; + private long nanos = 0; + + public ProcessorEntry(PacketProcessor processor, int priority) { + this.processor = processor; + this.priority = priority; + } + + @Override + public PacketProcessor processor() { + return processor; + } + + @Override + public int priority() { + return priority; + } + + @Override + public long invocations() { + return invocations; + } + + @Override + public long totalNanos() { + return nanos; + } + + @Override + public long averageNanos() { + return invocations > 0 ? nanos / invocations : 0; + } + + void addNanos(long nanos) { + this.nanos += nanos; + this.invocations++; + } + } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java new file mode 100644 index 00000000..6515ef31 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java @@ -0,0 +1,634 @@ +/*
+ * 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.net.statistic.impl;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+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.apache.felix.scr.annotations.Service;
+import org.onosproject.cli.Comparators;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTypedFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleListener;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.statistic.DefaultLoad;
+import org.onosproject.net.statistic.FlowStatisticService;
+import org.onosproject.net.statistic.Load;
+import org.onosproject.net.statistic.FlowStatisticStore;
+import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;
+import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
+
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
+import static org.onosproject.security.AppPermission.Type.*;
+
+/**
+ * Provides an implementation of the Flow Statistic Service.
+ */
+@Component(immediate = true, enabled = true)
+@Service
+public class FlowStatisticManager implements FlowStatisticService {
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleService flowRuleService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowStatisticStore flowStatisticStore;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ private final InternalFlowRuleStatsListener frListener = new InternalFlowRuleStatsListener();
+
+ @Activate
+ public void activate() {
+ flowRuleService.addListener(frListener);
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ flowRuleService.removeListener(frListener);
+ log.info("Stopped");
+ }
+
+ @Override
+ public Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device) {
+ checkPermission(STATISTIC_READ);
+
+ Map<ConnectPoint, SummaryFlowEntryWithLoad> summaryLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
+
+ if (device == null) {
+ return summaryLoad;
+ }
+
+ List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
+
+ for (Port port : ports) {
+ ConnectPoint cp = new ConnectPoint(device.id(), port.number());
+ SummaryFlowEntryWithLoad sfe = loadSummaryPortInternal(cp);
+ summaryLoad.put(cp, sfe);
+ }
+
+ return summaryLoad;
+ }
+
+ @Override
+ public SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber) {
+ checkPermission(STATISTIC_READ);
+
+ ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
+ return loadSummaryPortInternal(cp);
+ }
+
+ @Override
+ public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType) {
+ checkPermission(STATISTIC_READ);
+
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
+
+ if (device == null) {
+ return allLoad;
+ }
+
+ List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
+
+ for (Port port : ports) {
+ ConnectPoint cp = new ConnectPoint(device.id(), port.number());
+ List<TypedFlowEntryWithLoad> tfel = loadAllPortInternal(cp, liveType, instType);
+ allLoad.put(cp, tfel);
+ }
+
+ return allLoad;
+ }
+
+ @Override
+ public List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType) {
+ checkPermission(STATISTIC_READ);
+
+ ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
+ return loadAllPortInternal(cp, liveType, instType);
+ }
+
+ @Override
+ public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn) {
+ checkPermission(STATISTIC_READ);
+
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
+
+ if (device == null) {
+ return allLoad;
+ }
+
+ List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
+
+ for (Port port : ports) {
+ ConnectPoint cp = new ConnectPoint(device.id(), port.number());
+ List<TypedFlowEntryWithLoad> tfel = loadTopnPortInternal(cp, liveType, instType, topn);
+ allLoad.put(cp, tfel);
+ }
+
+ return allLoad;
+ }
+
+ @Override
+ public List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn) {
+ checkPermission(STATISTIC_READ);
+
+ ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
+ return loadTopnPortInternal(cp, liveType, instType, topn);
+ }
+
+ private SummaryFlowEntryWithLoad loadSummaryPortInternal(ConnectPoint cp) {
+ checkPermission(STATISTIC_READ);
+
+ Set<FlowEntry> currentStats;
+ Set<FlowEntry> previousStats;
+
+ TypedStatistics typedStatistics;
+ synchronized (flowStatisticStore) {
+ currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);
+ if (currentStats == null) {
+ return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
+ }
+ previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);
+ if (previousStats == null) {
+ return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
+ }
+ // copy to local flow entry
+ typedStatistics = new TypedStatistics(currentStats, previousStats);
+
+ // Check for validity of this stats data
+ checkLoadValidity(currentStats, previousStats);
+ }
+
+ // current and previous set is not empty!
+ Set<FlowEntry> currentSet = typedStatistics.current();
+ Set<FlowEntry> previousSet = typedStatistics.previous();
+ Load totalLoad = new DefaultLoad(aggregateBytesSet(currentSet), aggregateBytesSet(previousSet),
+ TypedFlowEntryWithLoad.avgPollInterval());
+
+ Map<FlowRule, TypedStoredFlowEntry> currentMap;
+ Map<FlowRule, TypedStoredFlowEntry> previousMap;
+
+ currentMap = typedStatistics.currentImmediate();
+ previousMap = typedStatistics.previousImmediate();
+ Load immediateLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.shortPollInterval());
+
+ currentMap = typedStatistics.currentShort();
+ previousMap = typedStatistics.previousShort();
+ Load shortLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.shortPollInterval());
+
+ currentMap = typedStatistics.currentMid();
+ previousMap = typedStatistics.previousMid();
+ Load midLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.midPollInterval());
+
+ currentMap = typedStatistics.currentLong();
+ previousMap = typedStatistics.previousLong();
+ Load longLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.longPollInterval());
+
+ currentMap = typedStatistics.currentUnknown();
+ previousMap = typedStatistics.previousUnknown();
+ Load unknownLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.avgPollInterval());
+
+ return new SummaryFlowEntryWithLoad(cp, totalLoad, immediateLoad, shortLoad, midLoad, longLoad, unknownLoad);
+ }
+
+ private List<TypedFlowEntryWithLoad> loadAllPortInternal(ConnectPoint cp,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType) {
+ checkPermission(STATISTIC_READ);
+
+ List<TypedFlowEntryWithLoad> retTFEL = new ArrayList<>();
+
+ Set<FlowEntry> currentStats;
+ Set<FlowEntry> previousStats;
+
+ TypedStatistics typedStatistics;
+ synchronized (flowStatisticStore) {
+ currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);
+ if (currentStats == null) {
+ return retTFEL;
+ }
+ previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);
+ if (previousStats == null) {
+ return retTFEL;
+ }
+ // copy to local flow entry set
+ typedStatistics = new TypedStatistics(currentStats, previousStats);
+
+ // Check for validity of this stats data
+ checkLoadValidity(currentStats, previousStats);
+ }
+
+ // current and previous set is not empty!
+ boolean isAllLiveType = (liveType == null ? true : false); // null is all live type
+ boolean isAllInstType = (instType == null ? true : false); // null is all inst type
+
+ Map<FlowRule, TypedStoredFlowEntry> currentMap;
+ Map<FlowRule, TypedStoredFlowEntry> previousMap;
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW) {
+ currentMap = typedStatistics.currentImmediate();
+ previousMap = typedStatistics.previousImmediate();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW) {
+ currentMap = typedStatistics.currentShort();
+ previousMap = typedStatistics.previousShort();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.MID_FLOW) {
+ currentMap = typedStatistics.currentMid();
+ previousMap = typedStatistics.previousMid();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.midPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.LONG_FLOW) {
+ currentMap = typedStatistics.currentLong();
+ previousMap = typedStatistics.previousLong();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.longPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW) {
+ currentMap = typedStatistics.currentUnknown();
+ previousMap = typedStatistics.previousUnknown();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.avgPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ return retTFEL;
+ }
+
+ private List<TypedFlowEntryWithLoad> typedFlowEntryLoadByInstInternal(ConnectPoint cp,
+ Map<FlowRule, TypedStoredFlowEntry> currentMap,
+ Map<FlowRule, TypedStoredFlowEntry> previousMap,
+ boolean isAllInstType,
+ Instruction.Type instType,
+ int liveTypePollInterval) {
+ List<TypedFlowEntryWithLoad> fel = new ArrayList<>();
+
+ for (TypedStoredFlowEntry tfe : currentMap.values()) {
+ if (isAllInstType ||
+ tfe.treatment().allInstructions().stream().
+ filter(i -> i.type() == instType).
+ findAny().isPresent()) {
+ long currentBytes = tfe.bytes();
+ long previousBytes = previousMap.getOrDefault(tfe, new DefaultTypedFlowEntry((FlowRule) tfe)).bytes();
+ Load fLoad = new DefaultLoad(currentBytes, previousBytes, liveTypePollInterval);
+ fel.add(new TypedFlowEntryWithLoad(cp, tfe, fLoad));
+ }
+ }
+
+ return fel;
+ }
+
+ private List<TypedFlowEntryWithLoad> loadTopnPortInternal(ConnectPoint cp,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn) {
+ List<TypedFlowEntryWithLoad> fel = loadAllPortInternal(cp, liveType, instType);
+
+ // Sort with descending order of load
+ List<TypedFlowEntryWithLoad> tfel =
+ fel.stream().sorted(Comparators.TYPEFLOWENTRY_WITHLOAD_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+
+ return tfel;
+ }
+
+ private long aggregateBytesSet(Set<FlowEntry> setFE) {
+ return setFE.stream().mapToLong(FlowEntry::bytes).sum();
+ }
+
+ private long aggregateBytesMap(Map<FlowRule, TypedStoredFlowEntry> mapFE) {
+ return mapFE.values().stream().mapToLong(FlowEntry::bytes).sum();
+ }
+
+ /**
+ * Internal data class holding two set of typed flow entries.
+ */
+ private static class TypedStatistics {
+ private final ImmutableSet<FlowEntry> currentAll;
+ private final ImmutableSet<FlowEntry> previousAll;
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentImmediate = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousImmediate = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentShort = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousShort = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentMid = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousMid = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentLong = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousLong = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentUnknown = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousUnknown = new HashMap<>();
+
+ public TypedStatistics(Set<FlowEntry> current, Set<FlowEntry> previous) {
+ this.currentAll = ImmutableSet.copyOf(checkNotNull(current));
+ this.previousAll = ImmutableSet.copyOf(checkNotNull(previous));
+
+ currentAll.forEach(fe -> {
+ TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);
+
+ switch (tfe.flowLiveType()) {
+ case IMMEDIATE_FLOW:
+ currentImmediate.put(fe, tfe);
+ break;
+ case SHORT_FLOW:
+ currentShort.put(fe, tfe);
+ break;
+ case MID_FLOW:
+ currentMid.put(fe, tfe);
+ break;
+ case LONG_FLOW:
+ currentLong.put(fe, tfe);
+ break;
+ default:
+ currentUnknown.put(fe, tfe);
+ break;
+ }
+ });
+
+ previousAll.forEach(fe -> {
+ TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);
+
+ switch (tfe.flowLiveType()) {
+ case IMMEDIATE_FLOW:
+ if (currentImmediate.containsKey(fe)) {
+ previousImmediate.put(fe, tfe);
+ } else if (currentShort.containsKey(fe)) {
+ previousShort.put(fe, tfe);
+ } else if (currentMid.containsKey(fe)) {
+ previousMid.put(fe, tfe);
+ } else if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ case SHORT_FLOW:
+ if (currentShort.containsKey(fe)) {
+ previousShort.put(fe, tfe);
+ } else if (currentMid.containsKey(fe)) {
+ previousMid.put(fe, tfe);
+ } else if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ case MID_FLOW:
+ if (currentMid.containsKey(fe)) {
+ previousMid.put(fe, tfe);
+ } else if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ case LONG_FLOW:
+ if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ default:
+ previousUnknown.put(fe, tfe);
+ break;
+ }
+ });
+ }
+
+ /**
+ * Returns flow entries as the current value.
+ *
+ * @return flow entries as the current value
+ */
+ public ImmutableSet<FlowEntry> current() {
+ return currentAll;
+ }
+
+ /**
+ * Returns flow entries as the previous value.
+ *
+ * @return flow entries as the previous value
+ */
+ public ImmutableSet<FlowEntry> previous() {
+ return previousAll;
+ }
+
+ public Map<FlowRule, TypedStoredFlowEntry> currentImmediate() {
+ return currentImmediate;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousImmediate() {
+ return previousImmediate;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentShort() {
+ return currentShort;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousShort() {
+ return previousShort;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentMid() {
+ return currentMid;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousMid() {
+ return previousMid;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentLong() {
+ return currentLong;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousLong() {
+ return previousLong;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentUnknown() {
+ return currentUnknown;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousUnknown() {
+ return previousUnknown;
+ }
+
+ /**
+ * Validates values are not empty.
+ *
+ * @return false if either of the sets is empty. Otherwise, true.
+ */
+ public boolean isValid() {
+ return !(currentAll.isEmpty() || previousAll.isEmpty());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(currentAll, previousAll);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TypedStatistics)) {
+ return false;
+ }
+ final TypedStatistics other = (TypedStatistics) obj;
+ return Objects.equals(this.currentAll, other.currentAll) &&
+ Objects.equals(this.previousAll, other.previousAll);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("current", currentAll)
+ .add("previous", previousAll)
+ .toString();
+ }
+ }
+
+ private void checkLoadValidity(Set<FlowEntry> current, Set<FlowEntry> previous) {
+ current.stream().forEach(c -> {
+ FlowEntry f = previous.stream().filter(p -> c.equals(p)).
+ findAny().orElse(null);
+ if (f != null && c.bytes() < f.bytes()) {
+ log.debug("FlowStatisticManager:checkLoadValidity():" +
+ "Error: " + c + " :Previous bytes=" + f.bytes() +
+ " is larger than current bytes=" + c.bytes() + " !!!");
+ }
+ });
+
+ }
+
+ /**
+ * Creates a predicate that checks the instruction type of a flow entry is the same as
+ * the specified instruction type.
+ *
+ * @param instType instruction type to be checked
+ * @return predicate
+ */
+ private static Predicate<FlowEntry> hasInstructionType(Instruction.Type instType) {
+ return new Predicate<FlowEntry>() {
+ @Override
+ public boolean apply(FlowEntry flowEntry) {
+ List<Instruction> allInstructions = flowEntry.treatment().allInstructions();
+
+ return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent();
+ }
+ };
+ }
+
+ /**
+ * Internal flow rule event listener for FlowStatisticManager.
+ */
+ private class InternalFlowRuleStatsListener implements FlowRuleListener {
+
+ @Override
+ public void event(FlowRuleEvent event) {
+ FlowRule rule = event.subject();
+ switch (event.type()) {
+ case RULE_ADDED:
+ if (rule instanceof FlowEntry) {
+ flowStatisticStore.addFlowStatistic((FlowEntry) rule);
+ }
+ break;
+ case RULE_UPDATED:
+ flowStatisticStore.updateFlowStatistic((FlowEntry) rule);
+ break;
+ case RULE_ADD_REQUESTED:
+ break;
+ case RULE_REMOVE_REQUESTED:
+ break;
+ case RULE_REMOVED:
+ flowStatisticStore.removeFlowStatistic(rule);
+ break;
+ default:
+ log.warn("Unknown flow rule event {}", event);
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java index a238c7fb..8347ee38 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java @@ -27,6 +27,8 @@ import org.apache.felix.scr.annotations.Service; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DefaultEdgeLink; import org.onosproject.net.DefaultPath; +import org.onosproject.net.DisjointPath; +import org.onosproject.net.DefaultDisjointPath; import org.onosproject.net.DeviceId; import org.onosproject.net.EdgeLink; import org.onosproject.net.ElementId; @@ -46,6 +48,8 @@ import org.slf4j.Logger; import java.util.List; import java.util.Set; +import java.util.Map; + import static com.google.common.base.Preconditions.checkNotNull; import static org.slf4j.LoggerFactory.getLogger; @@ -128,6 +132,84 @@ public class PathManager implements PathService { return edgeToEdgePaths(srcEdge, dstEdge, paths); } + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst) { + return getDisjointPaths(src, dst, (LinkWeight) null); + } + + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) { + checkNotNull(src, ELEMENT_ID_NULL); + checkNotNull(dst, ELEMENT_ID_NULL); + + // Get the source and destination edge locations + EdgeLink srcEdge = getEdgeLink(src, true); + EdgeLink dstEdge = getEdgeLink(dst, false); + + // If either edge is null, bail with no paths. + if (srcEdge == null || dstEdge == null) { + return ImmutableSet.of(); + } + + DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src; + DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst; + + // If the source and destination are on the same edge device, there + // is just one path, so build it and return it. + if (srcDevice.equals(dstDevice)) { + return edgeToEdgePathsDisjoint(srcEdge, dstEdge); + } + + // Otherwise get all paths between the source and destination edge + // devices. + Topology topology = topologyService.currentTopology(); + Set<DisjointPath> paths = weight == null ? + topologyService.getDisjointPaths(topology, srcDevice, dstDevice) : + topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight); + + return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths); + } + + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, + Map<Link, Object> riskProfile) { + return getDisjointPaths(src, dst, null, riskProfile); + } + + @Override + public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight, + Map<Link, Object> riskProfile) { + checkNotNull(src, ELEMENT_ID_NULL); + checkNotNull(dst, ELEMENT_ID_NULL); + + // Get the source and destination edge locations + EdgeLink srcEdge = getEdgeLink(src, true); + EdgeLink dstEdge = getEdgeLink(dst, false); + + // If either edge is null, bail with no paths. + if (srcEdge == null || dstEdge == null) { + return ImmutableSet.of(); + } + + DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src; + DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst; + + // If the source and destination are on the same edge device, there + // is just one path, so build it and return it. + if (srcDevice.equals(dstDevice)) { + return edgeToEdgePathsDisjoint(srcEdge, dstEdge); + } + + // Otherwise get all paths between the source and destination edge + // devices. + Topology topology = topologyService.currentTopology(); + Set<DisjointPath> paths = weight == null ? + topologyService.getDisjointPaths(topology, srcDevice, dstDevice, riskProfile) : + topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight, riskProfile); + + return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths); + } + // Finds the host edge link if the element ID is a host id of an existing // host. Otherwise, if the host does not exist, it returns null and if // the element ID is not a host ID, returns NOT_HOST edge link. @@ -162,6 +244,20 @@ public class PathManager implements PathService { return endToEndPaths; } + private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink) { + Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(1); + endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, null)); + return endToEndPaths; + } + + private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink, Set<DisjointPath> paths) { + Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size()); + for (DisjointPath path : paths) { + endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, path)); + } + return endToEndPaths; + } + // Produces a direct edge-to-edge path. private Path edgeToEdgePath(EdgeLink srcLink, EdgeLink dstLink, Path path) { List<Link> links = Lists.newArrayListWithCapacity(2); @@ -179,6 +275,13 @@ public class PathManager implements PathService { return new DefaultPath(PID, links, 2); } + // Produces a direct edge-to-edge path. + private DisjointPath edgeToEdgePathD(EdgeLink srcLink, EdgeLink dstLink, DisjointPath path) { + return new DefaultDisjointPath(PID, (DefaultPath) edgeToEdgePath(srcLink, dstLink, path.primary()), + (DefaultPath) edgeToEdgePath(srcLink, dstLink, path.backup())); + } + + // Special value for edge link to represent that this is really not an // edge link since the src or dst are really an infrastructure device. private static class NotHost extends DefaultEdgeLink implements EdgeLink { diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java index 04c4f1c1..4425e1c1 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java @@ -21,6 +21,7 @@ import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.DisjointPath; import org.onosproject.net.provider.AbstractListenerProviderRegistry; import org.onosproject.event.Event; import org.onosproject.net.ConnectPoint; @@ -46,6 +47,7 @@ import org.slf4j.Logger; import java.util.List; import java.util.Set; +import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; import static org.onosproject.security.AppGuard.checkPermission; @@ -60,7 +62,7 @@ import static org.onosproject.security.AppPermission.Type.*; @Service public class TopologyManager extends AbstractListenerProviderRegistry<TopologyEvent, TopologyListener, - TopologyProvider, TopologyProviderService> + TopologyProvider, TopologyProviderService> implements TopologyService, TopologyProviderRegistry { public static final String TOPOLOGY_NULL = "Topology cannot be null"; @@ -68,6 +70,7 @@ public class TopologyManager private static final String CLUSTER_ID_NULL = "Cluster ID cannot be null"; private static final String CLUSTER_NULL = "Topology cluster cannot be null"; public static final String CONNECTION_POINT_NULL = "Connection point cannot be null"; + public static final String LINK_WEIGHT_NULL = "Link weight cannot be null"; private final Logger log = getLogger(getClass()); @@ -162,6 +165,44 @@ public class TopologyManager } @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + return store.getDisjointPaths(topology, src, dst); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + checkNotNull(weight, LINK_WEIGHT_NULL); + return store.getDisjointPaths(topology, src, dst, weight); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map<Link, Object> riskProfile) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + return store.getDisjointPaths(topology, src, dst, riskProfile); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight, + Map<Link, Object> riskProfile) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + checkNotNull(weight, LINK_WEIGHT_NULL); + return store.getDisjointPaths(topology, src, dst, weight, riskProfile); + } + + @Override public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { checkPermission(TOPOLOGY_READ); checkNotNull(topology, TOPOLOGY_NULL); diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java new file mode 100644 index 00000000..0320cf77 --- /dev/null +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java @@ -0,0 +1,126 @@ +/* + * 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.cfg.impl; + +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Files; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.cfg.ComponentConfigAdapter; +import org.slf4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.util.Set; + +import static com.google.common.io.ByteStreams.toByteArray; +import static com.google.common.io.Files.write; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * UnitTest for ComponentLoader. + */ +public class ComponentConfigLoaderTest { + + static final File TEST_DIR = Files.createTempDir(); + + private static final String FOO_COMPONENT = "fooComponent"; + + private ComponentConfigLoader loader; + + private TestConfigService service; + + private final Logger log = getLogger(getClass()); + + /* + * Method to SetUp the test environment with test file, a config loader a service, + * and assign it to the loader.configService for the test. + */ + @Before + public void setUp() { + ComponentConfigLoader.cfgFile = new File(TEST_DIR, "test.json"); + loader = new ComponentConfigLoader(); + service = new TestConfigService(); + loader.configService = service; + } + + /* + * Tests that the component in the json receives the correct configuration. + */ + @Test + public void basics() throws IOException { + stageTestResource("basic.json"); + loader.activate(); + assertEquals("incorrect component", FOO_COMPONENT, service.component); + } + + /* + * Tests that the component is null if the file has a bad configuration format + * for which it yielded an exception. Can't test the exception because it happens + * in a different thread. + */ + @Test + public void badConfig() throws IOException { + stageTestResource("badConfig.json"); + loader.activate(); + assertNull("incorrect configuration", service.component); + + } + + /* + * Writes the necessary file for the tests in the temporary directory + */ + static void stageTestResource(String name) throws IOException { + byte[] bytes = toByteArray(ComponentConfigLoaderTest.class.getResourceAsStream(name)); + write(bytes, ComponentConfigLoader.cfgFile); + } + + /* + * Mockup class for the config service. + */ + private class TestConfigService extends ComponentConfigAdapter { + + protected String component; + protected String name; + protected String value; + + @Override + public Set<String> getComponentNames() { + return ImmutableSet.of(FOO_COMPONENT); + } + + @Override + public void preSetProperty(String componentName, String name, String value) { + log.info("preSet"); + this.component = componentName; + this.name = name; + this.value = value; + + } + + @Override + public void setProperty(String componentName, String name, String value) { + log.info("Set"); + this.component = componentName; + this.name = name; + this.value = value; + + } + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java index d167197a..3cd2ca2b 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java @@ -23,10 +23,12 @@ import org.junit.Before; import org.junit.Test; import org.onlab.packet.ARP; import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv6; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.VlanId; +import org.onlab.packet.ndp.NeighborSolicitation; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; @@ -64,14 +66,22 @@ import static org.junit.Assert.assertTrue; public class HostMonitorTest { - private static final IpAddress TARGET_IP_ADDR = + private static final IpAddress TARGET_IPV4_ADDR = IpAddress.valueOf("10.0.0.1"); - private static final IpAddress SOURCE_ADDR = + private static final IpAddress SOURCE_IPV4_ADDR = IpAddress.valueOf("10.0.0.99"); private static final InterfaceIpAddress IA1 = - new InterfaceIpAddress(SOURCE_ADDR, IpPrefix.valueOf("10.0.0.0/24")); + new InterfaceIpAddress(SOURCE_IPV4_ADDR, IpPrefix.valueOf("10.0.0.0/24")); private MacAddress sourceMac = MacAddress.valueOf(1L); + private static final IpAddress TARGET_IPV6_ADDR = + IpAddress.valueOf("1000::1"); + private static final IpAddress SOURCE_IPV6_ADDR = + IpAddress.valueOf("1000::f"); + private static final InterfaceIpAddress IA2 = + new InterfaceIpAddress(SOURCE_IPV6_ADDR, IpPrefix.valueOf("1000::/64")); + private MacAddress sourceMac2 = MacAddress.valueOf(2L); + private EdgePortService edgePortService; private HostMonitor hostMonitor; @@ -90,7 +100,36 @@ public class HostMonitorTest { } @Test - public void testMonitorHostExists() throws Exception { + public void testMonitorIpv4HostExists() throws Exception { + ProviderId id = new ProviderId("fake://", "id"); + + Host host = createMock(Host.class); + expect(host.providerId()).andReturn(id); + replay(host); + + HostManager hostManager = createMock(HostManager.class); + expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR)) + .andReturn(Collections.singleton(host)); + replay(hostManager); + + HostProvider hostProvider = createMock(HostProvider.class); + expect(hostProvider.id()).andReturn(id).anyTimes(); + hostProvider.triggerProbe(host); + expectLastCall().once(); + replay(hostProvider); + + hostMonitor = new HostMonitor(null, hostManager, null, edgePortService); + + hostMonitor.registerHostProvider(hostProvider); + hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR); + + hostMonitor.run(null); + + verify(hostProvider); + } + + @Test + public void testMonitorIpv6HostExists() throws Exception { ProviderId id = new ProviderId("fake://", "id"); Host host = createMock(Host.class); @@ -98,7 +137,7 @@ public class HostMonitorTest { replay(host); HostManager hostManager = createMock(HostManager.class); - expect(hostManager.getHostsByIp(TARGET_IP_ADDR)) + expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR)) .andReturn(Collections.singleton(host)); replay(hostManager); @@ -111,7 +150,7 @@ public class HostMonitorTest { hostMonitor = new HostMonitor(null, hostManager, null, edgePortService); hostMonitor.registerHostProvider(hostProvider); - hostMonitor.addMonitoringFor(TARGET_IP_ADDR); + hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR); hostMonitor.run(null); @@ -119,7 +158,7 @@ public class HostMonitorTest { } @Test - public void testMonitorHostDoesNotExist() throws Exception { + public void testMonitorIpv4HostDoesNotExist() throws Exception { HostManager hostManager = createMock(HostManager.class); @@ -140,12 +179,12 @@ public class HostMonitorTest { ConnectPoint cp = new ConnectPoint(devId, portNum); - expect(hostManager.getHostsByIp(TARGET_IP_ADDR)) + expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR)) .andReturn(Collections.emptySet()).anyTimes(); replay(hostManager); InterfaceService interfaceService = createMock(InterfaceService.class); - expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR)) + expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR)) .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE)) .anyTimes(); replay(interfaceService); @@ -156,7 +195,7 @@ public class HostMonitorTest { // Run the test hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); - hostMonitor.addMonitoringFor(TARGET_IP_ADDR); + hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR); hostMonitor.run(null); @@ -178,16 +217,85 @@ public class HostMonitorTest { Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID()); ARP arp = (ARP) eth.getPayload(); - assertArrayEquals(SOURCE_ADDR.toOctets(), + assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(), arp.getSenderProtocolAddress()); assertArrayEquals(sourceMac.toBytes(), arp.getSenderHardwareAddress()); - assertArrayEquals(TARGET_IP_ADDR.toOctets(), + assertArrayEquals(TARGET_IPV4_ADDR.toOctets(), arp.getTargetProtocolAddress()); } @Test - public void testMonitorHostDoesNotExistWithVlan() throws Exception { + public void testMonitorIpv6HostDoesNotExist() throws Exception { + + HostManager hostManager = createMock(HostManager.class); + + DeviceId devId = DeviceId.deviceId("fake"); + + Device device = createMock(Device.class); + expect(device.id()).andReturn(devId).anyTimes(); + replay(device); + + PortNumber portNum = PortNumber.portNumber(2L); + + Port port = createMock(Port.class); + expect(port.number()).andReturn(portNum).anyTimes(); + replay(port); + + TestDeviceService deviceService = new TestDeviceService(); + deviceService.addDevice(device, Collections.singleton(port)); + + ConnectPoint cp = new ConnectPoint(devId, portNum); + + expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR)) + .andReturn(Collections.emptySet()).anyTimes(); + replay(hostManager); + + InterfaceService interfaceService = createMock(InterfaceService.class); + expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR)) + .andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.NONE)) + .anyTimes(); + replay(interfaceService); + + TestPacketService packetService = new TestPacketService(); + + + // Run the test + hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); + + hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR); + hostMonitor.run(null); + + + // Check that a packet was sent to our PacketService and that it has + // the properties we expect + assertEquals(1, packetService.packets.size()); + OutboundPacket packet = packetService.packets.get(0); + + // Check the output port is correct + assertEquals(1, packet.treatment().immediate().size()); + Instruction instruction = packet.treatment().immediate().get(0); + assertTrue(instruction instanceof OutputInstruction); + OutputInstruction oi = (OutputInstruction) instruction; + assertEquals(portNum, oi.port()); + + // Check the output packet is correct (well the important bits anyway) + final byte[] pktData = new byte[packet.data().remaining()]; + packet.data().get(pktData); + Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); + assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID()); + IPv6 ipv6 = (IPv6) eth.getPayload(); + assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress()); + + NeighborSolicitation ns = + (NeighborSolicitation) ipv6.getPayload().getPayload(); + assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data()); + + assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress()); + } + + @Test + public void testMonitorIpv4HostDoesNotExistWithVlan() throws Exception { HostManager hostManager = createMock(HostManager.class); @@ -209,12 +317,12 @@ public class HostMonitorTest { ConnectPoint cp = new ConnectPoint(devId, portNum); - expect(hostManager.getHostsByIp(TARGET_IP_ADDR)) + expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR)) .andReturn(Collections.emptySet()).anyTimes(); replay(hostManager); InterfaceService interfaceService = createMock(InterfaceService.class); - expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR)) + expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR)) .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.vlanId(vlan))) .anyTimes(); replay(interfaceService); @@ -225,7 +333,7 @@ public class HostMonitorTest { // Run the test hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); - hostMonitor.addMonitoringFor(TARGET_IP_ADDR); + hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR); hostMonitor.run(null); @@ -247,14 +355,84 @@ public class HostMonitorTest { Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); assertEquals(vlan, eth.getVlanID()); ARP arp = (ARP) eth.getPayload(); - assertArrayEquals(SOURCE_ADDR.toOctets(), + assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(), arp.getSenderProtocolAddress()); assertArrayEquals(sourceMac.toBytes(), arp.getSenderHardwareAddress()); - assertArrayEquals(TARGET_IP_ADDR.toOctets(), + assertArrayEquals(TARGET_IPV4_ADDR.toOctets(), arp.getTargetProtocolAddress()); } + @Test + public void testMonitorIpv6HostDoesNotExistWithVlan() throws Exception { + + HostManager hostManager = createMock(HostManager.class); + + DeviceId devId = DeviceId.deviceId("fake"); + short vlan = 5; + + Device device = createMock(Device.class); + expect(device.id()).andReturn(devId).anyTimes(); + replay(device); + + PortNumber portNum = PortNumber.portNumber(1L); + + Port port = createMock(Port.class); + expect(port.number()).andReturn(portNum).anyTimes(); + replay(port); + + TestDeviceService deviceService = new TestDeviceService(); + deviceService.addDevice(device, Collections.singleton(port)); + + ConnectPoint cp = new ConnectPoint(devId, portNum); + + expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR)) + .andReturn(Collections.emptySet()).anyTimes(); + replay(hostManager); + + InterfaceService interfaceService = createMock(InterfaceService.class); + expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR)) + .andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.vlanId(vlan))) + .anyTimes(); + replay(interfaceService); + + TestPacketService packetService = new TestPacketService(); + + + // Run the test + hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); + + hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR); + hostMonitor.run(null); + + + // Check that a packet was sent to our PacketService and that it has + // the properties we expect + assertEquals(1, packetService.packets.size()); + OutboundPacket packet = packetService.packets.get(0); + + // Check the output port is correct + assertEquals(1, packet.treatment().immediate().size()); + Instruction instruction = packet.treatment().immediate().get(0); + assertTrue(instruction instanceof OutputInstruction); + OutputInstruction oi = (OutputInstruction) instruction; + assertEquals(portNum, oi.port()); + + // Check the output packet is correct (well the important bits anyway) + final byte[] pktData = new byte[packet.data().remaining()]; + packet.data().get(pktData); + Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); + assertEquals(vlan, eth.getVlanID()); + IPv6 ipv6 = (IPv6) eth.getPayload(); + assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress()); + + NeighborSolicitation ns = + (NeighborSolicitation) ipv6.getPayload().getPayload(); + assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data()); + + assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress()); + } + class TestPacketService extends PacketServiceAdapter { List<OutboundPacket> packets = new ArrayList<>(); diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java index 4bf32f43..3f40de09 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java @@ -157,7 +157,7 @@ public class IntentManagerTest { private static class MockInstallableIntent extends FlowRuleIntent { public MockInstallableIntent() { - super(APPID, Collections.singletonList(new MockFlowRule(100))); + super(APPID, Collections.singletonList(new MockFlowRule(100)), Collections.emptyList()); } } diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java index eb7a3936..03d664d3 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java @@ -31,8 +31,7 @@ import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentTestsMocks; import org.onosproject.net.intent.LinkCollectionIntent; import org.onosproject.net.intent.MultiPointToSinglePointIntent; -import org.onosproject.net.topology.LinkWeight; -import org.onosproject.net.topology.PathService; +import org.onosproject.net.topology.PathServiceAdapter; import java.util.HashSet; import java.util.List; @@ -60,7 +59,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes /** * Mock path service for creating paths within the test. */ - private static class MockPathService implements PathService { + private static class MockPathService extends PathServiceAdapter { final String[] pathHops; @@ -86,11 +85,6 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes return result; } - - @Override - public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) { - return null; - } } /** diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java index 2f40b37a..38a116dd 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java @@ -27,18 +27,12 @@ import org.onosproject.net.DefaultLink; import org.onosproject.net.DefaultPath; import org.onosproject.net.Link; import org.onosproject.net.OchSignalType; -import org.onosproject.net.flow.DefaultTrafficSelector; -import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowRule; -import org.onosproject.net.flow.TrafficSelector; -import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.intent.FlowRuleIntent; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentExtensionService; -import org.onosproject.net.intent.IntentTestsMocks; import org.onosproject.net.intent.MockIdGenerator; import org.onosproject.net.intent.OpticalPathIntent; -import org.onosproject.net.provider.ProviderId; import java.util.Arrays; import java.util.Collection; @@ -63,16 +57,11 @@ public class OpticalPathIntentCompilerTest { private final IdGenerator idGenerator = new MockIdGenerator(); private OpticalPathIntentCompiler sut; - private final TrafficSelector selector = DefaultTrafficSelector.builder().build(); - private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); private final ApplicationId appId = new TestApplicationId("test"); - private final ProviderId pid = new ProviderId("of", "test"); private final ConnectPoint d1p1 = connectPoint("s1", 0); private final ConnectPoint d2p0 = connectPoint("s2", 0); private final ConnectPoint d2p1 = connectPoint("s2", 1); private final ConnectPoint d3p1 = connectPoint("s3", 1); - private final ConnectPoint d3p0 = connectPoint("s3", 10); - private final ConnectPoint d1p0 = connectPoint("s1", 10); private final List<Link> links = Arrays.asList( new DefaultLink(PID, d1p1, d2p0, DIRECT), @@ -103,7 +92,6 @@ public class OpticalPathIntentCompilerTest { intentExtensionService.registerCompiler(OpticalPathIntent.class, sut); intentExtensionService.unregisterCompiler(OpticalPathIntent.class); sut.intentManager = intentExtensionService; - sut.resourceService = new IntentTestsMocks.MockResourceService(); replay(coreService, intentExtensionService); } diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java index 2a2d0b54..1911da56 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java @@ -23,13 +23,11 @@ import org.onosproject.net.ElementId; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.Path; -import org.onosproject.net.host.HostService; import org.onosproject.net.host.HostServiceAdapter; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.PathService; import org.onosproject.net.topology.Topology; -import org.onosproject.net.topology.TopologyService; import org.onosproject.net.topology.TopologyServiceAdapter; import java.util.HashMap; @@ -137,7 +135,7 @@ public class PathManagerTest { } // Fake entity to give out paths. - private class FakeTopoMgr extends TopologyServiceAdapter implements TopologyService { + private class FakeTopoMgr extends TopologyServiceAdapter { Set<Path> paths = new HashSet<>(); @Override @@ -152,7 +150,7 @@ public class PathManagerTest { } // Fake entity to give out hosts. - private class FakeHostMgr extends HostServiceAdapter implements HostService { + private class FakeHostMgr extends HostServiceAdapter { private Map<HostId, Host> hosts = new HashMap<>(); @Override diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java index f3cd28df..56133a0f 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java @@ -114,7 +114,7 @@ public class TopologyManagerTest { link("c", 2, "d", 1), link("d", 1, "c", 2), link("d", 2, "a", 2), link("a", 2, "d", 2), link("e", 1, "f", 1), link("f", 1, "e", 1)); - GraphDescription data = new DefaultGraphDescription(4321L, devices, links); + GraphDescription data = new DefaultGraphDescription(4321L, System.currentTimeMillis(), devices, links); providerService.topologyChanged(data, null); } diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json new file mode 100644 index 00000000..5c0ac35d --- /dev/null +++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json @@ -0,0 +1,5 @@ +{ + "org.onosproject.proxyarp.ProxyArp2": { + "testProperty": true + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json new file mode 100644 index 00000000..a76552e5 --- /dev/null +++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json @@ -0,0 +1,5 @@ +{ + "fooComponent": { + badconfig + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json new file mode 100644 index 00000000..dd329243 --- /dev/null +++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json @@ -0,0 +1,5 @@ +{ + "fooComponent": { + "testProperty": true + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java index ff3e36ac..52a999a4 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java @@ -38,7 +38,7 @@ public interface Database extends DatabaseProxy<String, byte[]>, Resource<Databa * options specified in {@code cluster.conf} will override those in {cluster-defaults.conf}.<p> * * Additionally, the database will be constructed with an database configuration that searches the classpath for - * three configuration files - {@code {name}}, {@code database}, {@code database-defaults}, {@code resource}, and + * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and * {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name * as the map resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource * configurations will be loaded according to namespaces as well; for example, `databases.conf`. @@ -54,7 +54,7 @@ public interface Database extends DatabaseProxy<String, byte[]>, Resource<Databa * Creates a new database.<p> * * The database will be constructed with an database configuration that searches the classpath for - * three configuration files - {@code {name}}, {@code database}, {@code database-defaults}, {@code resource}, and + * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and * {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name * as the database resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource * configurations will be loaded according to namespaces as well; for example, `databases.conf`. diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java index fbc2c88d..6ea7c220 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java @@ -443,7 +443,10 @@ public class DatabaseManager implements StorageService, StorageAdminService { public void event(ApplicationEvent event) { if (event.type() == APP_UNINSTALLED || event.type() == APP_DEACTIVATED) { ApplicationId appId = event.subject().id(); - List<DefaultAsyncConsistentMap> mapsToRemove = ImmutableList.copyOf(mapsByApplication.get(appId)); + List<DefaultAsyncConsistentMap> mapsToRemove; + synchronized (mapsByApplication) { + mapsToRemove = ImmutableList.copyOf(mapsByApplication.get(appId)); + } mapsToRemove.forEach(DatabaseManager.this::unregisterMap); if (event.type() == APP_UNINSTALLED) { mapsToRemove.stream().filter(map -> map.purgeOnUninstall()).forEach(map -> map.clear()); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java index 95f9e39a..1d81f998 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java @@ -16,14 +16,14 @@ package org.onosproject.store.consistent.impl; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - /** * Database proxy. */ @@ -45,6 +45,7 @@ public interface DatabaseProxy<K, V> { /** * Returns the number of entries in map. + * * @param mapName map name * @return A completable future to be completed with the result once complete. */ @@ -62,7 +63,7 @@ public interface DatabaseProxy<K, V> { * Checks whether the map contains a key. * * @param mapName map name - * @param key key to check. + * @param key key to check. * @return A completable future to be completed with the result once complete. */ CompletableFuture<Boolean> mapContainsKey(String mapName, K key); @@ -71,7 +72,7 @@ public interface DatabaseProxy<K, V> { * Checks whether the map contains a value. * * @param mapName map name - * @param value The value to check. + * @param value The value to check. * @return A completable future to be completed with the result once complete. */ CompletableFuture<Boolean> mapContainsValue(String mapName, V value); @@ -80,7 +81,7 @@ public interface DatabaseProxy<K, V> { * Gets a value from the map. * * @param mapName map name - * @param key The key to get. + * @param key The key to get. * @return A completable future to be completed with the result once complete. */ CompletableFuture<Versioned<V>> mapGet(String mapName, K key); @@ -88,11 +89,11 @@ public interface DatabaseProxy<K, V> { /** * Updates the map. * - * @param mapName map name - * @param key The key to set - * @param valueMatch match for checking existing value - * @param versionMatch match for checking existing version - * @param value new value + * @param mapName map name + * @param key The key to set + * @param valueMatch match for checking existing value + * @param versionMatch match for checking existing version + * @param value new value * @return A completable future to be completed with the result once complete */ CompletableFuture<Result<UpdateResult<K, V>>> mapUpdate( @@ -130,11 +131,11 @@ public interface DatabaseProxy<K, V> { */ CompletableFuture<Set<Map.Entry<K, Versioned<V>>>> mapEntrySet(String mapName); - /** + /** * Atomically add the given value to current value of the specified counter. * * @param counterName counter name - * @param delta value to add + * @param delta value to add * @return updated value */ CompletableFuture<Long> counterAddAndGet(String counterName, long delta); @@ -143,11 +144,31 @@ public interface DatabaseProxy<K, V> { * Atomically add the given value to current value of the specified counter. * * @param counterName counter name - * @param delta value to add + * @param delta value to add * @return previous value */ CompletableFuture<Long> counterGetAndAdd(String counterName, long delta); + + /** + * Atomically sets the given value to current value of the specified counter. + * + * @param counterName counter name + * @param value value to set + * @return void future + */ + CompletableFuture<Void> counterSet(String counterName, long value); + + /** + * Atomically sets the given counter to the specified update value if and only if the current value is equal to the + * expected value. + * @param counterName counter name + * @param expectedValue value to use for equivalence check + * @param update value to set if expected value is current value + * @return true if an update occurred, false otherwise + */ + CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update); + /** * Returns the current value of the specified atomic counter. * @@ -158,6 +179,7 @@ public interface DatabaseProxy<K, V> { /** * Returns the size of queue. + * * @param queueName queue name * @return queue size */ @@ -165,14 +187,16 @@ public interface DatabaseProxy<K, V> { /** * Inserts an entry into the queue. + * * @param queueName queue name - * @param entry queue entry + * @param entry queue entry * @return void future */ CompletableFuture<Void> queuePush(String queueName, byte[] entry); /** * Removes an entry from the queue if the queue is non-empty. + * * @param queueName queue name * @return entry future. Can be completed with null if queue is empty */ @@ -180,6 +204,7 @@ public interface DatabaseProxy<K, V> { /** * Returns but does not remove an entry from the queue. + * * @param queueName queue name * @return entry. Can be null if queue is empty */ diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java index b3dd1c44..1136428b 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java @@ -16,18 +16,17 @@ package org.onosproject.store.consistent.impl; -import java.util.Collection; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - import net.kuujo.copycat.state.Command; import net.kuujo.copycat.state.Initializer; import net.kuujo.copycat.state.Query; import net.kuujo.copycat.state.StateContext; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; /** * Database state. @@ -83,6 +82,9 @@ public interface DatabaseState<K, V> { Long counterAddAndGet(String counterName, long delta); @Command + Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue); + + @Command Long counterGetAndAdd(String counterName, long delta); @Query diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java index 7a439c34..d851eaa0 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java @@ -18,6 +18,7 @@ package org.onosproject.store.consistent.impl; import org.onosproject.store.service.AsyncAtomicCounter; import java.util.concurrent.CompletableFuture; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -38,6 +39,8 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { private static final String GET_AND_ADD = "getAndAdd"; private static final String ADD_AND_GET = "addAndGet"; private static final String GET = "get"; + private static final String SET = "set"; + private static final String COMPARE_AND_SET = "compareAndSet"; public DefaultAsyncAtomicCounter(String name, Database database, @@ -72,13 +75,27 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { public CompletableFuture<Long> getAndAdd(long delta) { final MeteringAgent.Context timer = monitor.startTimer(GET_AND_ADD); return database.counterGetAndAdd(name, delta) - .whenComplete((r, e) -> timer.stop(e)); + .whenComplete((r, e) -> timer.stop(e)); } @Override public CompletableFuture<Long> addAndGet(long delta) { final MeteringAgent.Context timer = monitor.startTimer(ADD_AND_GET); return database.counterAddAndGet(name, delta) - .whenComplete((r, e) -> timer.stop(e)); + .whenComplete((r, e) -> timer.stop(e)); + } + + @Override + public CompletableFuture<Void> set(long value) { + final MeteringAgent.Context timer = monitor.startTimer(SET); + return database.counterSet(name, value) + .whenComplete((r, e) -> timer.stop(e)); + } + + @Override + public CompletableFuture<Boolean> compareAndSet(long expectedValue, long updateValue) { + final MeteringAgent.Context timer = monitor.startTimer(COMPARE_AND_SET); + return database.counterCompareAndSet(name, expectedValue, updateValue) + .whenComplete((r, e) -> timer.stop(e)); } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java index 64886e41..2d6a956c 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java @@ -63,6 +63,16 @@ public class DefaultAtomicCounter implements AtomicCounter { } @Override + public void set(long value) { + complete(asyncCounter.set(value)); + } + + @Override + public boolean compareAndSet(long expectedValue, long updateValue) { + return complete(asyncCounter.compareAndSet(expectedValue, updateValue)); + } + + @Override public long get() { return complete(asyncCounter.get()); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java index 4d9776ee..2a50fbd6 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java @@ -16,12 +16,15 @@ package org.onosproject.store.consistent.impl; -import net.kuujo.copycat.state.StateMachine; +import com.google.common.collect.Sets; import net.kuujo.copycat.resource.internal.AbstractResource; import net.kuujo.copycat.resource.internal.ResourceManager; +import net.kuujo.copycat.state.StateMachine; import net.kuujo.copycat.state.internal.DefaultStateMachine; import net.kuujo.copycat.util.concurrent.Futures; import net.kuujo.copycat.util.function.TriConsumer; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; import java.util.Collection; import java.util.Map; @@ -30,11 +33,6 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Supplier; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - -import com.google.common.collect.Sets; - /** * Default database. */ @@ -44,7 +42,7 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab private final Set<Consumer<StateMachineUpdate>> consumers = Sets.newCopyOnWriteArraySet(); private final TriConsumer<String, Object, Object> watcher = new InternalStateMachineWatcher(); - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) public DefaultDatabase(ResourceManager context) { super(context); this.stateMachine = new DefaultStateMachine(context, @@ -66,7 +64,7 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab * return the completed future result. * * @param supplier The supplier to call if the database is open. - * @param <T> The future result type. + * @param <T> The future result type. * @return A completable future that if this database is closed is immediately failed. */ protected <T> CompletableFuture<T> checkOpen(Supplier<CompletableFuture<T>> supplier) { @@ -153,6 +151,16 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab } @Override + public CompletableFuture<Void> counterSet(String counterName, long value) { + return checkOpen(() -> proxy.counterSet(counterName, value)); + } + + @Override + public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update) { + return checkOpen(() -> proxy.counterCompareAndSet(counterName, expectedValue, update)); + } + + @Override public CompletableFuture<Long> queueSize(String queueName) { return checkOpen(() -> proxy.queueSize(queueName)); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java index 9a55ffb1..8943fc87 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java @@ -16,27 +16,26 @@ package org.onosproject.store.consistent.impl; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import net.kuujo.copycat.state.Initializer; +import net.kuujo.copycat.state.StateContext; +import org.onosproject.store.service.DatabaseUpdate; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; -import java.util.Set; - -import org.onosproject.store.service.DatabaseUpdate; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import net.kuujo.copycat.state.Initializer; -import net.kuujo.copycat.state.StateContext; /** * Default database state. @@ -195,6 +194,11 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { } @Override + public Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue) { + return getCounter(counterName).compareAndSet(expectedValue, updateValue); + } + + @Override public Long counterGet(String counterName) { return getCounter(counterName).get(); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java new file mode 100644 index 00000000..d8593e37 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java @@ -0,0 +1,315 @@ +/* + * 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.store.consistent.impl; + +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +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.apache.felix.scr.annotations.Service; +import org.onlab.util.Tools; +import org.onosproject.cluster.ClusterEvent; +import org.onosproject.cluster.ClusterEventListener; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode.State; +import org.onosproject.cluster.NodeId; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.ConsistentMapException; +import org.onosproject.store.service.MapEvent; +import org.onosproject.store.service.MapEventListener; +import org.onosproject.store.service.MutexExecutionService; +import org.onosproject.store.service.MutexTask; +import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +/** + * Implementation of a MutexExecutionService. + */ +@Component(immediate = true) +@Service +public class MutexExecutionManager implements MutexExecutionService { + + private final Logger log = getLogger(getClass()); + + protected ConsistentMap<String, MutexState> lockMap; + protected NodeId localNodeId; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + private final MapEventListener<String, MutexState> mapEventListener = new InternalLockMapEventListener(); + private final ClusterEventListener clusterEventListener = new InternalClusterEventListener(); + + private Map<String, CompletableFuture<MutexState>> pending = Maps.newConcurrentMap(); + private Map<String, InnerMutexTask> activeTasks = Maps.newConcurrentMap(); + + @Activate + public void activate() { + localNodeId = clusterService.getLocalNode().id(); + lockMap = storageService.<String, MutexState>consistentMapBuilder() + .withName("onos-mutexes") + .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API), MutexState.class)) + .withPartitionsDisabled() + .build(); + lockMap.addListener(mapEventListener); + clusterService.addListener(clusterEventListener); + releaseOldLocks(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + lockMap.removeListener(mapEventListener); + pending.values().forEach(future -> future.cancel(true)); + activeTasks.forEach((k, v) -> { + v.stop(); + unlock(k); + }); + clusterService.removeListener(clusterEventListener); + log.info("Stopped"); + } + + @Override + public CompletableFuture<Void> execute(MutexTask task, String exclusionPath, Executor executor) { + return lock(exclusionPath) + .thenApply(state -> activeTasks.computeIfAbsent(exclusionPath, + k -> new InnerMutexTask(exclusionPath, + task, + state.term()))) + .thenAcceptAsync(t -> t.start(), executor) + .whenComplete((r, e) -> unlock(exclusionPath)); + } + + protected CompletableFuture<MutexState> lock(String exclusionPath) { + CompletableFuture<MutexState> future = + pending.computeIfAbsent(exclusionPath, k -> new CompletableFuture<>()); + tryLock(exclusionPath); + return future; + } + + /** + * Attempts to acquire lock for a path. If lock is held by some other node, adds this node to + * the wait list. + * @param exclusionPath exclusion path + */ + protected void tryLock(String exclusionPath) { + Tools.retryable(() -> lockMap.asJavaMap() + .compute(exclusionPath, + (k, v) -> MutexState.admit(v, localNodeId)), + ConsistentMapException.ConcurrentModification.class, + Integer.MAX_VALUE, + 100).get(); + } + + /** + * Releases lock for the specific path. This operation is idempotent. + * @param exclusionPath exclusion path + */ + protected void unlock(String exclusionPath) { + Tools.retryable(() -> lockMap.asJavaMap() + .compute(exclusionPath, (k, v) -> MutexState.evict(v, localNodeId)), + ConsistentMapException.ConcurrentModification.class, + Integer.MAX_VALUE, + 100).get(); + } + + /** + * Detects and releases all locks held by this node. + */ + private void releaseOldLocks() { + Maps.filterValues(lockMap.asJavaMap(), state -> localNodeId.equals(state.holder())) + .keySet() + .forEach(path -> { + log.info("Detected zombie task still holding lock for {}. Releasing lock.", path); + unlock(path); + }); + } + + private class InternalLockMapEventListener implements MapEventListener<String, MutexState> { + + @Override + public void event(MapEvent<String, MutexState> event) { + log.debug("Received {}", event); + if (event.type() == MapEvent.Type.UPDATE || event.type() == MapEvent.Type.INSERT) { + pending.computeIfPresent(event.key(), (k, future) -> { + MutexState state = Versioned.valueOrElse(event.value(), null); + if (state != null && localNodeId.equals(state.holder())) { + log.debug("Local node is now owner for {}", event.key()); + future.complete(state); + return null; + } else { + return future; + } + }); + InnerMutexTask task = activeTasks.get(event.key()); + if (task != null && task.term() < Versioned.valueOrElse(event.value(), null).term()) { + task.stop(); + } + } + } + } + + private class InternalClusterEventListener implements ClusterEventListener { + + @Override + public void event(ClusterEvent event) { + if (event.type() == ClusterEvent.Type.INSTANCE_DEACTIVATED || + event.type() == ClusterEvent.Type.INSTANCE_REMOVED) { + NodeId nodeId = event.subject().id(); + log.debug("{} is no longer active. Attemping to clean up its locks.", nodeId); + lockMap.asJavaMap().forEach((k, v) -> { + if (v.contains(nodeId)) { + lockMap.compute(k, (path, state) -> MutexState.evict(v, nodeId)); + } + }); + } + long activeNodes = clusterService.getNodes() + .stream() + .map(node -> clusterService.getState(node.id())) + .filter(State.ACTIVE::equals) + .count(); + if (clusterService.getNodes().size() > 1 && activeNodes == 1) { + log.info("This node is partitioned away from the cluster. Stopping all inflight executions"); + activeTasks.forEach((k, v) -> { + v.stop(); + }); + } + } + } + + private static final class MutexState { + + private final NodeId holder; + private final List<NodeId> waitList; + private final long term; + + public static MutexState admit(MutexState state, NodeId nodeId) { + if (state == null) { + return new MutexState(nodeId, 1L, Lists.newArrayList()); + } else if (state.holder() == null) { + return new MutexState(nodeId, state.term() + 1, Lists.newArrayList()); + } else { + if (!state.contains(nodeId)) { + NodeId newHolder = state.holder(); + List<NodeId> newWaitList = Lists.newArrayList(state.waitList()); + newWaitList.add(nodeId); + return new MutexState(newHolder, state.term(), newWaitList); + } else { + return state; + } + } + } + + public static MutexState evict(MutexState state, NodeId nodeId) { + return state.evict(nodeId); + } + + public MutexState evict(NodeId nodeId) { + if (nodeId.equals(holder)) { + if (waitList.isEmpty()) { + return new MutexState(null, term, waitList); + } + List<NodeId> newWaitList = Lists.newArrayList(waitList); + NodeId newHolder = newWaitList.remove(0); + return new MutexState(newHolder, term + 1, newWaitList); + } else { + NodeId newHolder = holder; + List<NodeId> newWaitList = Lists.newArrayList(waitList); + newWaitList.remove(nodeId); + return new MutexState(newHolder, term, newWaitList); + } + } + + public NodeId holder() { + return holder; + } + + public List<NodeId> waitList() { + return waitList; + } + + public long term() { + return term; + } + + private boolean contains(NodeId nodeId) { + return (nodeId.equals(holder) || waitList.contains(nodeId)); + } + + private MutexState(NodeId holder, long term, List<NodeId> waitList) { + this.holder = holder; + this.term = term; + this.waitList = Lists.newArrayList(waitList); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("holder", holder) + .add("term", term) + .add("waitList", waitList) + .toString(); + } + } + + private class InnerMutexTask implements MutexTask { + private final MutexTask task; + private final String mutexPath; + private final long term; + + public InnerMutexTask(String mutexPath, MutexTask task, long term) { + this.mutexPath = mutexPath; + this.term = term; + this.task = task; + } + + public long term() { + return term; + } + + @Override + public void start() { + log.debug("Starting execution for mutex task guarded by {}", mutexPath); + task.start(); + log.debug("Finished execution for mutex task guarded by {}", mutexPath); + } + + @Override + public void stop() { + log.debug("Stopping execution for mutex task guarded by {}", mutexPath); + task.stop(); + } + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java index a294681e..f741b367 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java @@ -16,6 +16,17 @@ package org.onosproject.store.consistent.impl; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import net.kuujo.copycat.Task; +import net.kuujo.copycat.cluster.Cluster; +import net.kuujo.copycat.resource.ResourceState; +import org.onosproject.store.service.DatabaseUpdate; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + import java.util.Collection; import java.util.List; import java.util.Map; @@ -28,18 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; -import org.onosproject.store.service.DatabaseUpdate; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import net.kuujo.copycat.Task; -import net.kuujo.copycat.cluster.Cluster; -import net.kuujo.copycat.resource.ResourceState; import static com.google.common.base.Preconditions.checkState; /** @@ -100,10 +99,10 @@ public class PartitionedDatabase implements Database { return CompletableFuture.allOf(partitions .stream() .map(db -> db.counters() - .thenApply(m -> { - counters.putAll(m); - return null; - })) + .thenApply(m -> { + counters.putAll(m); + return null; + })) .toArray(CompletableFuture[]::new)) .thenApply(v -> counters); } @@ -113,9 +112,9 @@ public class PartitionedDatabase implements Database { checkState(isOpen.get(), DB_NOT_OPEN); AtomicInteger totalSize = new AtomicInteger(0); return CompletableFuture.allOf(partitions - .stream() - .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet)) - .toArray(CompletableFuture[]::new)) + .stream() + .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet)) + .toArray(CompletableFuture[]::new)) .thenApply(v -> totalSize.get()); } @@ -136,10 +135,10 @@ public class PartitionedDatabase implements Database { checkState(isOpen.get(), DB_NOT_OPEN); AtomicBoolean containsValue = new AtomicBoolean(false); return CompletableFuture.allOf(partitions - .stream() - .map(p -> p.mapContainsValue(mapName, value) - .thenApply(v -> containsValue.compareAndSet(false, v))) - .toArray(CompletableFuture[]::new)) + .stream() + .map(p -> p.mapContainsValue(mapName, value) + .thenApply(v -> containsValue.compareAndSet(false, v))) + .toArray(CompletableFuture[]::new)) .thenApply(v -> containsValue.get()); } @@ -196,9 +195,9 @@ public class PartitionedDatabase implements Database { checkState(isOpen.get(), DB_NOT_OPEN); Set<Entry<String, Versioned<byte[]>>> entrySet = Sets.newConcurrentHashSet(); return CompletableFuture.allOf(partitions - .stream() - .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll)) - .toArray(CompletableFuture[]::new)) + .stream() + .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll)) + .toArray(CompletableFuture[]::new)) .thenApply(v -> entrySet); } @@ -220,6 +219,19 @@ public class PartitionedDatabase implements Database { return partitioner.getPartition(counterName, counterName).counterGetAndAdd(counterName, delta); } + @Override + public CompletableFuture<Void> counterSet(String counterName, long value) { + checkState(isOpen.get(), DB_NOT_OPEN); + return partitioner.getPartition(counterName, counterName).counterSet(counterName, value); + } + + @Override + public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long updateValue) { + checkState(isOpen.get(), DB_NOT_OPEN); + return partitioner.getPartition(counterName, counterName). + counterCompareAndSet(counterName, expectedValue, updateValue); + + } @Override public CompletableFuture<Long> queueSize(String queueName) { @@ -268,8 +280,8 @@ public class PartitionedDatabase implements Database { AtomicBoolean status = new AtomicBoolean(true); return CompletableFuture.allOf(subTransactions.entrySet() .stream() - .map(entry -> entry - .getKey() + .map(entry -> entry + .getKey() .prepare(entry.getValue()) .thenApply(v -> status.compareAndSet(true, v))) .toArray(CompletableFuture[]::new)) @@ -282,15 +294,15 @@ public class PartitionedDatabase implements Database { AtomicBoolean success = new AtomicBoolean(true); List<UpdateResult<String, byte[]>> allUpdates = Lists.newArrayList(); return CompletableFuture.allOf(subTransactions.entrySet() - .stream() - .map(entry -> entry.getKey().commit(entry.getValue()) - .thenAccept(response -> { - success.set(success.get() && response.success()); - if (success.get()) { - allUpdates.addAll(response.updates()); - } - })) - .toArray(CompletableFuture[]::new)) + .stream() + .map(entry -> entry.getKey().commit(entry.getValue()) + .thenAccept(response -> { + success.set(success.get() && response.success()); + if (success.get()) { + allUpdates.addAll(response.updates()); + } + })) + .toArray(CompletableFuture[]::new)) .thenApply(v -> success.get() ? CommitResponse.success(allUpdates) : CommitResponse.failure()); } @@ -301,7 +313,7 @@ public class PartitionedDatabase implements Database { return CompletableFuture.allOf(subTransactions.entrySet() .stream() .map(entry -> entry.getKey().rollback(entry.getValue())) - .toArray(CompletableFuture[]::new)) + .toArray(CompletableFuture[]::new)) .thenApply(v -> true); } @@ -384,3 +396,4 @@ public class PartitionedDatabase implements Database { partitions.forEach(p -> p.unregisterConsumer(consumer)); } } + diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java index 2859b62f..f1e0dbd4 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java @@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; - import org.apache.commons.lang3.tuple.Pair; import org.onlab.util.AbstractAccumulator; import org.onlab.util.KryoNamespace; @@ -33,18 +32,15 @@ import org.onosproject.store.Timestamp; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.cluster.messaging.MessageSubject; import org.onosproject.store.impl.LogicalTimestamp; -import org.onosproject.store.service.WallClockTimestamp; import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.serializers.KryoSerializer; import org.onosproject.store.service.EventuallyConsistentMap; import org.onosproject.store.service.EventuallyConsistentMapEvent; import org.onosproject.store.service.EventuallyConsistentMapListener; +import org.onosproject.store.service.WallClockTimestamp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; -import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; - import java.util.Collection; import java.util.Collections; import java.util.List; @@ -67,6 +63,8 @@ import static com.google.common.base.Preconditions.checkState; import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; import static org.onlab.util.BoundedThreadPool.newFixedThreadPool; import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; /** * Distributed Map implementation which uses optimistic replication and gossip @@ -359,7 +357,7 @@ public class EventuallyConsistentMapImpl<K, V> valueMatches = Objects.equals(value.get(), existing.get()); } if (existing == null) { - log.debug("ECMap Remove: Existing value for key {} is already null", k); + log.trace("ECMap Remove: Existing value for key {} is already null", k); } if (valueMatches) { if (existing == null) { @@ -523,7 +521,7 @@ public class EventuallyConsistentMapImpl<K, V> return; } peers.forEach(node -> - senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event) + senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event) ); } @@ -576,8 +574,10 @@ public class EventuallyConsistentMapImpl<K, V> return; } try { - log.debug("Received anti-entropy advertisement from {} for {} with {} entries in it", - mapName, ad.sender(), ad.digest().size()); + if (log.isTraceEnabled()) { + log.trace("Received anti-entropy advertisement from {} for {} with {} entries in it", + mapName, ad.sender(), ad.digest().size()); + } antiEntropyCheckLocalItems(ad).forEach(this::notifyListeners); if (!lightweightAntiEntropy) { @@ -675,4 +675,4 @@ public class EventuallyConsistentMapImpl<K, V> }); } } -}
\ No newline at end of file +} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java index de7a3ac3..8cd63e7d 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java @@ -16,6 +16,7 @@ package org.onosproject.store.flow.impl; import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; @@ -57,6 +58,7 @@ import org.onosproject.net.flow.FlowRuleService; import org.onosproject.net.flow.FlowRuleStore; import org.onosproject.net.flow.FlowRuleStoreDelegate; import org.onosproject.net.flow.StoredFlowEntry; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.store.AbstractStore; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.cluster.messaging.ClusterMessage; @@ -64,9 +66,16 @@ import org.onosproject.store.cluster.messaging.ClusterMessageHandler; import org.onosproject.store.flow.ReplicaInfoEvent; import org.onosproject.store.flow.ReplicaInfoEventListener; import org.onosproject.store.flow.ReplicaInfoService; +import org.onosproject.store.impl.MastershipBasedTimestamp; +import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.serializers.KryoSerializer; import org.onosproject.store.serializers.StoreSerializer; import org.onosproject.store.serializers.custom.DistributedStoreSerializers; +import org.onosproject.store.service.EventuallyConsistentMap; +import org.onosproject.store.service.EventuallyConsistentMapEvent; +import org.onosproject.store.service.EventuallyConsistentMapListener; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.WallClockTimestamp; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; @@ -151,6 +160,13 @@ public class NewDistributedFlowRuleStore private final ScheduledExecutorService backupSenderExecutor = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/flow", "backup-sender")); + private EventuallyConsistentMap<DeviceId, List<TableStatisticsEntry>> deviceTableStats; + private final EventuallyConsistentMapListener<DeviceId, List<TableStatisticsEntry>> tableStatsListener = + new InternalTableStatsListener(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + protected static final StoreSerializer SERIALIZER = new KryoSerializer() { @Override protected void setupKryoPool() { @@ -161,6 +177,11 @@ public class NewDistributedFlowRuleStore } }; + protected static final KryoNamespace.Builder SERIALIZER_BUILDER = KryoNamespace.newBuilder() + .register(KryoNamespaces.API) + .register(MastershipBasedTimestamp.class); + + private IdGenerator idGenerator; private NodeId local; @@ -186,6 +207,15 @@ public class NewDistributedFlowRuleStore TimeUnit.MILLISECONDS); } + deviceTableStats = storageService.<DeviceId, List<TableStatisticsEntry>>eventuallyConsistentMapBuilder() + .withName("onos-flow-table-stats") + .withSerializer(SERIALIZER_BUILDER) + .withAntiEntropyPeriod(5, TimeUnit.SECONDS) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .withTombstonesDisabled() + .build(); + deviceTableStats.addListener(tableStatsListener); + logConfig("Started"); } @@ -197,6 +227,8 @@ public class NewDistributedFlowRuleStore } configService.unregisterProperties(getClass(), false); unregisterMessageHandlers(); + deviceTableStats.removeListener(tableStatsListener); + deviceTableStats.destroy(); messageHandlingExecutor.shutdownNow(); backupSenderExecutor.shutdownNow(); log.info("Stopped"); @@ -786,4 +818,36 @@ public class NewDistributedFlowRuleStore return backedupDevices; } } + + @Override + public FlowRuleEvent updateTableStatistics(DeviceId deviceId, + List<TableStatisticsEntry> tableStats) { + deviceTableStats.put(deviceId, tableStats); + return null; + } + + @Override + public Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId) { + NodeId master = mastershipService.getMasterFor(deviceId); + + if (master == null) { + log.debug("Failed to getTableStats: No master for {}", deviceId); + return Collections.emptyList(); + } + + List<TableStatisticsEntry> tableStats = deviceTableStats.get(deviceId); + if (tableStats == null) { + return Collections.emptyList(); + } + return ImmutableList.copyOf(tableStats); + } + + private class InternalTableStatsListener + implements EventuallyConsistentMapListener<DeviceId, List<TableStatisticsEntry>> { + @Override + public void event(EventuallyConsistentMapEvent<DeviceId, + List<TableStatisticsEntry>> event) { + //TODO: Generate an event to listeners (do we need?) + } + } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java index 97333ebf..a999ee7f 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java @@ -28,19 +28,11 @@ import org.apache.felix.scr.annotations.Service; import org.onlab.util.KryoNamespace; import org.onlab.util.NewConcurrentHashMap; import org.onosproject.cluster.ClusterService; -import org.onosproject.core.DefaultApplicationId; import org.onosproject.core.DefaultGroupId; import org.onosproject.core.GroupId; import org.onosproject.mastership.MastershipService; import org.onosproject.net.DeviceId; import org.onosproject.net.MastershipRole; -import org.onosproject.net.PortNumber; -import org.onosproject.net.flow.DefaultTrafficTreatment; -import org.onosproject.net.flow.FlowRule; -import org.onosproject.net.flow.instructions.Instructions; -import org.onosproject.net.flow.instructions.L0ModificationInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction; -import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.group.DefaultGroup; import org.onosproject.net.group.DefaultGroupBucket; import org.onosproject.net.group.DefaultGroupDescription; @@ -61,9 +53,7 @@ import org.onosproject.net.group.StoredGroupEntry; import org.onosproject.store.AbstractStore; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.service.MultiValuedTimestamp; -import org.onosproject.store.serializers.DeviceIdSerializer; import org.onosproject.store.serializers.KryoNamespaces; -import org.onosproject.store.serializers.URISerializer; import org.onosproject.store.service.EventuallyConsistentMap; import org.onosproject.store.service.EventuallyConsistentMapBuilder; import org.onosproject.store.service.EventuallyConsistentMapEvent; @@ -71,7 +61,6 @@ import org.onosproject.store.service.EventuallyConsistentMapListener; import org.onosproject.store.service.StorageService; import org.slf4j.Logger; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -139,9 +128,12 @@ public class DistributedGroupStore private final AtomicLong sequenceNumber = new AtomicLong(0); + private KryoNamespace clusterMsgSerializer; + @Activate public void activate() { kryoBuilder = new KryoNamespace.Builder() + .register(KryoNamespaces.API) .register(DefaultGroup.class, DefaultGroupBucket.class, DefaultGroupDescription.class, @@ -158,38 +150,9 @@ public class DistributedGroupStore GroupStoreKeyMapKey.class, GroupStoreIdMapKey.class, GroupStoreMapKey.class - ) - .register(new URISerializer(), URI.class) - .register(new DeviceIdSerializer(), DeviceId.class) - .register(PortNumber.class) - .register(DefaultApplicationId.class) - .register(DefaultTrafficTreatment.class, - Instructions.DropInstruction.class, - Instructions.OutputInstruction.class, - Instructions.GroupInstruction.class, - Instructions.TableTypeTransition.class, - FlowRule.Type.class, - L0ModificationInstruction.class, - L0ModificationInstruction.L0SubType.class, - L0ModificationInstruction.ModLambdaInstruction.class, - L2ModificationInstruction.class, - L2ModificationInstruction.L2SubType.class, - L2ModificationInstruction.ModEtherInstruction.class, - L2ModificationInstruction.PushHeaderInstructions.class, - L2ModificationInstruction.ModVlanIdInstruction.class, - L2ModificationInstruction.ModVlanPcpInstruction.class, - L2ModificationInstruction.ModMplsLabelInstruction.class, - L2ModificationInstruction.ModMplsTtlInstruction.class, - L3ModificationInstruction.class, - L3ModificationInstruction.L3SubType.class, - L3ModificationInstruction.ModIPInstruction.class, - L3ModificationInstruction.ModIPv6FlowLabelInstruction.class, - L3ModificationInstruction.ModTtlInstruction.class, - org.onlab.packet.MplsLabel.class - ) - .register(org.onosproject.cluster.NodeId.class) - .register(KryoNamespaces.BASIC) - .register(KryoNamespaces.MISC); + ); + + clusterMsgSerializer = kryoBuilder.build(); messageHandlingExecutor = Executors. newFixedThreadPool(MESSAGE_HANDLER_THREAD_POOL_SIZE, @@ -197,7 +160,7 @@ public class DistributedGroupStore "message-handlers")); clusterCommunicator.addSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - kryoBuilder.build()::deserialize, + clusterMsgSerializer::deserialize, this::process, messageHandlingExecutor); @@ -233,6 +196,7 @@ public class DistributedGroupStore @Deactivate public void deactivate() { + clusterCommunicator.removeSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST); groupStoreEntriesByKey.destroy(); auditPendingReqQueue.destroy(); log.info("Stopped"); @@ -313,8 +277,6 @@ public class DistributedGroupStore @Override public Iterable<Group> getGroups(DeviceId deviceId) { // flatten and make iterator unmodifiable - log.debug("getGroups: for device {} total number of groups {}", - deviceId, getGroupStoreKeyMap().values().size()); return FluentIterable.from(getGroupStoreKeyMap().values()) .filter(input -> input.deviceId().equals(deviceId)) .transform(input -> input); @@ -322,8 +284,6 @@ public class DistributedGroupStore private Iterable<StoredGroupEntry> getStoredGroups(DeviceId deviceId) { // flatten and make iterator unmodifiable - log.debug("getGroups: for device {} total number of groups {}", - deviceId, getGroupStoreKeyMap().values().size()); return FluentIterable.from(getGroupStoreKeyMap().values()) .filter(input -> input.deviceId().equals(deviceId)); } @@ -411,7 +371,7 @@ public class DistributedGroupStore clusterCommunicator.unicast(groupOp, GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - m -> kryoBuilder.build().serialize(m), + clusterMsgSerializer::serialize, mastershipService.getMasterFor(groupDesc.deviceId())).whenComplete((result, error) -> { if (error != null) { log.warn("Failed to send request to master: {} to {}", @@ -609,7 +569,7 @@ public class DistributedGroupStore clusterCommunicator.unicast(groupOp, GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - m -> kryoBuilder.build().serialize(m), + clusterMsgSerializer::serialize, mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> { if (error != null) { log.warn("Failed to send request to master: {} to {}", @@ -741,7 +701,7 @@ public class DistributedGroupStore clusterCommunicator.unicast(groupOp, GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - m -> kryoBuilder.build().serialize(m), + clusterMsgSerializer::serialize, mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> { if (error != null) { log.warn("Failed to send request to master: {} to {}", diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java index d0b827cd..f9c96891 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java @@ -27,6 +27,7 @@ import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.RE import static org.slf4j.LoggerFactory.getLogger; import java.util.Collection; +import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -67,7 +68,6 @@ import org.onosproject.store.service.StorageService; import org.slf4j.Logger; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; @@ -197,6 +197,35 @@ public class ECHostStore } @Override + public HostEvent removeIp(HostId hostId, IpAddress ipAddress) { + DefaultHost host = hosts.compute(hostId, (id, existingHost) -> { + if (existingHost != null) { + checkState(Objects.equals(hostId.mac(), existingHost.mac()), + "Existing and new MAC addresses differ."); + checkState(Objects.equals(hostId.vlanId(), existingHost.vlan()), + "Existing and new VLANs differ."); + + Set<IpAddress> addresses = existingHost.ipAddresses(); + if (addresses != null && addresses.contains(ipAddress)) { + addresses = new HashSet<>(existingHost.ipAddresses()); + addresses.remove(ipAddress); + return new DefaultHost(existingHost.providerId(), + hostId, + existingHost.mac(), + existingHost.vlan(), + existingHost.location(), + ImmutableSet.copyOf(addresses), + existingHost.annotations()); + } else { + return existingHost; + } + } + return null; + }); + return host != null ? new HostEvent(HOST_UPDATED, host) : null; + } + + @Override public int getHostCount() { return hosts.size(); } @@ -228,17 +257,23 @@ public class ECHostStore @Override public Set<Host> getConnectedHosts(ConnectPoint connectPoint) { - return ImmutableSet.copyOf(locations.get(connectPoint)); + synchronized (locations) { + return ImmutableSet.copyOf(locations.get(connectPoint)); + } } @Override public Set<Host> getConnectedHosts(DeviceId deviceId) { - return ImmutableMultimap.copyOf(locations) - .entries() - .stream() - .filter(entry -> entry.getKey().deviceId().equals(deviceId)) - .map(entry -> entry.getValue()) - .collect(Collectors.toSet()); + Set<Host> filtered; + synchronized (locations) { + filtered = locations + .entries() + .stream() + .filter(entry -> entry.getKey().deviceId().equals(deviceId)) + .map(entry -> entry.getValue()) + .collect(Collectors.toSet()); + } + return ImmutableSet.copyOf(filtered); } private Set<Host> filter(Collection<DefaultHost> collection, Predicate<DefaultHost> predicate) { diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java index fa3a0751..1e5db99c 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java @@ -193,7 +193,7 @@ public class GossipIntentStore private Collection<NodeId> getPeerNodes(Key key, IntentData data) { NodeId master = partitionService.getLeader(key); NodeId origin = (data != null) ? data.origin() : null; - if (master == null || origin == null) { + if (data != null && (master == null || origin == null)) { log.debug("Intent {} missing master and/or origin; master = {}, origin = {}", key, master, origin); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java index 105c77df..47aa85c5 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java @@ -826,7 +826,7 @@ public class GossipLinkStore public void handle(ClusterMessage message) { log.trace("Received link event from peer: {}", message.sender()); - InternalLinkEvent event = (InternalLinkEvent) SERIALIZER.decode(message.payload()); + InternalLinkEvent event = SERIALIZER.decode(message.payload()); ProviderId providerId = event.providerId(); Timestamped<LinkDescription> linkDescription = event.linkDescription(); @@ -845,7 +845,7 @@ public class GossipLinkStore public void handle(ClusterMessage message) { log.trace("Received link removed event from peer: {}", message.sender()); - InternalLinkRemovedEvent event = (InternalLinkRemovedEvent) SERIALIZER.decode(message.payload()); + InternalLinkRemovedEvent event = SERIALIZER.decode(message.payload()); LinkKey linkKey = event.linkKey(); Timestamp timestamp = event.timestamp(); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java index d4c89c93..f0f3eb5e 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java @@ -15,7 +15,9 @@ */ package org.onosproject.store.packet.impl; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -41,14 +43,13 @@ import org.onosproject.store.serializers.KryoSerializer; import org.onosproject.store.service.ConsistentMap; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import org.onosproject.store.service.Versioned; import org.slf4j.Logger; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; import static org.onlab.util.Tools.groupedThreads; import static org.slf4j.LoggerFactory.getLogger; @@ -117,6 +118,7 @@ public class DistributedPacketStore public void deactivate() { communicationService.removeSubscriber(PACKET_OUT_SUBJECT); messageHandlingExecutor.shutdown(); + tracker = null; log.info("Stopped"); } @@ -143,13 +145,13 @@ public class DistributedPacketStore } @Override - public boolean requestPackets(PacketRequest request) { - return tracker.add(request); + public void requestPackets(PacketRequest request) { + tracker.add(request); } @Override - public boolean cancelPackets(PacketRequest request) { - return tracker.remove(request); + public void cancelPackets(PacketRequest request) { + tracker.remove(request); } @Override @@ -169,33 +171,50 @@ public class DistributedPacketStore .build(); } - public boolean add(PacketRequest request) { - Versioned<Set<PacketRequest>> old = requests.get(request.selector()); - if (old != null && old.value().contains(request)) { - return false; + public void add(PacketRequest request) { + AtomicBoolean firstRequest = new AtomicBoolean(false); + requests.compute(request.selector(), (s, existingRequests) -> { + if (existingRequests == null) { + firstRequest.set(true); + return ImmutableSet.of(request); + } else if (!existingRequests.contains(request)) { + return ImmutableSet.<PacketRequest>builder() + .addAll(existingRequests) + .add(request) + .build(); + } else { + return existingRequests; + } + }); + + if (firstRequest.get() && delegate != null) { + // The instance that makes the first request will push to all devices + delegate.requestPackets(request); } - // FIXME: add retry logic using a random delay - Set<PacketRequest> newSet = new HashSet<>(); - newSet.add(request); - if (old == null) { - return requests.putIfAbsent(request.selector(), newSet) == null; - } - newSet.addAll(old.value()); - return requests.replace(request.selector(), old.version(), newSet); } - public boolean remove(PacketRequest request) { - Versioned<Set<PacketRequest>> old = requests.get(request.selector()); - if (old == null || !old.value().contains(request)) { - return false; - } - // FIXME: add retry logic using a random delay - Set<PacketRequest> newSet = new HashSet<>(old.value()); - newSet.remove(request); - if (newSet.isEmpty()) { - return requests.remove(request.selector(), old.version()); + public void remove(PacketRequest request) { + AtomicBoolean removedLast = new AtomicBoolean(false); + requests.computeIfPresent(request.selector(), (s, existingRequests) -> { + if (existingRequests.contains(request)) { + Set<PacketRequest> newRequests = Sets.newHashSet(existingRequests); + newRequests.remove(request); + if (newRequests.size() > 0) { + return ImmutableSet.copyOf(newRequests); + } else { + removedLast.set(true); + return null; + } + } else { + return existingRequests; + } + }); + + if (removedLast.get() && delegate != null) { + // The instance that removes the last request will remove from all devices + delegate.cancelPackets(request); } - return requests.replace(request.selector(), old.version(), newSet); + } public List<PacketRequest> requests() { @@ -204,6 +223,5 @@ public class DistributedPacketStore list.sort((o1, o2) -> o1.priority().priorityValue() - o2.priority().priorityValue()); return list; } - } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java new file mode 100644 index 00000000..87e67215 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java @@ -0,0 +1,111 @@ +/* + * 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.store.resource.impl; + +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.apache.felix.scr.annotations.Service; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.device.IntentSetMultimap; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +import java.util.HashSet; +import java.util.Set; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * A collection that maps Intent IDs as keys to values as Intent IDs, + * where each key may associated with multiple values without duplication. + */ +@Component(immediate = true, enabled = true) +@Service +public class ConsistentIntentSetMultimap implements IntentSetMultimap { + private final Logger log = getLogger(getClass()); + + private static final String INTENT_MAPPING = "IntentMapping"; + + private static final Serializer SERIALIZER = Serializer.using(KryoNamespaces.API); + + private ConsistentMap<IntentId, Set<IntentId>> intentMapping; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Activate + public void activate() { + intentMapping = storageService.<IntentId, Set<IntentId>>consistentMapBuilder() + .withName(INTENT_MAPPING) + .withSerializer(SERIALIZER) + .build(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public Set<IntentId> getMapping(IntentId intentId) { + Versioned<Set<IntentId>> result = intentMapping.get(intentId); + + if (result != null) { + return result.value(); + } + + return null; + } + + @Override + public boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId) { + Versioned<Set<IntentId>> versionedIntents = intentMapping.get(keyIntentId); + + if (versionedIntents == null) { + Set<IntentId> newSet = new HashSet<>(); + newSet.add(valIntentId); + intentMapping.put(keyIntentId, newSet); + } else { + versionedIntents.value().add(valIntentId); + } + + return true; + } + + @Override + public void releaseMapping(IntentId intentId) { + for (IntentId intent : intentMapping.keySet()) { + // TODO: optimize by checking for identical src & dst + Set<IntentId> mapping = intentMapping.get(intent).value(); + if (mapping.remove(intentId)) { + return; + } + } + } + +} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java index 3a296353..11137aa2 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java @@ -40,7 +40,6 @@ import org.onosproject.net.Link; import org.onosproject.net.LinkKey; import org.onosproject.net.Port; import org.onosproject.net.intent.IntentId; -import org.onosproject.net.link.LinkService; import org.onosproject.net.resource.link.BandwidthResource; import org.onosproject.net.resource.link.BandwidthResourceAllocation; import org.onosproject.net.resource.link.LambdaResource; @@ -69,7 +68,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; import static org.slf4j.LoggerFactory.getLogger; import static org.onosproject.net.AnnotationKeys.BANDWIDTH; @@ -108,9 +106,6 @@ public class ConsistentLinkResourceStore extends protected StorageService storageService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkService linkService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected DeviceService deviceService; @Activate @@ -139,29 +134,30 @@ public class ConsistentLinkResourceStore extends return storageService.transactionContextBuilder().build(); } - private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) { - if (type == ResourceType.BANDWIDTH) { - return ImmutableSet.of(getBandwidthResourceCapacity(link)); - } - if (type == ResourceType.LAMBDA) { - return getLambdaResourceCapacity(link); + private Set<ResourceAllocation> getResourceCapacity(ResourceType type, Link link) { + switch (type) { + case BANDWIDTH: + return ImmutableSet.of(getBandwidthResourceCapacity(link)); + case LAMBDA: + return getLambdaResourceCapacity(link); + case MPLS_LABEL: + return getMplsResourceCapacity(); + default: + return ImmutableSet.of(); } - if (type == ResourceType.MPLS_LABEL) { - return getMplsResourceCapacity(); - } - return ImmutableSet.of(); } - private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) { - Set<LambdaResourceAllocation> allocations = new HashSet<>(); + private Set<ResourceAllocation> getLambdaResourceCapacity(Link link) { Port port = deviceService.getPort(link.src().deviceId(), link.src().port()); - if (port instanceof OmsPort) { - OmsPort omsPort = (OmsPort) port; + if (!(port instanceof OmsPort)) { + return Collections.emptySet(); + } - // Assume fixed grid for now - for (int i = 0; i < omsPort.totalChannels(); i++) { - allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i))); - } + OmsPort omsPort = (OmsPort) port; + Set<ResourceAllocation> allocations = new HashSet<>(); + // Assume fixed grid for now + for (int i = 0; i < omsPort.totalChannels(); i++) { + allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i))); } return allocations; } @@ -170,26 +166,23 @@ public class ConsistentLinkResourceStore extends // if Link annotation exist, use them // if all fails, use DEFAULT_BANDWIDTH - BandwidthResource bandwidth = null; + BandwidthResource bandwidth = DEFAULT_BANDWIDTH; String strBw = link.annotations().value(BANDWIDTH); - if (strBw != null) { - try { - bandwidth = new BandwidthResource(Bandwidth.mbps(Double.parseDouble(strBw))); - } catch (NumberFormatException e) { - // do nothings - bandwidth = null; - } + if (strBw == null) { + return new BandwidthResourceAllocation(bandwidth); } - if (bandwidth == null) { - // fall back, use fixed default + try { + bandwidth = new BandwidthResource(Bandwidth.mbps(Double.parseDouble(strBw))); + } catch (NumberFormatException e) { + // do nothings, use default bandwidth bandwidth = DEFAULT_BANDWIDTH; } return new BandwidthResourceAllocation(bandwidth); } - private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() { - Set<MplsLabelResourceAllocation> allocations = new HashSet<>(); + private Set<ResourceAllocation> getMplsResourceCapacity() { + Set<ResourceAllocation> allocations = new HashSet<>(); //Ignoring reserved labels of 0 through 15 for (int i = MIN_UNRESERVED_LABEL; i <= MAX_UNRESERVED_LABEL; i++) { allocations.add(new MplsLabelResourceAllocation(MplsLabel @@ -199,13 +192,11 @@ public class ConsistentLinkResourceStore extends return allocations; } - private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) { - Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>(); + private Map<ResourceType, Set<ResourceAllocation>> getResourceCapacity(Link link) { + Map<ResourceType, Set<ResourceAllocation>> caps = new HashMap<>(); for (ResourceType type : ResourceType.values()) { - Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link); - if (cap != null) { - caps.put(type, cap); - } + Set<ResourceAllocation> cap = getResourceCapacity(type, link); + caps.put(type, cap); } return caps; } @@ -216,106 +207,80 @@ public class ConsistentLinkResourceStore extends tx.begin(); try { - Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(tx, link); - Set<ResourceAllocation> allFree = new HashSet<>(); - freeResources.values().forEach(allFree::addAll); - return allFree; + Map<ResourceType, Set<ResourceAllocation>> freeResources = getFreeResourcesEx(tx, link); + return freeResources.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); } finally { tx.abort(); } } - private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(TransactionContext tx, Link link) { + private Map<ResourceType, Set<ResourceAllocation>> getFreeResourcesEx(TransactionContext tx, Link link) { checkNotNull(tx); checkNotNull(link); - Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>(); - final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link); - final Iterable<LinkResourceAllocations> allocations = getAllocations(tx, link); + Map<ResourceType, Set<ResourceAllocation>> free = new HashMap<>(); + final Map<ResourceType, Set<ResourceAllocation>> caps = getResourceCapacity(link); + final List<LinkResourceAllocations> allocations = ImmutableList.copyOf(getAllocations(tx, link)); - for (ResourceType type : ResourceType.values()) { - // there should be class/category of resources + Set<ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH); + Set<ResourceAllocation> value = getFreeBandwidthResources(link, bw, allocations); + free.put(ResourceType.BANDWIDTH, value); - switch (type) { - case BANDWIDTH: - Set<? extends ResourceAllocation> bw = caps.get(type); - if (bw == null || bw.isEmpty()) { - bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW)); - } + Set<ResourceAllocation> lmd = caps.get(ResourceType.LAMBDA); + Set<ResourceAllocation> freeL = getFreeResources(link, lmd, allocations, + LambdaResourceAllocation.class); + free.put(ResourceType.LAMBDA, freeL); - BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next(); - double freeBw = cap.bandwidth().toDouble(); - - // enumerate current allocations, subtracting resources - for (LinkResourceAllocations alloc : allocations) { - Set<ResourceAllocation> types = alloc.getResourceAllocation(link); - for (ResourceAllocation a : types) { - if (a instanceof BandwidthResourceAllocation) { - BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a; - freeBw -= bwA.bandwidth().toDouble(); - } - } - } + Set<ResourceAllocation> mpls = caps.get(ResourceType.MPLS_LABEL); + Set<ResourceAllocation> freeLabel = getFreeResources(link, mpls, allocations, + MplsLabelResourceAllocation.class); + free.put(ResourceType.MPLS_LABEL, freeLabel); - free.put(type, Sets.newHashSet( - new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(freeBw))))); - break; - case LAMBDA: - Set<? extends ResourceAllocation> lmd = caps.get(type); - if (lmd == null || lmd.isEmpty()) { - // nothing left - break; - } - Set<LambdaResourceAllocation> freeL = new HashSet<>(); - for (ResourceAllocation r : lmd) { - if (r instanceof LambdaResourceAllocation) { - freeL.add((LambdaResourceAllocation) r); - } - } - - // enumerate current allocations, removing resources - for (LinkResourceAllocations alloc : allocations) { - Set<ResourceAllocation> types = alloc.getResourceAllocation(link); - for (ResourceAllocation a : types) { - if (a instanceof LambdaResourceAllocation) { - freeL.remove(a); - } - } - } + return free; + } - free.put(type, freeL); - break; - case MPLS_LABEL: - Set<? extends ResourceAllocation> mpls = caps.get(type); - if (mpls == null || mpls.isEmpty()) { - // nothing left - break; - } - Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>(); - for (ResourceAllocation r : mpls) { - if (r instanceof MplsLabelResourceAllocation) { - freeLabel.add((MplsLabelResourceAllocation) r); - } - } + private Set<ResourceAllocation> getFreeBandwidthResources(Link link, Set<ResourceAllocation> bw, + List<LinkResourceAllocations> allocations) { + if (bw == null || bw.isEmpty()) { + bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW)); + } - // enumerate current allocations, removing resources - for (LinkResourceAllocations alloc : allocations) { - Set<ResourceAllocation> types = alloc.getResourceAllocation(link); - for (ResourceAllocation a : types) { - if (a instanceof MplsLabelResourceAllocation) { - freeLabel.remove(a); - } - } - } + BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next(); + double freeBw = cap.bandwidth().toDouble(); + + // enumerate current allocations, subtracting resources + double allocatedBw = allocations.stream() + .flatMap(x -> x.getResourceAllocation(link).stream()) + .filter(x -> x instanceof BandwidthResourceAllocation) + .map(x -> (BandwidthResourceAllocation) x) + .mapToDouble(x -> x.bandwidth().toDouble()) + .sum(); + freeBw -= allocatedBw; + return Sets.newHashSet( + new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(freeBw)))); + } - free.put(type, freeLabel); - break; - default: - log.debug("unsupported ResourceType {}", type); - break; - } + private Set<ResourceAllocation> getFreeResources(Link link, + Set<ResourceAllocation> resources, + List<LinkResourceAllocations> allocations, + Class<? extends ResourceAllocation> cls) { + if (resources == null || resources.isEmpty()) { + // nothing left + return Collections.emptySet(); } - return free; + Set<ResourceAllocation> freeL = resources.stream() + .filter(cls::isInstance) + .collect(Collectors.toSet()); + + // enumerate current allocations, removing resources + List<ResourceAllocation> allocated = allocations.stream() + .flatMap(x -> x.getResourceAllocation(link).stream()) + .filter(cls::isInstance) + .collect(Collectors.toList()); + freeL.removeAll(allocated); + return freeL; } @Override @@ -329,6 +294,9 @@ public class ConsistentLinkResourceStore extends intentAllocs.put(allocations.intentId(), allocations); allocations.links().forEach(link -> allocateLinkResource(tx, link, allocations)); tx.commit(); + } catch (TransactionException | ResourceAllocationException e) { + log.error("Exception thrown, rolling back", e); + tx.abort(); } catch (Exception e) { log.error("Exception thrown, rolling back", e); tx.abort(); @@ -340,15 +308,13 @@ public class ConsistentLinkResourceStore extends LinkResourceAllocations allocations) { // requested resources Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link); - Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(tx, link); + Map<ResourceType, Set<ResourceAllocation>> available = getFreeResourcesEx(tx, link); for (ResourceAllocation req : reqs) { - Set<? extends ResourceAllocation> avail = available.get(req.type()); + Set<ResourceAllocation> avail = available.get(req.type()); if (req instanceof BandwidthResourceAllocation) { // check if allocation should be accepted if (avail.isEmpty()) { - checkState(!avail.isEmpty(), - "There's no Bandwidth resource on %s?", - link); + throw new ResourceAllocationException(String.format("There's no Bandwidth resource on %s?", link)); } BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next(); double bwLeft = bw.bandwidth().toDouble(); @@ -395,12 +361,7 @@ public class ConsistentLinkResourceStore extends if (before == null) { List<LinkResourceAllocations> after = new ArrayList<>(); after.add(allocations); - before = linkAllocs.putIfAbsent(linkKey, after); - if (before != null) { - // concurrent allocation detected, retry transaction : is this needed? - log.warn("Concurrent Allocation, retrying"); - throw new TransactionException(); - } + linkAllocs.putIfAbsent(linkKey, after); } else { List<LinkResourceAllocations> after = new ArrayList<>(before.size() + 1); after.addAll(before); @@ -500,19 +461,18 @@ public class ConsistentLinkResourceStore extends checkNotNull(link); final LinkKey key = LinkKey.linkKey(link); TransactionalMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx); - List<LinkResourceAllocations> res = null; - res = linkAllocs.get(key); - if (res == null) { - res = linkAllocs.putIfAbsent(key, new ArrayList<>()); + List<LinkResourceAllocations> res = linkAllocs.get(key); + if (res != null) { + return res; + } - if (res == null) { - return Collections.emptyList(); - } else { - return res; - } + res = linkAllocs.putIfAbsent(key, new ArrayList<>()); + if (res == null) { + return Collections.emptyList(); + } else { + return res; } - return res; } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java new file mode 100644 index 00000000..0cd4a831 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java @@ -0,0 +1,289 @@ +/*
+ * 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.store.statistic.impl;
+
+import com.google.common.base.Objects;
+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.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onlab.util.Tools;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.statistic.FlowStatisticStore;
+import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.serializers.KryoSerializer;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_CURRENT;
+import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_PREVIOUS;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Maintains flow statistics using RPC calls to collect stats from remote instances
+ * on demand.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedFlowStatisticStore implements FlowStatisticStore {
+ private final Logger log = getLogger(getClass());
+
+ // TODO: Make configurable.
+ private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 4;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterCommunicationService clusterCommunicator;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ private Map<ConnectPoint, Set<FlowEntry>> previous =
+ new ConcurrentHashMap<>();
+
+ private Map<ConnectPoint, Set<FlowEntry>> current =
+ new ConcurrentHashMap<>();
+
+ protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
+ @Override
+ protected void setupKryoPool() {
+ serializerPool = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
+ // register this store specific classes here
+ .build();
+ }
+ };
+
+ private NodeId local;
+ private ExecutorService messageHandlingExecutor;
+
+ private static final long STATISTIC_STORE_TIMEOUT_MILLIS = 3000;
+
+ @Activate
+ public void activate() {
+ local = clusterService.getLocalNode().id();
+
+ messageHandlingExecutor = Executors.newFixedThreadPool(
+ MESSAGE_HANDLER_THREAD_POOL_SIZE,
+ groupedThreads("onos/store/statistic", "message-handlers"));
+
+ clusterCommunicator.addSubscriber(
+ GET_CURRENT, SERIALIZER::decode, this::getCurrentStatisticInternal, SERIALIZER::encode,
+ messageHandlingExecutor);
+
+ clusterCommunicator.addSubscriber(
+ GET_CURRENT, SERIALIZER::decode, this::getPreviousStatisticInternal, SERIALIZER::encode,
+ messageHandlingExecutor);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ clusterCommunicator.removeSubscriber(GET_PREVIOUS);
+ clusterCommunicator.removeSubscriber(GET_CURRENT);
+ messageHandlingExecutor.shutdown();
+ log.info("Stopped");
+ }
+
+ @Override
+ public synchronized void removeFlowStatistic(FlowRule rule) {
+ ConnectPoint cp = buildConnectPoint(rule);
+ if (cp == null) {
+ return;
+ }
+
+ // remove this rule if present from current map
+ current.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
+
+ // remove this on if present from previous map
+ previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
+ }
+
+ @Override
+ public synchronized void addFlowStatistic(FlowEntry rule) {
+ ConnectPoint cp = buildConnectPoint(rule);
+ if (cp == null) {
+ return;
+ }
+
+ // create one if absent and add this rule
+ current.putIfAbsent(cp, new HashSet<>());
+ current.computeIfPresent(cp, (c, e) -> { e.add(rule); return e; });
+
+ // remove previous one if present
+ previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
+ }
+
+ public synchronized void updateFlowStatistic(FlowEntry rule) {
+ ConnectPoint cp = buildConnectPoint(rule);
+ if (cp == null) {
+ return;
+ }
+
+ Set<FlowEntry> curr = current.get(cp);
+ if (curr == null) {
+ addFlowStatistic(rule);
+ } else {
+ Optional<FlowEntry> f = curr.stream().filter(c -> rule.equals(c)).
+ findAny();
+ if (f.isPresent() && rule.bytes() < f.get().bytes()) {
+ log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
+ " Invalid Flow Update! Will be removed!!" +
+ " curr flowId=" + Long.toHexString(rule.id().value()) +
+ ", prev flowId=" + Long.toHexString(f.get().id().value()) +
+ ", curr bytes=" + rule.bytes() + ", prev bytes=" + f.get().bytes() +
+ ", curr life=" + rule.life() + ", prev life=" + f.get().life() +
+ ", curr lastSeen=" + rule.lastSeen() + ", prev lastSeen=" + f.get().lastSeen());
+ // something is wrong! invalid flow entry, so delete it
+ removeFlowStatistic(rule);
+ return;
+ }
+ Set<FlowEntry> prev = previous.get(cp);
+ if (prev == null) {
+ prev = new HashSet<>();
+ previous.put(cp, prev);
+ }
+
+ // previous one is exist
+ if (f.isPresent()) {
+ // remove old one and add new one
+ prev.remove(rule);
+ if (!prev.add(f.get())) {
+ log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
+ " flowId={}, add failed into previous.",
+ Long.toHexString(rule.id().value()));
+ }
+ }
+
+ // remove old one and add new one
+ curr.remove(rule);
+ if (!curr.add(rule)) {
+ log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
+ " flowId={}, add failed into current.",
+ Long.toHexString(rule.id().value()));
+ }
+ }
+ }
+
+ @Override
+ public Set<FlowEntry> getCurrentFlowStatistic(ConnectPoint connectPoint) {
+ final DeviceId deviceId = connectPoint.deviceId();
+
+ NodeId master = mastershipService.getMasterFor(deviceId);
+ if (master == null) {
+ log.warn("No master for {}", deviceId);
+ return Collections.emptySet();
+ }
+
+ if (Objects.equal(local, master)) {
+ return getCurrentStatisticInternal(connectPoint);
+ } else {
+ return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive(
+ connectPoint,
+ GET_CURRENT,
+ SERIALIZER::encode,
+ SERIALIZER::decode,
+ master),
+ STATISTIC_STORE_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS,
+ Collections.emptySet());
+ }
+ }
+
+ private synchronized Set<FlowEntry> getCurrentStatisticInternal(ConnectPoint connectPoint) {
+ return current.get(connectPoint);
+ }
+
+ @Override
+ public Set<FlowEntry> getPreviousFlowStatistic(ConnectPoint connectPoint) {
+ final DeviceId deviceId = connectPoint.deviceId();
+
+ NodeId master = mastershipService.getMasterFor(deviceId);
+ if (master == null) {
+ log.warn("No master for {}", deviceId);
+ return Collections.emptySet();
+ }
+
+ if (Objects.equal(local, master)) {
+ return getPreviousStatisticInternal(connectPoint);
+ } else {
+ return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive(
+ connectPoint,
+ GET_PREVIOUS,
+ SERIALIZER::encode,
+ SERIALIZER::decode,
+ master),
+ STATISTIC_STORE_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS,
+ Collections.emptySet());
+ }
+ }
+
+ private synchronized Set<FlowEntry> getPreviousStatisticInternal(ConnectPoint connectPoint) {
+ return previous.get(connectPoint);
+ }
+
+ private ConnectPoint buildConnectPoint(FlowRule rule) {
+ PortNumber port = getOutput(rule);
+
+ if (port == null) {
+ return null;
+ }
+ ConnectPoint cp = new ConnectPoint(rule.deviceId(), port);
+ return cp;
+ }
+
+ private PortNumber getOutput(FlowRule rule) {
+ for (Instruction i : rule.treatment().allInstructions()) {
+ if (i.type() == Instruction.Type.OUTPUT) {
+ Instructions.OutputInstruction out = (Instructions.OutputInstruction) i;
+ return out.port();
+ }
+ if (i.type() == Instruction.Type.DROP) {
+ return PortNumber.P0;
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java index 487fad9b..da4e3cc4 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java @@ -21,6 +21,7 @@ import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED; import static org.slf4j.LoggerFactory.getLogger; import java.util.Collections; +import java.util.Map; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -40,6 +41,7 @@ import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; import org.onosproject.net.Path; +import org.onosproject.net.DisjointPath; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.topology.ClusterId; import org.onosproject.net.topology.DefaultGraphDescription; @@ -74,7 +76,6 @@ public class DistributedTopologyStore implements TopologyStore { private final Logger log = getLogger(getClass()); - private volatile DefaultTopology current = new DefaultTopology(ProviderId.NONE, new DefaultGraphDescription(0L, System.currentTimeMillis(), @@ -167,6 +168,29 @@ public class DistributedTopologyStore } @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + return defaultTopology(topology).getDisjointPaths(src, dst); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map<Link, Object> riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, riskProfile); + } + + @Override + public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map<Link, Object> riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight, riskProfile); + } + + @Override public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { return defaultTopology(topology).isInfrastructure(connectPoint); } diff --git a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java new file mode 100644 index 00000000..a7077a81 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java @@ -0,0 +1,95 @@ +/* + * 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.store.host.impl; + +import junit.framework.TestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.host.DefaultHostDescription; +import org.onosproject.net.host.HostDescription; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.Timestamp; +import org.onosproject.store.service.LogicalClockService; +import org.onosproject.store.service.TestStorageService; + +import java.util.HashSet; +import java.util.Set; + +/** + * Tests for the ECHostStore. + */ +public class ECHostStoreTest extends TestCase { + + private ECHostStore ecXHostStore; + + private static final HostId HOSTID = HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a")); + + private static final IpAddress IP1 = IpAddress.valueOf("10.2.0.2"); + private static final IpAddress IP2 = IpAddress.valueOf("10.2.0.3"); + + private static final ProviderId PID = new ProviderId("of", "foo"); + + @Before + public void setUp() { + ecXHostStore = new ECHostStore(); + + ecXHostStore.storageService = new TestStorageService(); + ecXHostStore.clockService = new TestLogicalClockService(); + ecXHostStore.activate(); + } + + @After + public void tearDown() { + ecXHostStore.deactivate(); + } + + /** + * Tests the removeIp method call. + */ + @Test + public void testRemoveIp() { + Set<IpAddress> ips = new HashSet<>(); + ips.add(IP1); + ips.add(IP2); + + HostDescription description = new DefaultHostDescription(HOSTID.mac(), + HOSTID.vlanId(), + HostLocation.NONE, + ips); + ecXHostStore.createOrUpdateHost(PID, HOSTID, description, false); + ecXHostStore.removeIp(HOSTID, IP1); + Host host = ecXHostStore.getHost(HOSTID); + + assertFalse(host.ipAddresses().contains(IP1)); + assertTrue(host.ipAddresses().contains(IP2)); + } + + /** + * Mocks the LogicalClockService class. + */ + class TestLogicalClockService implements LogicalClockService { + @Override + public Timestamp getTimestamp() { + return null; + } + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java index 66ee7be7..5b5056cb 100644 --- a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java +++ b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java @@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; - import org.onlab.packet.ChassisId; import org.onlab.packet.EthType; import org.onlab.packet.Ip4Address; @@ -85,11 +84,11 @@ import org.onosproject.net.device.PortStatistics; import org.onosproject.net.flow.CompletedBatchOperation; import org.onosproject.net.flow.DefaultFlowEntry; import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTableStatisticsEntry; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowEntry; import org.onosproject.net.flow.FlowId; -import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.FlowRuleBatchEntry; import org.onosproject.net.flow.FlowRuleBatchEvent; import org.onosproject.net.flow.FlowRuleBatchOperation; @@ -97,6 +96,7 @@ import org.onosproject.net.flow.FlowRuleBatchRequest; import org.onosproject.net.flow.FlowRuleEvent; import org.onosproject.net.flow.FlowRuleExtPayLoad; import org.onosproject.net.flow.StoredFlowEntry; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.net.flow.criteria.Criterion; import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; @@ -118,7 +118,6 @@ import org.onosproject.net.flow.criteria.MetadataCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.OchSignalCriterion; import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; -import org.onosproject.net.flow.criteria.OpticalSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -302,7 +301,6 @@ public final class KryoNamespaces { DefaultHostDescription.class, DefaultFlowEntry.class, StoredFlowEntry.class, - FlowRule.Type.class, DefaultFlowRule.class, DefaultFlowEntry.class, DefaultPacketRequest.class, @@ -339,11 +337,11 @@ public final class KryoNamespaces { IndexedLambdaCriterion.class, OchSignalCriterion.class, OchSignalTypeCriterion.class, - OpticalSignalTypeCriterion.class, Criterion.class, Criterion.Type.class, DefaultTrafficTreatment.class, Instructions.DropInstruction.class, + Instructions.NoActionInstruction.class, Instructions.OutputInstruction.class, Instructions.GroupInstruction.class, Instructions.TableTypeTransition.class, @@ -425,7 +423,9 @@ public final class KryoNamespaces { DefaultAnnotations.class, PortStatistics.class, DefaultPortStatistics.class, - IntentDomainId.class + IntentDomainId.class, + TableStatisticsEntry.class, + DefaultTableStatisticsEntry.class ) .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class) .register(new URISerializer(), URI.class) |