diff options
author | Ashlee Young <ashlee@wildernessvoice.com> | 2015-12-06 07:15:03 -0800 |
---|---|---|
committer | Ashlee Young <ashlee@wildernessvoice.com> | 2015-12-08 10:55:21 -0800 |
commit | 76dc892491948adae5e5e62cf94448967e8d865b (patch) | |
tree | 7a33ef05cc583946db21edad627060f280a53549 /framework/src/onos/core | |
parent | d333c63fdec8b064184b0a26f8d777f267577fde (diff) |
Fixes bad POM file with ONOS commit 8c68536972f63069c263635c9d9f4f31d7f3e9a2
Change-Id: I7adb5a2d3738d53dbc41db7577768b0e7ced5450
Signed-off-by: Ashlee Young <ashlee@wildernessvoice.com>
Diffstat (limited to 'framework/src/onos/core')
75 files changed, 2706 insertions, 573 deletions
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 8c5fb790..38b599de 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,7 +25,6 @@ package org.onosproject.net; */ public final class AnnotationKeys { - // Prohibit instantiation private AnnotationKeys() { } @@ -81,6 +80,12 @@ public final class AnnotationKeys { public static final String DURABLE = "durable"; /** + * Annotation key for link metric; used by + * {@link org.onosproject.net.topology.MetricLinkWeight} function. + */ + public static final String METRIC = "metric"; + + /** * Annotation key for latency. * * @deprecated since Cardinal @@ -108,12 +113,23 @@ public final class AnnotationKeys { public static final String PORT_NAME = "portName"; /** + * Annotation key for the port mac. + */ + public static final String PORT_MAC = "portMac"; + + /** * Annotation key for the router ID. */ public static final String ROUTER_ID = "routerId"; + /** + * Annotation key for the static lambda. + */ public static final String STATIC_LAMBDA = "staticLambda"; + /** + * Annotation key for the static port. + */ public static final String STATIC_PORT = "staticPort"; /** diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultOchSignalComparator.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultOchSignalComparator.java new file mode 100644 index 00000000..e605dcfd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultOchSignalComparator.java @@ -0,0 +1,37 @@ +/* + * 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 java.util.Comparator; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Comparator implementation for OchSignal. Assumes identical grid type and channel spacing. + */ +public class DefaultOchSignalComparator implements Comparator<OchSignal> { + @Override + public int compare(OchSignal o1, OchSignal o2) { + checkNotNull(o1.gridType()); + checkNotNull(o1.channelSpacing()); + + checkArgument(o1.gridType().equals(o2.gridType())); + checkArgument(o1.channelSpacing().equals(o2.channelSpacing())); + + return o1.spacingMultiplier() * o1.slotGranularity() - o2.spacingMultiplier() * o2.slotGranularity(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshContextHeader.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshContextHeader.java new file mode 100644 index 00000000..745b616f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshContextHeader.java @@ -0,0 +1,83 @@ +/* + * 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 java.util.Objects; + +import com.google.common.base.MoreObjects; + +/* + * Representation of NSH context header value + */ +public final class NshContextHeader { + + private final int nshContextHeader; + + /** + * Default constructor. + * + * @param nshContextHeader nsh context header value. + */ + private NshContextHeader(int nshContextHeader) { + this.nshContextHeader = nshContextHeader; + } + + /** + * Returns the NshContextHeader by setting its value. + * + * @param nshContextHeader nsh context header value. + * @return NshContextHeader + */ + public static NshContextHeader of(int nshContextHeader) { + return new NshContextHeader(nshContextHeader); + } + + + /** + * Returns nsh context header value. + * + * @return the nsh context header + */ + public int nshContextHeader() { + return nshContextHeader; + } + + + @Override + public int hashCode() { + return Objects.hash(nshContextHeader); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof NshContextHeader)) { + return false; + } + final NshContextHeader other = (NshContextHeader) obj; + return Objects.equals(this.nshContextHeader, other.nshContextHeader); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("nshContextHeader", nshContextHeader) + .toString(); + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshServiceIndex.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshServiceIndex.java new file mode 100644 index 00000000..7e0c914c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshServiceIndex.java @@ -0,0 +1,83 @@ +/* + * 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 java.util.Objects; + +import com.google.common.base.MoreObjects; + +/* + * Representation of NSH Service index + */ +public final class NshServiceIndex { + private static final short MASK = 0xFF; + private final short serviceIndex; + + /** + * Default constructor. + * + * @param serviceIndex nsh service index + */ + private NshServiceIndex(short serviceIndex) { + this.serviceIndex = (short) (serviceIndex & MASK); + } + + /** + * Returns the NshServiceIndex by setting its value. + * + * @param serviceIndex nsh service index + * @return NshServiceIndex + */ + public static NshServiceIndex of(short serviceIndex) { + return new NshServiceIndex(serviceIndex); + } + + + /** + * Returns nsh service index value. + * + * @return the nsh service index + */ + public short serviceIndex() { + return serviceIndex; + } + + + @Override + public int hashCode() { + return Objects.hash(serviceIndex); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof NshServiceIndex)) { + return false; + } + final NshServiceIndex other = (NshServiceIndex) obj; + return Objects.equals(this.serviceIndex, other.serviceIndex); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("serviceIndex", serviceIndex) + .toString(); + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshServicePathId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshServicePathId.java new file mode 100644 index 00000000..16fbc4e7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NshServicePathId.java @@ -0,0 +1,83 @@ +/* + * 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 java.util.Objects; + +import com.google.common.base.MoreObjects; + +/* + * Representation of NSH Service path Identifier + */ +public final class NshServicePathId { + + private final int servicePathId; + + /** + * Default constructor. + * + * @param servicePathId nsh service path identifier + */ + private NshServicePathId(int servicePathId) { + this.servicePathId = servicePathId; + } + + /** + * Returns the NshServicePathId by setting its value. + * + * @param servicePathId nsh service path identifier + * @return NshServicePathId + */ + public static NshServicePathId of(int servicePathId) { + return new NshServicePathId(servicePathId); + } + + + /** + * Returns nsh context service path identifier. + * + * @return the nsh context service path id + */ + public int servicePathId() { + return servicePathId; + } + + + @Override + public int hashCode() { + return Objects.hash(servicePathId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof NshServicePathId)) { + return false; + } + final NshServicePathId other = (NshServicePathId) obj; + return Objects.equals(this.servicePathId, other.servicePathId); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("servicePathId", servicePathId) + .toString(); + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java index eb956f2a..94d4d321 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java @@ -87,7 +87,9 @@ public class OchPort extends DefaultPort { if (this == obj) { return true; } - if (obj instanceof OchPort) { + + // Subclass is considered as a change of identity, hence equals() will return false if class type don't match + if (obj != null && getClass() == obj.getClass()) { final OchPort other = (OchPort) obj; return Objects.equals(this.element().id(), other.element().id()) && Objects.equals(this.number(), other.number()) && diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java index 5a5af34a..3adc9086 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java @@ -17,6 +17,7 @@ package org.onosproject.net; import com.google.common.base.MoreObjects; import org.onlab.util.Frequency; +import org.onlab.util.Spectrum; import java.util.Objects; @@ -32,7 +33,6 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class OchSignal implements Lambda { - public static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1); public static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5); private static final GridType DEFAULT_OCH_GRIDTYPE = GridType.DWDM; private static final ChannelSpacing DEFAULT_CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ; @@ -78,7 +78,7 @@ public class OchSignal implements Lambda { this.gridType = DEFAULT_OCH_GRIDTYPE; this.channelSpacing = DEFAULT_CHANNEL_SPACING; - this.spacingMultiplier = (int) (centerFrequency.subtract(OchSignal.CENTER_FREQUENCY).asHz() / grid.asHz()); + this.spacingMultiplier = (int) (centerFrequency.subtract(Spectrum.CENTER_FREQUENCY).asHz() / grid.asHz()); this.slotGranularity = (int) Math.round((double) grid.asHz() / ChannelSpacing.CHL_12P5GHZ.frequency().asHz()); } @@ -86,7 +86,7 @@ public class OchSignal implements Lambda { this.gridType = DEFAULT_OCH_GRIDTYPE; this.channelSpacing = channelSpacing; this.spacingMultiplier = (int) Math.round((double) centerFrequency. - subtract(OchSignal.CENTER_FREQUENCY).asHz() / channelSpacing().frequency().asHz()); + subtract(Spectrum.CENTER_FREQUENCY).asHz() / channelSpacing().frequency().asHz()); this.slotGranularity = slotGranularity; } @@ -132,7 +132,7 @@ public class OchSignal implements Lambda { * @return frequency in MHz */ public Frequency centralFrequency() { - return CENTER_FREQUENCY.add(channelSpacing().frequency().multiply(spacingMultiplier)); + return Spectrum.CENTER_FREQUENCY.add(channelSpacing().frequency().multiply(spacingMultiplier)); } /** diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java index e5602f36..f51393a4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java @@ -71,7 +71,7 @@ public class OduCltPort extends DefaultPort { if (this == obj) { return true; } - if (obj instanceof OduCltPort) { + if (obj != null && getClass() == obj.getClass()) { final OduCltPort other = (OduCltPort) obj; return Objects.equals(this.element().id(), other.element().id()) && Objects.equals(this.number(), other.number()) && diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java index 753834b5..d37fe75d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java @@ -102,7 +102,7 @@ public class OmsPort extends DefaultPort { if (this == obj) { return true; } - if (obj instanceof OmsPort) { + if (obj != null && getClass() == obj.getClass()) { final OmsPort other = (OmsPort) obj; return Objects.equals(this.element().id(), other.element().id()) && Objects.equals(this.number(), other.number()) && diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionSelectorResolver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionSelectorResolver.java new file mode 100644 index 00000000..d45dd53c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionSelectorResolver.java @@ -0,0 +1,40 @@ +/* + * 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 com.google.common.annotations.Beta; +import org.onosproject.net.driver.HandlerBehaviour; +import org.onosproject.net.flow.criteria.ExtensionSelector; +import org.onosproject.net.flow.criteria.ExtensionSelectorType; + +/** + * Provides access to the extension selectors implemented by this driver. + */ +@Beta +public interface ExtensionSelectorResolver extends HandlerBehaviour { + + /** + * Gets an extension selector instance of the specified type, if supported + * by the driver. + * + * @param type type of extension to get + * @return extension selector + * @throws UnsupportedOperationException if the extension type is not + * supported by this driver + */ + ExtensionSelector getExtensionSelector(ExtensionSelectorType type); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionTreatmentResolver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionTreatmentResolver.java index 85f0216d..8ca05af3 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionTreatmentResolver.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionTreatmentResolver.java @@ -22,13 +22,13 @@ import org.onosproject.net.flow.instructions.ExtensionTreatment; import org.onosproject.net.flow.instructions.ExtensionTreatmentType; /** - * Provides access to the extension implemented by this driver. + * Provides access to the extension treatments implemented by this driver. */ @Beta public interface ExtensionTreatmentResolver extends HandlerBehaviour { /** - * Gets an extension instruction instance of the specified type, if supported + * Gets an extension treatment instance of the specified type, if supported * by the driver. * * @param type type of extension to get diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/LambdaQuery.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/LambdaQuery.java new file mode 100644 index 00000000..e3b1d963 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/LambdaQuery.java @@ -0,0 +1,40 @@ +/* + * 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 com.google.common.annotations.Beta; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.HandlerBehaviour; + +import java.util.SortedSet; + +/** + * A HandlerBehaviour to retrieve available wavelength resources. + */ +@Beta +public interface LambdaQuery extends HandlerBehaviour { + + // Currently returns set of FLEX GridType ochSignal instances + /** + * Returns set of Lambda instances which can be used at the port. + * + * @param port to be checked for the available resources. + * @return Set of OchSignals which can be used at the port. + */ + SortedSet<OchSignal> queryLambdas(PortNumber port); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java index 2fe2b2c0..92946312 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java @@ -15,13 +15,83 @@ */ package org.onosproject.net.config.basics; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.onlab.packet.IpAddress; +import org.onosproject.net.ConnectPoint; import org.onosproject.net.HostId; +import java.util.HashSet; +import java.util.Set; /** * Basic configuration for network end-station hosts. */ public class BasicHostConfig extends BasicElementConfig<HostId> { + private static final String IPS = "ips"; + private static final String LOCATION = "location"; - // TODO: determine what aspects of configuration to add for hosts + @Override + public boolean isValid() { + return hasOnlyFields(IPS, LOCATION) && + this.location() != null && + this.ipAddresses() != null; + } + /** + * Gets location of the host. + * + * @return location of the host. Or null if not specified with correct format. + */ + public ConnectPoint location() { + String location = get(LOCATION, null); + + if (location != null) { + try { + return ConnectPoint.deviceConnectPoint(location); + } catch (Exception e) { + return null; + } + } + return null; + } + + /** + * Sets the location of the host. + * + * @param location location of the host. + * @return the config of the host. + */ + public BasicHostConfig setLocation(String location) { + return (BasicHostConfig) setOrClear(LOCATION, location); + } + + /** + * Gets IP addresses of the host. + * + * @return IP addresses of the host. Or null if not specified with correct format. + */ + public Set<IpAddress> ipAddresses() { + HashSet<IpAddress> ipAddresses = new HashSet<>(); + if (object.has(IPS)) { + ArrayNode ipNodes = (ArrayNode) object.path(IPS); + try { + ipNodes.forEach(ipNode -> { + ipAddresses.add(IpAddress.valueOf(ipNode.asText())); + }); + return ipAddresses; + } catch (Exception e) { + return null; + } + } + return null; + } + + /** + * Sets the IP addresses of the host. + * + * @param ipAddresses IP addresses of the host. + * @return the config of the host. + */ + public BasicHostConfig setIps(Set<IpAddress> ipAddresses) { + return (BasicHostConfig) setOrClear(IPS, ipAddresses); + } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java index e962110c..ed807b8f 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java @@ -15,22 +15,32 @@ */ package org.onosproject.net.config.basics; +import com.fasterxml.jackson.databind.JsonNode; import org.onosproject.net.Link; import org.onosproject.net.LinkKey; -import com.fasterxml.jackson.databind.JsonNode; import java.time.Duration; +import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL; + /** * Basic configuration for network infrastructure link. */ public class BasicLinkConfig extends AllowedEntityConfig<LinkKey> { public static final String TYPE = "type"; + public static final String METRIC = "metric"; public static final String LATENCY = "latency"; public static final String BANDWIDTH = "bandwidth"; public static final String IS_DURABLE = "durable"; + @Override + public boolean isValid() { + return hasOnlyFields(TYPE, METRIC, LATENCY, BANDWIDTH, IS_DURABLE) && + isNumber(METRIC, OPTIONAL) && isNumber(LATENCY, OPTIONAL) && + isNumber(BANDWIDTH, OPTIONAL); + } + /** * Returns the link type. * @@ -51,6 +61,27 @@ public class BasicLinkConfig extends AllowedEntityConfig<LinkKey> { } /** + * Returns link metric value for use by + * {@link org.onosproject.net.topology.MetricLinkWeight} function. + * + * @return link metric; -1 if not set + */ + public double metric() { + return get(METRIC, -1); + } + + /** + * Sets the link metric for use by + * {@link org.onosproject.net.topology.MetricLinkWeight} function. + * + * @param metric new metric; null to clear + * @return self + */ + public BasicLinkConfig metric(Double metric) { + return (BasicLinkConfig) setOrClear(METRIC, metric); + } + + /** * Returns link latency in terms of nanos. * * @return link latency; -1 if not set diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/AbstractExtension.java index ac7c771f..b48d69ce 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/AbstractExtension.java @@ -14,22 +14,25 @@ * limitations under the License. */ -package org.onosproject.net.flow.instructions; +package org.onosproject.net.flow; + +import org.onosproject.net.flow.instructions.ExtensionPropertyException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; /** - * Abstract implementation of the set/get property methods of ExtensionInstruction. + * Abstract implementation of the set/get property methods of Extension. */ -public abstract class AbstractExtensionTreatment implements ExtensionTreatment { +public abstract class AbstractExtension implements Extension { private static final String INVALID_KEY = "Invalid property key: "; private static final String INVALID_TYPE = "Given type does not match field type: "; @Override - public <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException { + public <T> void setPropertyValue(String key, T value) throws + ExtensionPropertyException { Class<?> clazz = this.getClass(); try { Field field = clazz.getDeclaredField(key); 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 d3c2449c..0525d8fa 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 @@ -15,14 +15,8 @@ */ package org.onosproject.net.flow; -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; - +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip6Address; import org.onlab.packet.IpPrefix; @@ -30,12 +24,19 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; +import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.ExtensionSelector; -import com.google.common.base.MoreObjects; -import com.google.common.collect.ImmutableSet; +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. @@ -379,6 +380,12 @@ public final class DefaultTrafficSelector implements TrafficSelector { } @Override + public TrafficSelector.Builder extension(ExtensionSelector extensionSelector, + DeviceId deviceId) { + return add(Criteria.extension(extensionSelector, deviceId)); + } + + @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 22bff7dd..40291f57 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 @@ -489,6 +489,21 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { } @Override + public Builder setArpSpa(IpAddress addr) { + return add(Instructions.modArpSpa(addr)); + } + + @Override + public Builder setArpSha(MacAddress addr) { + return add(Instructions.modArpSha(addr)); + } + + @Override + public Builder setArpOp(short op) { + return add(Instructions.modL3ArpOp(op)); + } + + @Override public TrafficTreatment.Builder extension(ExtensionTreatment extension, DeviceId deviceId) { return add(Instructions.extension(extension, deviceId)); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Extension.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Extension.java new file mode 100644 index 00000000..1d61542e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Extension.java @@ -0,0 +1,71 @@ +/* + * 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.flow.instructions.ExtensionPropertyException; + +import java.util.List; + +/** + * An extension to the northbound APIs. + */ +public interface Extension { + + /** + * Sets a property on the extension. + * + * @param key property key + * @param value value to set for the given key + * @param <T> class of the value + * @throws ExtensionPropertyException if the given key is not a valid + * property on this extension + */ + <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException; + + /** + * Gets a property value of an extension. + * + * @param key property key + * @param <T> class of the value + * @return value of the property + * @throws ExtensionPropertyException if the given key is not a valid + * property on this extension + */ + <T> T getPropertyValue(String key) throws ExtensionPropertyException; + + /** + * Gets a list of all properties on the extension. + * + * @return list of properties + */ + List<String> getProperties(); + + /** + * Serialize the extension to a byte array. + * + * @return byte array + */ + byte[] serialize(); + + /** + * Deserialize the extension from a byte array. The properties + * of this object will be overwritten with the data in the byte array. + * + * @param data input byte array + */ + void deserialize(byte[] data); +} 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 b92281f5..0d055add 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 @@ -15,8 +15,6 @@ */ package org.onosproject.net.flow; -import java.util.Set; - import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip6Address; import org.onlab.packet.IpPrefix; @@ -24,8 +22,12 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; +import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.ExtensionSelector; + +import java.util.Set; /** * Abstraction of a slice of network traffic. @@ -427,6 +429,15 @@ public interface TrafficSelector { Builder matchArpOp(int arpOp); /** + * Uses an extension selector. + * + * @param extensionSelector extension selector + * @param deviceId device ID + * @return a selection builder + */ + Builder extension(ExtensionSelector extensionSelector, DeviceId deviceId); + + /** * 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 06b6ffa0..3e57925d 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 @@ -424,6 +424,30 @@ public interface TrafficTreatment { Builder setUdpDst(TpPort port); /** + * Sets the arp src ip address. + * + * @param addr an ip + * @return a treatment builder + */ + Builder setArpSpa(IpAddress addr); + + /** + * Sets the arp src mac address. + * + * @param addr a macaddress + * @return a treatment builder + */ + Builder setArpSha(MacAddress addr); + + /** + * Sets the arp operation. + * + * @param op the value of arp operation. + * @return a treatment builder. + */ + Builder setArpOp(short op); + + /** * Uses an extension treatment. * * @param extension extension treatment 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 a28a4ab9..c94b1e02 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 @@ -23,6 +23,7 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; +import org.onosproject.net.DeviceId; import org.onosproject.net.IndexedLambda; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; @@ -579,6 +580,33 @@ public final class Criteria { return new ArpOpCriterion(arpOp, Type.ARP_OP); } + /** + * Creates a match on PBB I-SID field using the specific value. + * + * @param pbbIsid PBB I-SID + * @return match criterion + */ + public static Criterion matchPbbIsid(int pbbIsid) { + return new PbbIsidCriterion(pbbIsid); + } + + /** + * Creates an extension criterion for the specified extension selector. + * + * @param extensionSelector extension selector + * @param deviceId device ID + * @return match criterion + */ + public static Criterion extension(ExtensionSelector extensionSelector, + DeviceId deviceId) { + return new ExtensionCriterion(extensionSelector, deviceId); + } + + /** + * Creates a dummy criterion. + * + * @return match criterion + */ public static Criterion dummy() { return new DummyCriterion(); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java index 26665246..17557b9d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java @@ -177,6 +177,9 @@ public interface Criterion { /** ODU (Optical channel Data Unit) signal type. */ ODU_SIGTYPE, + /** Extension criterion. */ + EXTENSION, + /** An empty criterion. */ DUMMY } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionCriterion.java new file mode 100644 index 00000000..646b4184 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionCriterion.java @@ -0,0 +1,92 @@ +/* + * 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.criteria; + +import org.onosproject.net.DeviceId; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Criterion for implementing selector extensions. + */ +public class ExtensionCriterion implements Criterion { + + private final ExtensionSelector extensionSelector; + private final DeviceId deviceId; + + /** + * Constructor. + * + * @param extensionSelector extension selector + */ + public ExtensionCriterion(ExtensionSelector extensionSelector, DeviceId deviceId) { + this.extensionSelector = extensionSelector; + this.deviceId = deviceId; + } + + /** + * Returns the extension selector. + * + * @return extension selector + */ + public ExtensionSelector extensionSelector() { + return extensionSelector; + } + + /** + * Returns the device ID. + * + * @return device ID + */ + public DeviceId deviceId() { + return deviceId; + } + + @Override + public Type type() { + return Type.EXTENSION; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("extensionSelector", extensionSelector.toString()) + .add("deviceId", deviceId) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), extensionSelector, deviceId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExtensionCriterion) { + ExtensionCriterion that = (ExtensionCriterion) obj; + return Objects.equals(extensionSelector, that.extensionSelector) && + Objects.equals(deviceId, that.deviceId) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionSelector.java new file mode 100644 index 00000000..d3cebb37 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionSelector.java @@ -0,0 +1,32 @@ +/* + * 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.criteria; + +import org.onosproject.net.flow.Extension; + +/** + * An extension for the selector API. + */ +public interface ExtensionSelector extends Extension { + + /** + * Gets the type of the extension selector. + * + * @return type + */ + ExtensionSelectorType type(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionSelectorType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionSelectorType.java new file mode 100644 index 00000000..fa8f0923 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ExtensionSelectorType.java @@ -0,0 +1,98 @@ +/* + * 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.criteria; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Type of selector extensions. + */ +@Beta +public class ExtensionSelectorType { + + /** + * A list of well-known named extension selector type codes. + * These numbers have no impact on the actual OF type id. + */ + public enum ExtensionSelectorTypes { + NICIRA_MATCH_NSH_SPI(0), + NICIRA_MATCH_NSH_SI(1), + NICIRA_MATCH_NSH_CH1(2), + NICIRA_MATCH_NSH_CH2(3), + NICIRA_MATCH_NSH_CH3(4), + NICIRA_MATCH_NSH_CH4(5); + + + private ExtensionSelectorType type; + + /** + * Creates a new named extension selector type. + * + * @param type type code + */ + ExtensionSelectorTypes(int type) { + this.type = new ExtensionSelectorType(type); + } + + /** + * Gets the extension type object for this named type code. + * + * @return extension type object + */ + public ExtensionSelectorType type() { + return type; + } + } + + private final int type; + + /** + * Creates an extension type with the given int type code. + * + * @param type type code + */ + public ExtensionSelectorType(int type) { + this.type = type; + } + + @Override + public int hashCode() { + return Objects.hash(type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExtensionSelectorType) { + final ExtensionSelectorType that = (ExtensionSelectorType) obj; + return this.type == that.type; + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(ExtensionSelectorType.class) + .add("type", type) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalIdCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalIdCriterion.java index cb513397..21018544 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalIdCriterion.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalIdCriterion.java @@ -74,7 +74,7 @@ public final class OduSignalIdCriterion implements Criterion { @Override public String toString() { - return toStringHelper(type().toString()) + return toStringHelper(this) .add("oduSignalId", oduSignalId) .toString(); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalTypeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalTypeCriterion.java index d92880db..f4854339 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalTypeCriterion.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OduSignalTypeCriterion.java @@ -74,7 +74,7 @@ public final class OduSignalTypeCriterion implements Criterion { @Override public String toString() { - return toStringHelper(type().toString()) + return toStringHelper(this) .add("signalType", signalType) .toString(); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/PbbIsidCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/PbbIsidCriterion.java new file mode 100644 index 00000000..979aa6bd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/PbbIsidCriterion.java @@ -0,0 +1,75 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of PBB I-SID criterion (24 bits unsigned integer). + */ +public final class PbbIsidCriterion implements Criterion { + private static final int MASK = 0xfffff; + private final int pbbIsid; // PBB I-SID: 24 bits + + /** + * Constructor. + * + * @param pbbIsid the PBB I-SID to match (24 bits) + */ + PbbIsidCriterion(int pbbIsid) { + this.pbbIsid = pbbIsid & MASK; + } + + @Override + public Criterion.Type type() { + return Criterion.Type.PBB_ISID; + } + + /** + * Gets the PBB I-SID to match. + * + * @return the PBB I-SID to match (24 bits) + */ + public int pbbIsid() { + return this.pbbIsid; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("pbbIsid", Long.toHexString(pbbIsid)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), pbbIsid); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof PbbIsidCriterion) { + PbbIsidCriterion that = (PbbIsidCriterion) obj; + return Objects.equals(pbbIsid, that.pbbIsid) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatment.java index 0e8885ed..3df152e9 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatment.java @@ -16,63 +16,18 @@ package org.onosproject.net.flow.instructions; -import java.util.List; +import org.onosproject.net.flow.Extension; /** - * An extensible instruction type. + * An extension for the treatment API. */ -public interface ExtensionTreatment { +public interface ExtensionTreatment extends Extension { /** - * Gets the type of the extension instruction. + * Gets the type of the treatment extension. * * @return type */ ExtensionTreatmentType type(); - /** - * Sets a property on the extension instruction. - * - * @param key property key - * @param value value to set for the given key - * @param <T> class of the value - * @throws ExtensionPropertyException if the given key is not a valid - * property on this extension instruction - */ - <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException; - - /** - * Gets a property value of an extension instruction. - * - * @param key property key - * @param <T> class of the value - * @return value of the property - * @throws ExtensionPropertyException if the given key is not a valid - * property on this extension instruction - */ - <T> T getPropertyValue(String key) throws ExtensionPropertyException; - - /** - * Gets a list of all properties on the extension instruction. - * - * @return list of properties - */ - List<String> getProperties(); - - /** - * Serialize the extension instruction to a byte array. - * - * @return byte array - */ - byte[] serialize(); - - /** - * Deserialize the extension instruction from a byte array. The properties - * of this object will be overwritten with the data in the byte array. - * - * @param data input byte array - */ - void deserialize(byte[] data); - - } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java index 38fbc279..f597a46c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java @@ -22,7 +22,7 @@ import com.google.common.base.MoreObjects; import java.util.Objects; /** - * Type of extension instructions. + * Type of treatment extensions. */ @Beta public final class ExtensionTreatmentType { @@ -32,15 +32,24 @@ public final class ExtensionTreatmentType { * These numbers have no impact on the actual OF type id. */ public enum ExtensionTreatmentTypes { - // TODO fix type numbers to include experimenter id NICIRA_SET_TUNNEL_DST(0), NICIRA_RESUBMIT(1), - NICIRA_SET_NSH_SPI(32); + NICIRA_RESUBMIT_TABLE(14), + NICIRA_SET_NSH_SPI(32), + NICIRA_SET_NSH_SI(33), + NICIRA_SET_NSH_CH1(34), + NICIRA_SET_NSH_CH2(35), + NICIRA_SET_NSH_CH3(36), + NICIRA_SET_NSH_CH4(37), + NICIRA_MOV_ARP_SHA_TO_THA(2), + NICIRA_MOV_ARP_SPA_TO_TPA(3), + NICIRA_MOV_ETH_SRC_TO_DST(4), + NICIRA_MOV_IP_SRC_TO_DST(5); private ExtensionTreatmentType type; /** - * Creates a new named extension instruction type. + * Creates a new named extension treatment type. * * @param type type code */ 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 4643b315..8ed882c8 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 @@ -35,6 +35,9 @@ import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSig import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModTtlInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction.L4SubType; @@ -299,6 +302,39 @@ public final class Instructions { } /** + * Creates a L3 ARP IP src modification. + * + * @param addr the ip address to modify to + * @return a L3 modification + */ + public static L3ModificationInstruction modArpSpa(IpAddress addr) { + checkNotNull(addr, "Src l3 ARP IP address cannot be null"); + return new ModArpIPInstruction(L3SubType.ARP_SPA, addr); + } + + /** + * Creates a l3 ARP Ether src modification. + * + * @param addr the mac address to modify to + * @return a l3 modification + */ + public static L3ModificationInstruction modArpSha(MacAddress addr) { + checkNotNull(addr, "Src l3 ARP address cannot be null"); + return new ModArpEthInstruction(L3SubType.ARP_SHA, addr); + } + + /** + * Creates a l3 ARP operation modification. + * + * @param op the ARP operation to modify to + * @return a l3 modification + */ + public static L3ModificationInstruction modL3ArpOp(short op) { + checkNotNull(op, "Arp operation cannot be null"); + return new ModArpOpInstruction(L3SubType.ARP_OP, op); + } + + /** * Creates a push MPLS header instruction. * * @return a L2 modification. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java index 41819504..0efe9a77 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java @@ -20,6 +20,7 @@ import static com.google.common.base.MoreObjects.toStringHelper; import java.util.Objects; import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; /** * Abstraction of a single traffic treatment step. @@ -68,7 +69,22 @@ public abstract class L3ModificationInstruction implements Instruction { /** * Copy TTL in. */ - TTL_IN + TTL_IN, + + /** + * ARP IP src modification. + */ + ARP_SPA, + + /** + * ARP Ether src modification. + */ + ARP_SHA, + + /** + * Arp operation modification. + */ + ARP_OP //TODO: remaining types } @@ -133,6 +149,150 @@ public abstract class L3ModificationInstruction implements Instruction { } /** + * Represents a L3 ARP IP src/dst modification instruction. + */ + public static final class ModArpIPInstruction extends L3ModificationInstruction { + + private final L3SubType subtype; + private final IpAddress ip; + + ModArpIPInstruction(L3SubType subType, IpAddress addr) { + + this.subtype = subType; + this.ip = addr; + } + + @Override + public L3SubType subtype() { + return this.subtype; + } + + public IpAddress ip() { + return this.ip; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("ip", ip).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), ip); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModArpIPInstruction) { + ModArpIPInstruction that = (ModArpIPInstruction) obj; + return Objects.equals(ip, that.ip) && + Objects.equals(this.subtype(), that.subtype()); + } + return false; + } + } + + /** + * Represents a L3 ARP Ether src/dst modification instruction. + */ + public static final class ModArpEthInstruction extends L3ModificationInstruction { + + private final L3SubType subtype; + private final MacAddress mac; + + ModArpEthInstruction(L3SubType subType, MacAddress addr) { + + this.subtype = subType; + this.mac = addr; + } + + @Override + public L3SubType subtype() { + return this.subtype; + } + + public MacAddress mac() { + return this.mac; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("mac", mac).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), mac); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModArpEthInstruction) { + ModArpEthInstruction that = (ModArpEthInstruction) obj; + return Objects.equals(mac, that.mac) && + Objects.equals(this.subtype(), that.subtype()); + } + return false; + } + } + + /** + * Represents a L3 ARP operation modification instruction. + */ + public static final class ModArpOpInstruction extends L3ModificationInstruction { + + private final L3SubType subtype; + private final short op; + + ModArpOpInstruction(L3SubType subType, short op) { + + this.subtype = subType; + this.op = op; + } + + @Override + public L3SubType subtype() { + return this.subtype; + } + + public long op() { + return this.op; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("op", op).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), op); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModArpOpInstruction) { + ModArpOpInstruction that = (ModArpOpInstruction) obj; + return Objects.equals(op, that.op) && + Objects.equals(this.subtype(), that.subtype()); + } + return false; + } + } + + /** * Represents a L3 IPv6 Flow Label (RFC 6437) modification instruction * (20 bits unsigned integer). */ diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java index 06305bf7..4d9d7225 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java @@ -196,7 +196,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { } @Override - public Builder setMeta(TrafficTreatment treatment) { + public Builder withMeta(TrafficTreatment treatment) { this.meta = treatment; return this; } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java index 4701589f..bd580507 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java @@ -181,7 +181,7 @@ public final class DefaultNextObjective implements NextObjective { } @Override - public Builder setMeta(TrafficSelector meta) { + public Builder withMeta(TrafficSelector meta) { this.meta = meta; return this; } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java index 29257c61..8ed793d0 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java @@ -133,7 +133,7 @@ public interface FilteringObjective extends Objective { * @param treatment traffic treatment to use * @return a filtering builder */ - Builder setMeta(TrafficTreatment treatment); + Builder withMeta(TrafficTreatment treatment); /** * Assigns an application id. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java index 08916eb2..36098d71 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java @@ -147,7 +147,7 @@ public interface NextObjective extends Objective { * @param selector match conditions * @return an objective builder */ - Builder setMeta(TrafficSelector selector); + Builder withMeta(TrafficSelector selector); /** * Builds the next objective that will be added. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentUtils.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentUtils.java new file mode 100644 index 00000000..f6e33b6b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentUtils.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.intent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; + +/** + * Utilities for dealing with intents. + */ +public final class IntentUtils { + + private static final Logger log = LoggerFactory.getLogger(IntentUtils.class); + + private IntentUtils() { + } + + /** + * Checks if two intents represent the same value. + * + * <p>({@link Intent#equals(Object)} only checks ID equality)</p> + * + * <p>Both intents must be of the same type.</p> + * + * @param one first intent + * @param two second intent + * @return true if the two intents represent the same value, otherwise false + */ + public static boolean equals(Intent one, Intent two) { + if (one.getClass() != two.getClass()) { + return false; + } + + if (!(Objects.equals(one.appId(), two.appId()) && + Objects.equals(one.key(), two.key()))) { + return false; + } + + if (one instanceof SinglePointToMultiPointIntent) { + SinglePointToMultiPointIntent intent1 = (SinglePointToMultiPointIntent) one; + SinglePointToMultiPointIntent intent2 = (SinglePointToMultiPointIntent) two; + + return Objects.equals(intent1.selector(), intent2.selector()) && + Objects.equals(intent1.treatment(), intent2.treatment()) && + Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) && + Objects.equals(intent1.egressPoints(), intent2.egressPoints()); + } else if (one instanceof MultiPointToSinglePointIntent) { + MultiPointToSinglePointIntent intent1 = (MultiPointToSinglePointIntent) one; + MultiPointToSinglePointIntent intent2 = (MultiPointToSinglePointIntent) two; + + return Objects.equals(intent1.selector(), intent2.selector()) && + Objects.equals(intent1.treatment(), intent2.treatment()) && + Objects.equals(intent1.ingressPoints(), intent2.ingressPoints()) && + Objects.equals(intent1.egressPoint(), intent2.egressPoint()); + } else if (one instanceof PointToPointIntent) { + PointToPointIntent intent1 = (PointToPointIntent) one; + PointToPointIntent intent2 = (PointToPointIntent) two; + + return Objects.equals(intent1.selector(), intent2.selector()) && + Objects.equals(intent1.treatment(), intent2.treatment()) && + Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) && + Objects.equals(intent1.egressPoint(), intent2.egressPoint()); + } else { + log.error("Unimplemented intent type"); + return false; + } + } +} 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 index 56e87c55..bf65033a 100644 --- 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 @@ -16,6 +16,7 @@ package org.onosproject.net.mcast; import com.google.common.annotations.Beta; +import org.onosproject.event.ListenerService; import org.onosproject.net.ConnectPoint; import java.util.List; @@ -24,7 +25,8 @@ import java.util.List; * A service interface for maintaining multicast information. */ @Beta -public interface MulticastRouteService { +public interface MulticastRouteService + extends ListenerService<McastEvent, McastListener> { /** * Adds a route to the information base. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java index c0c4e34f..72f8ac01 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java @@ -18,6 +18,8 @@ package org.onosproject.net.newresource; import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; import java.util.LinkedList; import java.util.List; @@ -41,8 +43,8 @@ import static com.google.common.base.Preconditions.checkState; * A double value is associated with a continuous type value. * * Users of this class must keep the semantics of resources regarding the hierarchical structure. - * For example, resource path, Link:1/VLAN ID:100, is valid, but resource path, VLAN ID:100/Link:1 - * is not valid because a link is not a sub-component of a VLAN ID. + * For example, resource path, Device:1/Port:1/VLAN ID:100, is valid, but resource path, + * VLAN ID:100/Device:1/Port:1 is not valid because a link is not a sub-component of a VLAN ID. */ @Beta public abstract class ResourcePath { @@ -52,29 +54,73 @@ public abstract class ResourcePath { public static final Discrete ROOT = new Discrete(); + public static ResourcePath discrete(DeviceId device) { + return new Discrete(ImmutableList.of(device)); + } + /** * Creates an resource path which represents a discrete-type resource from the specified components. * - * @param components components of the path. The order represents hierarchical structure of the resource. + * @param device device ID which is the first component of the path + * @param components following components of the path. The order represents hierarchical structure of the resource. * @return resource path instance */ - public static ResourcePath discrete(Object... components) { - if (components.length == 0) { - return ROOT; - } else { - return new Discrete(ImmutableList.copyOf(components)); - } + public static ResourcePath discrete(DeviceId device, Object... components) { + return new Discrete(ImmutableList.builder() + .add(device) + .add(components) + .build()); + } + + /** + * Creates an resource path which represents a discrete-type resource from the specified components. + * + * @param device device ID which is the first component of the path + * @param port port number which is the second component of the path + * @param components following components of the path. The order represents hierarchical structure of the resource. + * @return resource path instance + */ + public static ResourcePath discrete(DeviceId device, PortNumber port, Object... components) { + return new Discrete(ImmutableList.builder() + .add(device) + .add(port) + .add(components) + .build()); } /** * Creates an resource path which represents a continuous-type resource from the specified components. * * @param value amount of the resource - * @param components components of the path. The order represents hierarchical structure of the resource. + * @param device device ID which is the first component of the path + * @param components following components of the path. The order represents hierarchical structure of the resource. + * @return resource path instance + */ + public static ResourcePath continuous(double value, DeviceId device, Object... components) { + checkArgument(components.length > 0, + "Length of components must be greater thant 0, but " + components.length); + + return new Continuous(ImmutableList.builder() + .add(device) + .add(components) + .build(), value); + } + + /** + * Creates an resource path which represents a continuous-type resource from the specified components. + * + * @param value amount of the resource + * @param device device ID which is the first component of the path. + * @param port port number which is the second component of the path. + * @param components following components of the path. The order represents hierarchical structure of the resource. * @return resource path instance */ - public static ResourcePath continuous(double value, Object... components) { - return new Continuous(ImmutableList.copyOf(components), value); + public static ResourcePath continuous(double value, DeviceId device, PortNumber port, Object... components) { + return new Continuous(ImmutableList.builder() + .add(device) + .add(port) + .add(components) + .build(), value); } /** @@ -82,7 +128,7 @@ public abstract class ResourcePath { * * @param components components of the path. The order represents hierarchical structure of the resource. */ - ResourcePath(List<Object> components) { + protected ResourcePath(List<Object> components) { checkNotNull(components); checkArgument(!components.isEmpty()); @@ -101,7 +147,7 @@ public abstract class ResourcePath { * @param parent the parent of this resource * @param last a child of the parent */ - ResourcePath(Discrete parent, Object last) { + protected ResourcePath(Discrete parent, Object last) { checkNotNull(parent); checkNotNull(last); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/GeoDistanceLinkWeight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/GeoDistanceLinkWeight.java new file mode 100644 index 00000000..c966902e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/GeoDistanceLinkWeight.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014-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.onlab.util.GeoLocation; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.Annotations; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; + +import static java.lang.Double.MAX_VALUE; + +/** + * Link weight for measuring link cost using the geo distance between link + * vertices as determined by the element longitude/latitude annotation. + */ +public class GeoDistanceLinkWeight implements LinkWeight { + + private static final double MAX_KM = 40_075 / 2.0; + + private final DeviceService deviceService; + + /** + * Creates a new link-weight with access to the specified device service. + * + * @param deviceService device service reference + */ + public GeoDistanceLinkWeight(DeviceService deviceService) { + this.deviceService = deviceService; + } + + @Override + public double weight(TopologyEdge edge) { + GeoLocation src = getLocation(edge.link().src().deviceId()); + GeoLocation dst = getLocation(edge.link().dst().deviceId()); + return src != null && dst != null ? src.kilometersTo(dst) : MAX_KM; + } + + private GeoLocation getLocation(DeviceId deviceId) { + Device d = deviceService.getDevice(deviceId); + Annotations a = d != null ? d.annotations() : null; + double latitude = getDouble(a, AnnotationKeys.LATITUDE); + double longitude = getDouble(a, AnnotationKeys.LONGITUDE); + return latitude == MAX_VALUE || longitude == MAX_VALUE ? null : + new GeoLocation(latitude, longitude); + } + + private double getDouble(Annotations a, String key) { + String value = a != null ? a.value(key) : null; + try { + return value != null ? Double.parseDouble(value) : MAX_VALUE; + } catch (NumberFormatException e) { + return MAX_VALUE; + } + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/HopCountLinkWeight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/HopCountLinkWeight.java new file mode 100644 index 00000000..c557016b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/HopCountLinkWeight.java @@ -0,0 +1,36 @@ +package org.onosproject.net.topology; + +import static org.onosproject.net.Link.State.ACTIVE; +import static org.onosproject.net.Link.Type.INDIRECT; + +/** + * Link weight for measuring link cost as hop count with indirect links + * being as expensive as traversing the entire graph to assume the worst. + */ +public class HopCountLinkWeight implements LinkWeight { + private final int indirectLinkCost; + + /** + * Creates a new hop-count weight. + */ + public HopCountLinkWeight() { + this.indirectLinkCost = Short.MAX_VALUE; + } + + /** + * Creates a new hop-count weight with the specified cost of indirect links. + */ + public HopCountLinkWeight(int indirectLinkCost) { + this.indirectLinkCost = indirectLinkCost; + } + + @Override + public double weight(TopologyEdge edge) { + // To force preference to use direct paths first, make indirect + // links as expensive as the linear vertex traversal. + return edge.link().state() == + ACTIVE ? (edge.link().type() == + INDIRECT ? indirectLinkCost : 1) : -1; + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/MetricLinkWeight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/MetricLinkWeight.java new file mode 100644 index 00000000..8463e087 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/MetricLinkWeight.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014-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.AnnotationKeys; + +/** + * Link weight for measuring link cost using the link metric annotation. + */ +public class MetricLinkWeight implements LinkWeight { + + @Override + public double weight(TopologyEdge edge) { + String v = edge.link().annotations().value(AnnotationKeys.METRIC); + try { + return v != null ? Double.parseDouble(v) : 1; + } catch (NumberFormatException e) { + return 1; + } + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java new file mode 100644 index 00000000..9d077e1e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014-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.onlab.graph.GraphPathSearch; + +/** + * Provides administrative abilities to tailor the path service behaviours. + */ +public interface PathAdminService { + + /** + * Sets the specified link-weight function to be used as a default. + * If null is specified, the builtin default hop-count link-weight will be + * used. + * + * @param linkWeight default link-weight function + */ + void setDefaultLinkWeight(LinkWeight linkWeight); + + /** + * Sets the specified graph path search algorightm to be used as a default. + * If null is specified, the builtin default all-shortest-paths Dijkstra + * algorithm will be used. + * + * @param graphPathSearch default graph path search algorithm + */ + void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch); + +} 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 0bd4d75d..38954079 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 @@ -30,8 +30,9 @@ import java.util.Set; public interface PathService { /** - * Returns the set of all shortest paths, precomputed in terms of hop-count, - * between the specified source and destination elements. + * Returns the set of all shortest paths between the specified source and + * destination elements. The path is computed using the default edge-weight + * function, which by default is hop-count. * * @param src source element * @param dst destination element @@ -40,9 +41,9 @@ public interface PathService { Set<Path> getPaths(ElementId src, ElementId dst); /** - * Returns the set of all shortest paths, computed using the supplied - * edge-weight entity, between the specified source and destination - * network elements. + * Returns the set of all shortest paths between the specified source and + * destination network elements. The path is computed using the supplied + * edge-weight function. * * @param src source element * @param dst destination element @@ -52,8 +53,9 @@ public interface PathService { 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. + * Returns the set of all disjoint shortest path pairs between the + * specified source and destination elements. The path is computed using + * the default edge-weight function, which by default is hop-count. * * @param src source device * @param dst destination device @@ -62,8 +64,9 @@ public interface PathService { 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. + * Returns the set of all disjoint shortest path pairs between the + * specified source and destination elements. The path is computed using + * the supplied edge-weight function. * * @param src source device * @param dst destination device @@ -74,8 +77,10 @@ public interface PathService { LinkWeight weight); /** - * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, - * between the specified source and destination devices. + * Returns the set of all disjoint shortest path pairs between the + * specified source and destination elements and taking into consideration + * the provided risk profile. The path is computed using the default + * edge-weight function, which by default is hop-count. * * @param src source device * @param dst destination device @@ -86,8 +91,10 @@ public interface PathService { 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. + * Returns the set of all disjoint shortest path pairs between the + * specified source and destination elements and taking into consideration + * the provided risk profile. The path is computed using the supplied + * edge-weight function. * * @param src source device * @param dst destination device @@ -96,6 +103,7 @@ public interface PathService { * @return set of all shortest paths between the two devices */ Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, - LinkWeight weight, Map<Link, Object> riskProfile); + LinkWeight weight, + Map<Link, Object> riskProfile); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java index 4030abdc..efe69f5f 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java @@ -131,6 +131,10 @@ public final class TopoJson { if (hh.subdued()) { n.put(SUBDUE, true); } + NodeBadge badge = hh.badge(); + if (badge != null) { + n.set(BADGE, json(badge)); + } return n; } 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 56a6ff63..d113fb98 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 @@ -222,6 +222,12 @@ public class CriteriaTest { Criterion sameAsMatchMpls1 = Criteria.matchMplsLabel(mpls1); Criterion matchMpls2 = Criteria.matchMplsLabel(mpls2); + byte mplsTc1 = 1; + byte mplsTc2 = 2; + Criterion matchMplsTc1 = Criteria.matchMplsTc(mplsTc1); + Criterion sameAsMatchMplsTc1 = Criteria.matchMplsTc(mplsTc1); + Criterion matchMplsTc2 = Criteria.matchMplsTc(mplsTc2); + long tunnelId1 = 1; long tunnelId2 = 2; Criterion matchTunnelId1 = Criteria.matchTunnelId(tunnelId1); @@ -273,6 +279,12 @@ public class CriteriaTest { Criterion sameAsMatchOduSignalType1 = Criteria.matchOduSignalType(oduSigType1); Criterion matchOduSignalType2 = Criteria.matchOduSignalType(oduSigType2); + int pbbIsid1 = 1; + int pbbIsid2 = 2; + Criterion matchPbbIsid1 = Criteria.matchPbbIsid(pbbIsid1); + Criterion sameAsMatchPbbIsid1 = Criteria.matchPbbIsid(pbbIsid1); + Criterion matchPbbIsid2 = Criteria.matchPbbIsid(pbbIsid2); + /** * Checks that a Criterion object has the proper type, and then converts * it to the proper type. @@ -326,10 +338,12 @@ public class CriteriaTest { assertThatClassIsImmutable(IPv6NDTargetAddressCriterion.class); assertThatClassIsImmutable(IPv6NDLinkLayerAddressCriterion.class); assertThatClassIsImmutable(MplsCriterion.class); + assertThatClassIsImmutable(MplsTcCriterion.class); assertThatClassIsImmutable(IPv6ExthdrFlagsCriterion.class); assertThatClassIsImmutable(LambdaCriterion.class); assertThatClassIsImmutable(OduSignalIdCriterion.class); assertThatClassIsImmutable(OduSignalTypeCriterion.class); + assertThatClassIsImmutable(PbbIsidCriterion.class); } // PortCriterion class @@ -752,6 +766,19 @@ public class CriteriaTest { // TcpFlagsCriterion class /** + * Test the matchTcpFlags method. + */ + @Test + public void testMatchTcpFlagsMethod() { + Criterion matchTcpFlag = Criteria.matchTcpFlags(tcpFlags1); + TcpFlagsCriterion tcpFlagsCriterion = + checkAndConvert(matchTcpFlag, + Criterion.Type.TCP_FLAGS, + TcpFlagsCriterion.class); + assertThat(tcpFlagsCriterion.flags(), is(equalTo(tcpFlags1))); + } + + /** * Test the equals() method of the TcpFlagsCriterion class. */ @Test @@ -1037,6 +1064,32 @@ public class CriteriaTest { .testEquals(); } + // MplsTcCriterion class + + /** + * Test the matchMplsTc method. + */ + @Test + public void testMatchMplsTcMethod() { + Criterion matchMplsTc = Criteria.matchMplsTc(mplsTc1); + MplsTcCriterion mplsTcCriterion = + checkAndConvert(matchMplsTc, + Criterion.Type.MPLS_TC, + MplsTcCriterion.class); + assertThat(mplsTcCriterion.tc(), is(equalTo(mplsTc1))); + } + + /** + * Test the equals() method of the MplsTcCriterion class. + */ + @Test + public void testMplsTcCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchMplsTc1, sameAsMatchMplsTc1) + .addEqualityGroup(matchMplsTc2) + .testEquals(); + } + // TunnelIdCriterion class /** @@ -1172,4 +1225,30 @@ public class CriteriaTest { .addEqualityGroup(matchOduSignalType2) .testEquals(); } + + // PbbIsidCriterion class + + /** + * Test the matchPbbIsid method. + */ + @Test + public void testMatchPbbIsidMethod() { + Criterion matchPbbIsid = Criteria.matchPbbIsid(pbbIsid1); + PbbIsidCriterion pbbIsidCriterion = + checkAndConvert(matchPbbIsid, + Criterion.Type.PBB_ISID, + PbbIsidCriterion.class); + assertThat(pbbIsidCriterion.pbbIsid(), is(equalTo(pbbIsid1))); + } + + /** + * Test the equals() method of the PbbIsidCriterion class. + */ + @Test + public void testPbbIsidCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchPbbIsid1, sameAsMatchPbbIsid1) + .addEqualityGroup(matchPbbIsid2) + .testEquals(); + } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.java index 5f448221..d21c4b1b 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.java @@ -18,9 +18,7 @@ package org.onosproject.net.newresource; import com.google.common.testing.EqualsTester; import org.junit.Test; import org.onlab.packet.VlanId; -import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; -import org.onosproject.net.LinkKey; import org.onosproject.net.PortNumber; import org.onosproject.net.intent.IntentId; @@ -29,18 +27,14 @@ public class ResourceAllocationTest { private static final DeviceId D1 = DeviceId.deviceId("of:001"); private static final DeviceId D2 = DeviceId.deviceId("of:002"); private static final PortNumber P1 = PortNumber.portNumber(1); - private static final ConnectPoint CP1_1 = new ConnectPoint(D1, P1); - private static final ConnectPoint CP2_1 = new ConnectPoint(D2, P1); private static final VlanId VLAN1 = VlanId.vlanId((short) 100); private static final IntentId IID1 = IntentId.valueOf(30); - private static final LinkKey LK1 = LinkKey.linkKey(CP1_1, CP2_1); - private static final LinkKey LK2 = LinkKey.linkKey(CP2_1, CP1_1); @Test public void testEquals() { - ResourceAllocation alloc1 = new ResourceAllocation(ResourcePath.discrete(LK1, VLAN1), IID1); - ResourceAllocation sameAsAlloc1 = new ResourceAllocation(ResourcePath.discrete(LK1, VLAN1), IID1); - ResourceAllocation alloc2 = new ResourceAllocation(ResourcePath.discrete(LK2, VLAN1), IID1); + ResourceAllocation alloc1 = new ResourceAllocation(ResourcePath.discrete(D1, P1, VLAN1), IID1); + ResourceAllocation sameAsAlloc1 = new ResourceAllocation(ResourcePath.discrete(D1, P1, VLAN1), IID1); + ResourceAllocation alloc2 = new ResourceAllocation(ResourcePath.discrete(D2, P1, VLAN1), IID1); new EqualsTester() .addEqualityGroup(alloc1, sameAsAlloc1) diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java index 35dcf1ec..4bbb458c 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java @@ -19,9 +19,7 @@ import com.google.common.testing.EqualsTester; import org.junit.Test; import org.onlab.packet.VlanId; import org.onlab.util.Bandwidth; -import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; -import org.onosproject.net.LinkKey; import org.onosproject.net.PortNumber; import java.util.Optional; @@ -35,19 +33,17 @@ public class ResourcePathTest { private static final DeviceId D1 = DeviceId.deviceId("of:001"); private static final DeviceId D2 = DeviceId.deviceId("of:002"); private static final PortNumber P1 = PortNumber.portNumber(1); - private static final ConnectPoint CP1_1 = new ConnectPoint(D1, P1); - private static final ConnectPoint CP2_1 = new ConnectPoint(D2, P1); private static final VlanId VLAN1 = VlanId.vlanId((short) 100); private static final Bandwidth BW1 = Bandwidth.gbps(2); private static final Bandwidth BW2 = Bandwidth.gbps(1); @Test public void testEquals() { - ResourcePath resource1 = ResourcePath.discrete(LinkKey.linkKey(CP1_1, CP2_1), VLAN1); - ResourcePath sameAsResource1 = ResourcePath.discrete(LinkKey.linkKey(CP1_1, CP2_1), VLAN1); - ResourcePath resource2 = ResourcePath.discrete(LinkKey.linkKey(CP2_1, CP1_1), VLAN1); - ResourcePath resource3 = ResourcePath.continuous(BW1.bps(), LinkKey.linkKey(CP1_1, CP2_1), BW1); - ResourcePath sameAsResource3 = ResourcePath.continuous(BW2.bps(), LinkKey.linkKey(CP1_1, CP2_1), BW1); + ResourcePath resource1 = ResourcePath.discrete(D1, P1, VLAN1); + ResourcePath sameAsResource1 = ResourcePath.discrete(D1, P1, VLAN1); + ResourcePath resource2 = ResourcePath.discrete(D2, P1, VLAN1); + ResourcePath resource3 = ResourcePath.continuous(BW1.bps(), D1, P1, BW1); + ResourcePath sameAsResource3 = ResourcePath.continuous(BW2.bps(), D1, P1, BW1); new EqualsTester() .addEqualityGroup(resource1, sameAsResource1) @@ -57,13 +53,6 @@ public class ResourcePathTest { } @Test - public void testCreateWithZeroComponent() { - ResourcePath path = ResourcePath.discrete(); - - assertThat(path, is(ResourcePath.ROOT)); - } - - @Test public void testComponents() { ResourcePath port = ResourcePath.discrete(D1, P1); @@ -72,25 +61,24 @@ public class ResourcePathTest { @Test public void testThereIsParent() { - ResourcePath path = ResourcePath.discrete(LinkKey.linkKey(CP1_1, CP2_1), VLAN1); - ResourcePath parent = ResourcePath.discrete(LinkKey.linkKey(CP1_1, CP2_1)); + ResourcePath path = ResourcePath.discrete(D1, P1, VLAN1); + ResourcePath parent = ResourcePath.discrete(D1, P1); assertThat(path.parent(), is(Optional.of(parent))); } @Test public void testNoParent() { - ResourcePath path = ResourcePath.discrete(LinkKey.linkKey(CP1_1, CP2_1)); + ResourcePath path = ResourcePath.discrete(D1); assertThat(path.parent(), is(Optional.of(ResourcePath.ROOT))); } @Test public void testBase() { - LinkKey linkKey = LinkKey.linkKey(CP1_1, CP2_1); - ResourcePath path = ResourcePath.discrete(linkKey); + ResourcePath path = ResourcePath.discrete(D1); - LinkKey child = (LinkKey) path.last(); - assertThat(child, is(linkKey)); + DeviceId child = (DeviceId) path.last(); + assertThat(child, is(D1)); } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/persistence/PersistenceServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/persistence/PersistenceServiceAdapter.java new file mode 100644 index 00000000..3edfcc73 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/persistence/PersistenceServiceAdapter.java @@ -0,0 +1,36 @@ +/* + * 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.persistence; + +import org.onosproject.persistence.PersistenceService; +import org.onosproject.persistence.PersistentMapBuilder; +import org.onosproject.persistence.PersistentSetBuilder; + +/** + * Adapter for PersistenceService. + */ +public class PersistenceServiceAdapter implements PersistenceService { + + @Override + public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() { + return null; + } + + @Override + public <E> PersistentSetBuilder<E> persistentSetBuilder() { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/persistence/TestPersistenceService.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/persistence/TestPersistenceService.java new file mode 100644 index 00000000..a6d97458 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/persistence/TestPersistenceService.java @@ -0,0 +1,57 @@ +/* + * 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.persistence; + +import java.util.Map; + +import org.onosproject.persistence.PersistentMapBuilder; +import org.onosproject.persistence.PersistentSetBuilder; +import org.onosproject.store.service.Serializer; + +import com.google.common.collect.Maps; + +/** + * PersistenceService that produces in memory maps for use in unit testing. + */ +public class TestPersistenceService extends PersistenceServiceAdapter { + @Override + public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() { + return new TestPersistentMapBuilder<K, V>(); + } + + @Override + public <E> PersistentSetBuilder<E> persistentSetBuilder() { + throw new UnsupportedOperationException(); + } + + private static class TestPersistentMapBuilder<K, V> implements PersistentMapBuilder<K, V> { + + @Override + public PersistentMapBuilder<K, V> withName(String name) { + return this; + } + + @Override + public PersistentMapBuilder<K, V> withSerializer(Serializer serializer) { + return this; + } + + @Override + public Map<K, V> build() { + return Maps.newConcurrentMap(); + } + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java index 33dd46a3..1852ee29 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java @@ -127,6 +127,7 @@ public final class EncodeCriterionCodecHelper { formatMap.put(Criterion.Type.TCP_FLAGS, new FormatUnknown()); formatMap.put(Criterion.Type.ACTSET_OUTPUT, new FormatUnknown()); formatMap.put(Criterion.Type.PACKET_TYPE, new FormatUnknown()); + formatMap.put(Criterion.Type.EXTENSION, new FormatUnknown()); } private interface CriterionTypeFormatter { 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 84cde424..c5263ed7 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 @@ -43,12 +43,15 @@ import org.onosproject.net.topology.ClusterId; import org.onosproject.net.topology.DefaultTopologyCluster; import org.onosproject.net.topology.DefaultTopologyVertex; import org.onosproject.net.topology.GraphDescription; +import org.onosproject.net.topology.HopCountLinkWeight; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.Topology; import org.onosproject.net.topology.TopologyCluster; import org.onosproject.net.topology.TopologyEdge; import org.onosproject.net.topology.TopologyGraph; import org.onosproject.net.topology.TopologyVertex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.List; @@ -61,7 +64,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static org.onlab.graph.GraphPathSearch.ALL_PATHS; import static org.onlab.util.Tools.isNullOrEmpty; import static org.onosproject.core.CoreService.CORE_PROVIDER_ID; -import static org.onosproject.net.Link.State.ACTIVE; import static org.onosproject.net.Link.State.INACTIVE; import static org.onosproject.net.Link.Type.INDIRECT; @@ -71,18 +73,22 @@ import static org.onosproject.net.Link.Type.INDIRECT; */ public class DefaultTopology extends AbstractModel implements Topology { + private static final Logger log = LoggerFactory.getLogger(DefaultTopology.class); + 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 static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE = new SuurballeGraphSearch<>(); + private static LinkWeight defaultLinkWeight = null; + private static GraphPathSearch<TopologyVertex, TopologyEdge> defaultGraphPathSearch = null; private final long time; private final long creationTime; private final long computeCost; private final TopologyGraph graph; - private final LinkWeight weight; + private final LinkWeight hopCountWeight; + private final Supplier<SccResult<TopologyVertex, TopologyEdge>> clusterResults; private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters; private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints; @@ -91,6 +97,30 @@ public class DefaultTopology extends AbstractModel implements Topology { private final Supplier<ClusterIndexes> clusterIndexes; /** + * Sets the default link-weight to be used when computing paths. If null is + * specified, the builtin default link-weight measuring hop-counts will be + * used. + * + * @param linkWeight new default link-weight + */ + public static void setDefaultLinkWeight(LinkWeight linkWeight) { + log.info("Setting new default link-weight function to {}", linkWeight); + defaultLinkWeight = linkWeight; + } + + /** + * Sets the default lpath search algorighm to be used when computing paths. + * If null is specified, the builtin default Dijkstra will be used. + * + * @param graphPathSearch new default algorithm + */ + public static void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch) { + log.info("Setting new default graph path algorithm to {}", graphPathSearch); + defaultGraphPathSearch = graphPathSearch; + } + + + /** * Creates a topology descriptor attributed to the specified provider. * * @param providerId identity of the provider @@ -113,7 +143,7 @@ public class DefaultTopology extends AbstractModel implements Topology { this.clusterIndexes = Suppliers.memoize(() -> buildIndexes()); - this.weight = new HopCountLinkWeight(graph.getVertexes().size()); + this.hopCountWeight = new HopCountLinkWeight(graph.getVertexes().size()); this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets()); this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints()); this.computeCost = Math.max(0, System.nanoTime() - time); @@ -294,7 +324,7 @@ public class DefaultTopology extends AbstractModel implements Topology { * @return set of shortest paths */ public Set<Path> getPaths(DeviceId src, DeviceId dst) { - return getPaths(src, dst, null); + return getPaths(src, dst, linkWeight()); } /** @@ -307,8 +337,8 @@ public class DefaultTopology extends AbstractModel implements Topology { * @return set of shortest paths */ public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) { - final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); - final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); + 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 @@ -316,7 +346,7 @@ public class DefaultTopology extends AbstractModel implements Topology { } GraphPathSearch.Result<TopologyVertex, TopologyEdge> result = - DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS); + graphPathSearch().search(graph, srcV, dstV, weight, ALL_PATHS); ImmutableSet.Builder<Path> builder = ImmutableSet.builder(); for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) { builder.add(networkPath(path)); @@ -334,7 +364,7 @@ public class DefaultTopology extends AbstractModel implements Topology { * @return set of shortest disjoint path pairs */ public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) { - return getDisjointPaths(src, dst, (LinkWeight) null); + return getDisjointPaths(src, dst, linkWeight()); } /** @@ -347,8 +377,8 @@ public class DefaultTopology extends AbstractModel implements Topology { * @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); + 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 @@ -375,7 +405,7 @@ public class DefaultTopology extends AbstractModel implements Topology { * @return set of shortest disjoint paths */ private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight, - Map<TopologyEdge, Object> riskProfile) { + Map<TopologyEdge, Object> riskProfile) { DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); @@ -438,7 +468,7 @@ public class DefaultTopology extends AbstractModel implements Topology { * @return set of shortest disjoint paths */ public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) { - return getDisjointPaths(src, dst, null, riskProfile); + return getDisjointPaths(src, dst, linkWeight(), riskProfile); } // Converts graph path to a network path with the same cost. @@ -499,8 +529,7 @@ public class DefaultTopology extends AbstractModel implements Topology { // Processes a map of broadcast sets for each cluster. private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() { - Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap - .builder(); + Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder(); for (TopologyCluster cluster : clusters.get().values()) { addClusterBroadcastSet(cluster, builder); } @@ -512,7 +541,7 @@ public class DefaultTopology extends AbstractModel implements Topology { // all other devices within the cluster. private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) { // Use the graph root search results to build the broadcast set. - Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1); + Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, hopCountWeight, 1); for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) { TopologyVertex vertex = entry.getKey(); @@ -577,23 +606,12 @@ public class DefaultTopology extends AbstractModel implements Topology { linksBuilder.build()); } - // Link weight for measuring link cost as hop count with indirect links - // being as expensive as traversing the entire graph to assume the worst. - private static class HopCountLinkWeight implements LinkWeight { - private final int indirectLinkCost; - - HopCountLinkWeight(int indirectLinkCost) { - this.indirectLinkCost = indirectLinkCost; - } + private GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch() { + return defaultGraphPathSearch != null ? defaultGraphPathSearch : DIJKSTRA; + } - @Override - public double weight(TopologyEdge edge) { - // To force preference to use direct paths first, make indirect - // links as expensive as the linear vertex traversal. - return edge.link().state() == - ACTIVE ? (edge.link().type() == - INDIRECT ? indirectLinkCost : 1) : -1; - } + private LinkWeight linkWeight() { + return defaultLinkWeight != null ? defaultLinkWeight : hopCountWeight; } // Link weight for preventing traversal over indirect links. diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java index e992f7a4..cd7335d6 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java @@ -27,10 +27,10 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onosproject.event.AbstractListenerManager; -import org.onosproject.event.Event; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; import org.onosproject.net.edge.EdgePortEvent; import org.onosproject.net.edge.EdgePortListener; @@ -38,17 +38,16 @@ import org.onosproject.net.edge.EdgePortService; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.link.LinkListener; +import org.onosproject.net.link.LinkService; import org.onosproject.net.packet.DefaultOutboundPacket; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketService; import org.onosproject.net.topology.Topology; -import org.onosproject.net.topology.TopologyEvent; -import org.onosproject.net.topology.TopologyListener; import org.onosproject.net.topology.TopologyService; import org.slf4j.Logger; import java.nio.ByteBuffer; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -73,7 +72,9 @@ public class EdgeManager private final Map<DeviceId, Set<ConnectPoint>> connectionPoints = Maps.newConcurrentMap(); - private final TopologyListener topologyListener = new InnerTopologyListener(); + private final LinkListener linkListener = new InnerLinkListener(); + + private final DeviceListener deviceListener = new InnerDeviceListener(); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected PacketService packetService; @@ -84,17 +85,23 @@ public class EdgeManager @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected TopologyService topologyService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkService linkService; + @Activate public void activate() { eventDispatcher.addSink(EdgePortEvent.class, listenerRegistry); - topologyService.addListener(topologyListener); + deviceService.addListener(deviceListener); + linkService.addListener(linkListener); + loadAllEdgePorts(); log.info("Started"); } @Deactivate public void deactivate() { eventDispatcher.removeSink(EdgePortEvent.class); - topologyService.removeListener(topologyListener); + deviceService.removeListener(deviceListener); + linkService.removeListener(linkListener); log.info("Stopped"); } @@ -142,31 +149,27 @@ public class EdgeManager return new DefaultOutboundPacket(point.deviceId(), builder.build(), data); } - // Internal listener for topo events used to keep our edge-port cache - // up to date. - private class InnerTopologyListener implements TopologyListener { + private class InnerLinkListener implements LinkListener { + @Override - public void event(TopologyEvent event) { - topology = event.subject(); - List<Event> triggers = event.reasons(); - if (triggers != null) { - triggers.forEach(reason -> { - if (reason instanceof DeviceEvent) { - processDeviceEvent((DeviceEvent) reason); - } else if (reason instanceof LinkEvent) { - processLinkEvent((LinkEvent) reason); - } - }); - } else { - //FIXME special case of preexisting edgeport & no triggerless events could cause this to never hit and - //never discover an edgeport that should have been discovered. - loadAllEdgePorts(); - } + public void event(LinkEvent event) { + topology = topologyService.currentTopology(); + processLinkEvent(event); + } + } + + private class InnerDeviceListener implements DeviceListener { + + @Override + public void event(DeviceEvent event) { + topology = topologyService.currentTopology(); + processDeviceEvent(event); } } // Initial loading of the edge port cache. private void loadAllEdgePorts() { + topology = topologyService.currentTopology(); deviceService.getAvailableDevices().forEach(d -> deviceService.getPorts(d.id()) .forEach(p -> addEdgePort(new ConnectPoint(d.id(), p.number())))); } 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 5958d1f5..63ee03ec 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 @@ -436,7 +436,7 @@ public class FlowRuleManager 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()); + log.debug("Can't add missing flow rule:", e); continue; } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java index 5ecdc7a2..33200b1a 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java @@ -16,7 +16,6 @@ package org.onosproject.net.flowobjective.impl; import com.google.common.collect.Maps; -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; @@ -53,9 +52,11 @@ import org.onosproject.net.group.GroupService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import static com.google.common.base.Preconditions.checkNotNull; @@ -228,8 +229,10 @@ public class FlowObjectiveManager implements FlowObjectiveService { flowObjectiveStore.getNextGroup(fwd.nextId()) == null) { log.trace("Queuing forwarding objective for nextId {}", fwd.nextId()); // TODO: change to computeIfAbsent - Set<PendingNext> pnext = pendingForwards.putIfAbsent(fwd.nextId(), - Sets.newHashSet(new PendingNext(deviceId, fwd))); + Set<PendingNext> newset = Collections.newSetFromMap( + new ConcurrentHashMap<PendingNext, Boolean>()); + newset.add(new PendingNext(deviceId, fwd)); + Set<PendingNext> pnext = pendingForwards.putIfAbsent(fwd.nextId(), newset); if (pnext != null) { pnext.add(new PendingNext(deviceId, fwd)); } 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 ebf681a2..ff711a02 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 @@ -34,6 +34,7 @@ import org.onosproject.net.HostId; import org.onosproject.net.Link; import org.onosproject.net.LinkKey; import org.onosproject.net.NetworkResource; +import org.onosproject.net.PortNumber; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; @@ -302,11 +303,11 @@ public class ObjectiveTracker implements ObjectiveTrackerService { private class InternalResourceListener implements ResourceListener { @Override public void event(ResourceEvent event) { - Optional<Class<?>> linkEvent = event.subject().components().stream() + Optional<Class<?>> deviceEvent = event.subject().components().stream() .map(Object::getClass) - .filter(x -> x == LinkKey.class) + .filter(x -> x == PortNumber.class) .findFirst(); - if (linkEvent.isPresent()) { + if (deviceEvent.isPresent()) { executorService.execute(() -> { if (delegate == null) { return; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java index 718c7bbf..5549918c 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java @@ -15,6 +15,7 @@ */ package org.onosproject.net.intent.impl.compiler; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Activate; @@ -59,9 +60,9 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkNotNull; import static org.onosproject.net.LinkKey.linkKey; @@ -120,11 +121,16 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { return Collections.emptyMap(); } - List<ResourcePath> resources = labels.entrySet().stream() - .map(x -> ResourcePath.discrete(linkKey(x.getKey().src(), x.getKey().src()), x.getValue())) - .collect(Collectors.toList()); + // for short term solution: same label is used for both directions + // TODO: introduce the concept of Tx and Rx resources of a port + Set<ResourcePath> resources = labels.entrySet().stream() + .flatMap(x -> Stream.of( + ResourcePath.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue()), + ResourcePath.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue()) + )) + .collect(Collectors.toSet()); List<org.onosproject.net.newresource.ResourceAllocation> allocations = - resourceService.allocate(intent.id(), resources); + resourceService.allocate(intent.id(), ImmutableList.copyOf(resources)); if (allocations.isEmpty()) { Collections.emptyMap(); } @@ -135,20 +141,23 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { private Map<LinkKey, MplsLabel> findMplsLabels(Set<LinkKey> links) { Map<LinkKey, MplsLabel> labels = new HashMap<>(); for (LinkKey link : links) { - Optional<MplsLabel> label = findMplsLabel(link); - if (label.isPresent()) { - labels.put(link, label.get()); + Set<MplsLabel> forward = findMplsLabel(link.src()); + Set<MplsLabel> backward = findMplsLabel(link.dst()); + Set<MplsLabel> common = Sets.intersection(forward, backward); + if (common.isEmpty()) { + continue; } + labels.put(link, common.iterator().next()); } return labels; } - private Optional<MplsLabel> findMplsLabel(LinkKey link) { - return resourceService.getAvailableResources(ResourcePath.discrete(link)).stream() + private Set<MplsLabel> findMplsLabel(ConnectPoint cp) { + return resourceService.getAvailableResources(ResourcePath.discrete(cp.deviceId(), cp.port())).stream() .filter(x -> x.last() instanceof MplsLabel) .map(x -> (MplsLabel) x.last()) - .findFirst(); + .collect(Collectors.toSet()); } private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) { 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 2941ddba..e017ac58 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 @@ -57,9 +57,9 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkArgument; -import static org.onosproject.net.LinkKey.linkKey; /** * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}. @@ -182,7 +182,10 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical IndexedLambda minLambda = findFirstLambda(lambdas); List<ResourcePath> lambdaResources = path.links().stream() - .map(x -> ResourcePath.discrete(linkKey(x.src(), x.dst()))) + .flatMap(x -> Stream.of( + ResourcePath.discrete(x.src().deviceId(), x.src().port()), + ResourcePath.discrete(x.dst().deviceId(), x.dst().port()) + )) .map(x -> x.child(minLambda)) .collect(Collectors.toList()); @@ -197,7 +200,10 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical private Set<IndexedLambda> findCommonLambdasOverLinks(List<Link> links) { return links.stream() - .map(x -> ResourcePath.discrete(linkKey(x.src(), x.dst()))) + .flatMap(x -> Stream.of( + ResourcePath.discrete(x.src().deviceId(), x.src().port()), + ResourcePath.discrete(x.dst().deviceId(), x.dst().port()) + )) .map(resourceService::getAvailableResources) .map(x -> Iterables.filter(x, r -> r.last() instanceof IndexedLambda)) .map(x -> Iterables.transform(x, r -> (IndexedLambda) r.last())) diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java index 801092f4..ff74dbde 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java @@ -38,6 +38,7 @@ import org.slf4j.Logger; public final class BasicLinkOperator implements ConfigOperator { private static final long DEF_BANDWIDTH = -1L; + private static final double DEF_METRIC = -1; private static final Duration DEF_DURATION = Duration.ofNanos(-1L); private static final Logger log = getLogger(BasicLinkOperator.class); @@ -77,6 +78,9 @@ public final class BasicLinkOperator implements ConfigOperator { */ public static SparseAnnotations combine(BasicLinkConfig cfg, SparseAnnotations an) { DefaultAnnotations.Builder b = DefaultAnnotations.builder(); + if (cfg.metric() != DEF_METRIC) { + b.set(AnnotationKeys.METRIC, String.valueOf(cfg.metric())); + } if (cfg.latency() != DEF_DURATION) { b.set(AnnotationKeys.LATENCY, cfg.latency().toString()); } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java index 4fb0d7ba..bfc6a995 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java @@ -16,19 +16,32 @@ package org.onosproject.net.newresource.impl; import com.google.common.collect.Lists; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.VlanId; +import org.onlab.util.ItemNotFoundException; import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; import org.onosproject.net.Port; import org.onosproject.net.OchPort; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; import org.onosproject.net.TributarySlot; import org.onosproject.net.OduSignalType; +import org.onosproject.net.behaviour.LambdaQuery; +import org.onosproject.net.behaviour.MplsQuery; +import org.onosproject.net.behaviour.VlanQuery; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.newresource.ResourceAdminService; import org.onosproject.net.newresource.ResourcePath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.List; +import java.util.SortedSet; import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -42,12 +55,19 @@ final class ResourceDeviceListener implements DeviceListener { private static final Logger log = LoggerFactory.getLogger(ResourceDeviceListener.class); + private static final int MAX_VLAN_ID = VlanId.MAX_VLAN; + private static final List<VlanId> ENTIRE_VLAN_IDS = getEntireVlans(); + + private static final int MAX_MPLS_LABEL = 1048576; + private static final List<MplsLabel> ENTIRE_MPLS_LABELS = getEntireMplsLabels(); + private static final int TOTAL_ODU2_TRIBUTARY_SLOTS = 8; private static final int TOTAL_ODU4_TRIBUTARY_SLOTS = 80; private static final List<TributarySlot> ENTIRE_ODU2_TRIBUTARY_SLOTS = getEntireOdu2TributarySlots(); private static final List<TributarySlot> ENTIRE_ODU4_TRIBUTARY_SLOTS = getEntireOdu4TributarySlots(); private final ResourceAdminService adminService; + private final DriverService driverService; private final ExecutorService executor; /** @@ -56,8 +76,10 @@ final class ResourceDeviceListener implements DeviceListener { * @param adminService instance invoked to register resources * @param executor executor used for processing resource registration */ - ResourceDeviceListener(ResourceAdminService adminService, ExecutorService executor) { + ResourceDeviceListener(ResourceAdminService adminService, DriverService driverService, + ExecutorService executor) { this.adminService = checkNotNull(adminService); + this.driverService = checkNotNull(driverService); this.executor = checkNotNull(executor); } @@ -95,6 +117,26 @@ final class ResourceDeviceListener implements DeviceListener { executor.submit(() -> { adminService.registerResources(portPath); + // for VLAN IDs + if (isVlanEnabled(device.id(), port.number())) { + adminService.registerResources(Lists.transform(ENTIRE_VLAN_IDS, portPath::child)); + } + + // for MPLS labels + if (isMplsEnabled(device.id(), port.number())) { + adminService.registerResources(Lists.transform(ENTIRE_MPLS_LABELS, portPath::child)); + } + + // for Lambdas + SortedSet<OchSignal> lambdas = queryLambdas(device.id(), port.number()); + if (!lambdas.isEmpty()) { + adminService.registerResources(lambdas.stream() + .map(portPath::child) + .collect(Collectors.toList())); + } + + // for Tributary slots + // TODO: need to define Behaviour to make a query about OCh port switch (port.type()) { case OCH: // register ODU TributarySlots against the OCH port @@ -124,15 +166,68 @@ final class ResourceDeviceListener implements DeviceListener { executor.submit(() -> adminService.unregisterResources(resource)); } + private SortedSet<OchSignal> queryLambdas(DeviceId did, PortNumber port) { + try { + DriverHandler handler = driverService.createHandler(did); + if (handler == null) { + return Collections.emptySortedSet(); + } + LambdaQuery query = handler.behaviour(LambdaQuery.class); + return query.queryLambdas(port); + } catch (ItemNotFoundException e) { + return Collections.emptySortedSet(); + } + } + + private boolean isVlanEnabled(DeviceId device, PortNumber port) { + try { + DriverHandler handler = driverService.createHandler(device); + if (handler == null) { + return false; + } + + VlanQuery query = handler.behaviour(VlanQuery.class); + return query != null && query.isEnabled(port); + } catch (ItemNotFoundException e) { + return false; + } + } + + private boolean isMplsEnabled(DeviceId device, PortNumber port) { + try { + DriverHandler handler = driverService.createHandler(device); + if (handler == null) { + return false; + } + + MplsQuery query = handler.behaviour(MplsQuery.class); + return query != null && query.isEnabled(port); + } catch (ItemNotFoundException e) { + return false; + } + } + + private static List<VlanId> getEntireVlans() { + return IntStream.range(0, MAX_VLAN_ID) + .mapToObj(x -> VlanId.vlanId((short) x)) + .collect(Collectors.toList()); + } + + private static List<MplsLabel> getEntireMplsLabels() { + // potentially many objects are created + return IntStream.range(0, MAX_MPLS_LABEL) + .mapToObj(MplsLabel::mplsLabel) + .collect(Collectors.toList()); + } + private static List<TributarySlot> getEntireOdu2TributarySlots() { return IntStream.rangeClosed(1, TOTAL_ODU2_TRIBUTARY_SLOTS) - .mapToObj(x -> TributarySlot.of(x)) + .mapToObj(TributarySlot::of) .collect(Collectors.toList()); } private static List<TributarySlot> getEntireOdu4TributarySlots() { return IntStream.rangeClosed(1, TOTAL_ODU4_TRIBUTARY_SLOTS) - .mapToObj(x -> TributarySlot.of(x)) + .mapToObj(TributarySlot::of) .collect(Collectors.toList()); } - } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceLinkListener.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceLinkListener.java deleted file mode 100644 index 9d2e06f5..00000000 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceLinkListener.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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.newresource.impl; - -import com.google.common.collect.Lists; -import org.onlab.packet.MplsLabel; -import org.onlab.packet.VlanId; -import org.onlab.util.ItemNotFoundException; -import org.onosproject.net.ConnectPoint; -import org.onosproject.net.Link; -import org.onosproject.net.LinkKey; -import org.onosproject.net.behaviour.MplsQuery; -import org.onosproject.net.behaviour.VlanQuery; -import org.onosproject.net.driver.DriverHandler; -import org.onosproject.net.driver.DriverService; -import org.onosproject.net.link.LinkEvent; -import org.onosproject.net.link.LinkListener; -import org.onosproject.net.newresource.ResourceAdminService; -import org.onosproject.net.newresource.ResourcePath; - -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * An implementation of LinkListener registering links as resources. - */ -final class ResourceLinkListener implements LinkListener { - - private static final int TOTAL_VLANS = 1024; - private static final List<VlanId> ENTIRE_VLAN_IDS = getEntireVlans(); - - private static final int TOTAL_MPLS_LABELS = 1048576; - private static final List<MplsLabel> ENTIRE_MPLS_LABELS = getEntireMplsLabels(); - - private final ResourceAdminService adminService; - private final DriverService driverService; - private final ExecutorService executor; - - /** - * Creates an instance with the specified ResourceAdminService and ExecutorService. - * - * @param adminService instance invoked to register resources - * @param driverService driver service instance - * @param executor executor used for processing resource registration - */ - ResourceLinkListener(ResourceAdminService adminService, DriverService driverService, ExecutorService executor) { - this.adminService = checkNotNull(adminService); - this.driverService = checkNotNull(driverService); - this.executor = checkNotNull(executor); - } - - @Override - public void event(LinkEvent event) { - Link link = event.subject(); - switch (event.type()) { - case LINK_ADDED: - registerLinkResource(link); - break; - case LINK_REMOVED: - unregisterLinkResource(link); - break; - default: - break; - } - } - - private void registerLinkResource(Link link) { - executor.submit(() -> { - // register the link - LinkKey linkKey = LinkKey.linkKey(link); - adminService.registerResources(ResourcePath.discrete(linkKey)); - - ResourcePath linkPath = ResourcePath.discrete(linkKey); - // register VLAN IDs against the link - if (isEnabled(link, this::isVlanEnabled)) { - adminService.registerResources(Lists.transform(ENTIRE_VLAN_IDS, linkPath::child)); - } - - // register MPLS labels against the link - if (isEnabled(link, this::isMplsEnabled)) { - adminService.registerResources(Lists.transform(ENTIRE_MPLS_LABELS, linkPath::child)); - } - }); - } - - private void unregisterLinkResource(Link link) { - LinkKey linkKey = LinkKey.linkKey(link); - executor.submit(() -> adminService.unregisterResources(ResourcePath.discrete(linkKey))); - } - - private boolean isEnabled(Link link, Predicate<ConnectPoint> predicate) { - return predicate.test(link.src()) && predicate.test(link.dst()); - } - - private boolean isVlanEnabled(ConnectPoint cp) { - try { - DriverHandler handler = driverService.createHandler(cp.deviceId()); - if (handler == null) { - return false; - } - - VlanQuery query = handler.behaviour(VlanQuery.class); - return query != null && query.isEnabled(cp.port()); - } catch (ItemNotFoundException e) { - return false; - } - } - - private boolean isMplsEnabled(ConnectPoint cp) { - try { - DriverHandler handler = driverService.createHandler(cp.deviceId()); - if (handler == null) { - return false; - } - - MplsQuery query = handler.behaviour(MplsQuery.class); - return query != null && query.isEnabled(cp.port()); - } catch (ItemNotFoundException e) { - return false; - } - } - - private static List<VlanId> getEntireVlans() { - return IntStream.range(0, TOTAL_VLANS) - .mapToObj(x -> VlanId.vlanId((short) x)) - .collect(Collectors.toList()); - } - - private static List<MplsLabel> getEntireMplsLabels() { - // potentially many objects are created - return IntStream.range(0, TOTAL_MPLS_LABELS) - .mapToObj(MplsLabel::mplsLabel) - .collect(Collectors.toList()); - } -} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java index 143f8c2b..e8042661 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java @@ -24,8 +24,6 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; import org.onosproject.net.driver.DriverService; -import org.onosproject.net.link.LinkListener; -import org.onosproject.net.link.LinkService; import org.onosproject.net.newresource.ResourceAdminService; import java.util.concurrent.ExecutorService; @@ -49,25 +47,18 @@ public final class ResourceRegistrar { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected DeviceService deviceService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkService linkService; - private DeviceListener deviceListener; - private LinkListener linkListener; private final ExecutorService executor = Executors.newSingleThreadExecutor(groupedThreads("onos/resource", "registrar")); @Activate public void activate() { - deviceListener = new ResourceDeviceListener(adminService, executor); + deviceListener = new ResourceDeviceListener(adminService, driverService, executor); deviceService.addListener(deviceListener); - linkListener = new ResourceLinkListener(adminService, driverService, executor); - linkService.addListener(linkListener); } @Deactivate public void deactivate() { deviceService.removeListener(deviceListener); - linkService.removeListener(linkListener); } } diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java index 319412fe..70be5deb 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java @@ -22,7 +22,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.onosproject.common.event.impl.TestEventDispatcher; -import org.onosproject.event.Event; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DefaultPort; import org.onosproject.net.Device; @@ -31,15 +30,17 @@ import org.onosproject.net.NetTestTools; import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceServiceAdapter; import org.onosproject.net.edge.EdgePortEvent; import org.onosproject.net.edge.EdgePortListener; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.link.LinkListener; +import org.onosproject.net.link.LinkServiceAdapter; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketServiceAdapter; import org.onosproject.net.topology.Topology; -import org.onosproject.net.topology.TopologyEvent; import org.onosproject.net.topology.TopologyListener; import org.onosproject.net.topology.TopologyServiceAdapter; @@ -58,7 +59,6 @@ import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_ADDED; import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_REMOVED; import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED; -import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED; /** * Test of the edge port manager. Each device has ports '0' through 'numPorts - 1' @@ -74,6 +74,8 @@ public class EdgeManagerTest { private final Map<DeviceId, Device> devices = Maps.newConcurrentMap(); private Set<OutboundPacket> packets = Sets.newConcurrentHashSet(); private final EdgePortListener testListener = new TestListener(events); + private TestLinkManager testLinkManager; + private TestDeviceManager testDeviceManager; private TestTopologyManager testTopologyManager; @Before @@ -82,8 +84,11 @@ public class EdgeManagerTest { injectEventDispatcher(mgr, new TestEventDispatcher()); testTopologyManager = new TestTopologyManager(infrastructurePorts); mgr.topologyService = testTopologyManager; - mgr.deviceService = new TestDeviceManager(devices); + testDeviceManager = new TestDeviceManager(devices); + mgr.deviceService = testDeviceManager; mgr.packetService = new TestPacketManager(); + testLinkManager = new TestLinkManager(); + mgr.linkService = testLinkManager; mgr.activate(); mgr.addListener(testListener); @@ -108,11 +113,11 @@ public class EdgeManagerTest { assertFalse("no ports expected", mgr.getEdgePoints().iterator().hasNext()); assertFalse("Expected isEdge to return false", - mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1))); + mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1))); removeInfraPort(NetTestTools.connectPoint(Integer.toString(1), 1)); assertTrue("Expected isEdge to return false", - mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1))); + mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1))); } @Test @@ -121,69 +126,57 @@ public class EdgeManagerTest { ConnectPoint testPoint, referencePoint; //Testing link removal - List<Event> eventsToAdd = Lists.newArrayList(); - eventsToAdd.add(new LinkEvent(LINK_REMOVED, NetTestTools.link("a", 1, "b", 2))); - TopologyEvent event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); + testLinkManager.listener.event(new LinkEvent(LINK_REMOVED, NetTestTools.link("a", 1, "b", 2))); assertTrue("The list contained an unexpected number of events", events.size() == 2); assertTrue("The first element is of the wrong type.", - events.get(0).type() == EDGE_PORT_ADDED); - assertTrue("The second element is of the wrong type.", - events.get(1).type() == EDGE_PORT_ADDED); + events.get(0).type() == EDGE_PORT_ADDED); testPoint = events.get(0).subject(); referencePoint = NetTestTools.connectPoint("a", 1); assertTrue("The port numbers of the first element are incorrect", - testPoint.port().toLong() == referencePoint.port().toLong()); + testPoint.port().toLong() == referencePoint.port().toLong()); assertTrue("The device id of the first element is incorrect.", - testPoint.deviceId().equals(referencePoint.deviceId())); + testPoint.deviceId().equals(referencePoint.deviceId())); testPoint = events.get(1).subject(); referencePoint = NetTestTools.connectPoint("b", 2); assertTrue("The port numbers of the second element are incorrect", - testPoint.port().toLong() == referencePoint.port().toLong()); + testPoint.port().toLong() == referencePoint.port().toLong()); assertTrue("The device id of the second element is incorrect.", - testPoint.deviceId().equals(referencePoint.deviceId())); + testPoint.deviceId().equals(referencePoint.deviceId())); //Rebroadcast event to ensure it results in no additional events - testTopologyManager.listener.event(event); + testLinkManager.listener.event(new LinkEvent(LINK_REMOVED, NetTestTools.link("a", 1, "b", 2))); assertTrue("The list contained an unexpected number of events", events.size() == 2); //Testing link adding when links to remove exist - eventsToAdd.clear(); events.clear(); - eventsToAdd.add(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2))); - event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); + testLinkManager.listener.event(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2))); assertTrue("The list contained an unexpected number of events", events.size() == 2); assertTrue("The first element is of the wrong type.", - events.get(0).type() == EDGE_PORT_REMOVED); + events.get(0).type() == EDGE_PORT_REMOVED); assertTrue("The second element is of the wrong type.", - events.get(1).type() == EDGE_PORT_REMOVED); + events.get(1).type() == EDGE_PORT_REMOVED); testPoint = events.get(0).subject(); referencePoint = NetTestTools.connectPoint("a", 1); assertTrue("The port numbers of the first element are incorrect", - testPoint.port().toLong() == referencePoint.port().toLong()); + testPoint.port().toLong() == referencePoint.port().toLong()); assertTrue("The device id of the first element is incorrect.", - testPoint.deviceId().equals(referencePoint.deviceId())); + testPoint.deviceId().equals(referencePoint.deviceId())); testPoint = events.get(1).subject(); referencePoint = NetTestTools.connectPoint("b", 2); assertTrue("The port numbers of the second element are incorrect", - testPoint.port().toLong() == referencePoint.port().toLong()); + testPoint.port().toLong() == referencePoint.port().toLong()); assertTrue("The device id of the second element is incorrect.", - testPoint.deviceId().equals(referencePoint.deviceId())); + testPoint.deviceId().equals(referencePoint.deviceId())); //Apparent duplicate of previous method tests removal when the elements have already been removed - eventsToAdd.clear(); events.clear(); - eventsToAdd.add(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2))); - event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); - + testLinkManager.listener.event(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2))); assertTrue("The list should contain no events, the removed elements don't exist.", events.size() == 0); } @@ -192,8 +185,7 @@ public class EdgeManagerTest { //Setup Device referenceDevice; - TopologyEvent event; - List<Event> eventsToAdd = Lists.newArrayList(); + DeviceEvent event; int numDevices = 10; int numInfraPorts = 5; totalPorts = 10; @@ -201,14 +193,13 @@ public class EdgeManagerTest { //Test response to device added events referenceDevice = NetTestTools.device("1"); - eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, referenceDevice, - new DefaultPort(referenceDevice, PortNumber.portNumber(1), true))); - event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); + event = new DeviceEvent(DEVICE_ADDED, referenceDevice, + new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)); + testDeviceManager.listener.event(event); //Check that ports were populated correctly assertTrue("Unexpected number of new ports added", - mgr.deviceService.getPorts(NetTestTools.did("1")).size() == 10); + mgr.deviceService.getPorts(NetTestTools.did("1")).size() == 10); //Check that of the ten ports the half that are infrastructure ports aren't added assertEquals("Unexpected number of new edge ports added", (totalPorts - numInfraPorts), events.size()); @@ -219,15 +210,15 @@ public class EdgeManagerTest { //Names here are irrelevant, the first 5 ports are populated as infrastructure, 6-10 are edge for (int index = 0; index < events.size(); index++) { assertEquals("Port added had unexpected port number.", - events.get(index).subject().port(), - NetTestTools.connectPoint("a", index + numInfraPorts + 1).port()); + events.get(index).subject().port(), + NetTestTools.connectPoint("a", index + numInfraPorts + 1).port()); } events.clear(); //Repost the event to test repeated posts - testTopologyManager.listener.event(event); + testDeviceManager.listener.event(event); assertEquals("The redundant notification should not have created additional notifications.", - 0, events.size()); + 0, events.size()); //Calculate the size of the returned iterable of edge points. Iterable<ConnectPoint> pts = mgr.getEdgePoints(); Iterator pointIterator = pts.iterator(); @@ -238,45 +229,41 @@ public class EdgeManagerTest { assertEquals("Unexpected number of edge points", totalPorts - numInfraPorts, count); //Testing device removal events.clear(); - eventsToAdd.clear(); - eventsToAdd.add(new DeviceEvent(DEVICE_REMOVED, referenceDevice, - new DefaultPort(referenceDevice, PortNumber.portNumber(1), true))); - event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); + event = (new DeviceEvent(DEVICE_REMOVED, referenceDevice, + new DefaultPort(referenceDevice, PortNumber.portNumber(1), true))); + testDeviceManager.listener.event(event); assertEquals("There should be five new events from removal of edge points", - totalPorts - numInfraPorts, events.size()); + totalPorts - numInfraPorts, events.size()); for (int index = 0; index < events.size(); index++) { //Assert that the correct port numbers were removed in the correct order assertEquals("Port removed had unexpected port number.", - events.get(index).subject().port(), - (NetTestTools.connectPoint("a", index + numInfraPorts + 1).port())); + events.get(index).subject().port(), + (NetTestTools.connectPoint("a", index + numInfraPorts + 1).port())); //Assert that the events are of the correct type assertEquals("Unexpected type of event", events.get(index).type(), EDGE_PORT_REMOVED); } events.clear(); //Rebroadcast event to check that it triggers no new behavior - testTopologyManager.listener.event(event); + testDeviceManager.listener.event(event); assertEquals("Rebroadcast of removal event should not produce additional events", - 0, events.size()); + 0, events.size()); //Testing device status change, changed from unavailable to available events.clear(); - eventsToAdd.clear(); //Make sure that the devicemanager shows the device as available. addDevice(referenceDevice, "1", 5); devices.put(referenceDevice.id(), referenceDevice); - eventsToAdd.add(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, referenceDevice)); - event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); + event = new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, referenceDevice); + testDeviceManager.listener.event(event); //An earlier setup set half of the reference device ports to infrastructure assertEquals("An unexpected number of events were generated.", totalPorts - numInfraPorts, events.size()); for (int i = 0; i < 5; i++) { assertEquals("The event was not of the right type", events.get(i).type(), EDGE_PORT_ADDED); } events.clear(); - testTopologyManager.listener.event(event); + testDeviceManager.listener.event(event); assertEquals("No events should have been generated for a set of existing ports.", 0, events.size()); //Test removal when state changes when the device becomes unavailable @@ -288,21 +275,20 @@ public class EdgeManagerTest { no events will be generated since no ports will be provided in getPorts() to EdgeManager. */ alwaysReturnPorts = true; - testTopologyManager.listener.event(event); + testDeviceManager.listener.event(event); alwaysReturnPorts = false; assertEquals("An unexpected number of events were created.", totalPorts - numInfraPorts, events.size()); for (int i = 0; i < 5; i++) { EdgePortEvent edgeEvent = events.get(i); assertEquals("The event is of an unexpected type.", - EdgePortEvent.Type.EDGE_PORT_REMOVED, edgeEvent.type()); + EdgePortEvent.Type.EDGE_PORT_REMOVED, edgeEvent.type()); assertEquals("The event pertains to an unexpected port", PortNumber.portNumber(i + numInfraPorts + 1), - edgeEvent.subject().port()); + edgeEvent.subject().port()); } } @Test public void testInternalCache() { - List<Event> eventsToAdd = Lists.newArrayList(); int numDevices = 10; //Number of infrastructure ports per device int numPorts = 5; @@ -312,11 +298,8 @@ public class EdgeManagerTest { for (int i = 0; i < numDevices; i++) { Device newDevice = NetTestTools.device(Integer.toString(i)); devices.put(newDevice.id(), newDevice); - eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, newDevice)); + testDeviceManager.listener.event(new DeviceEvent(DEVICE_ADDED, newDevice)); } - TopologyEvent event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); - //Check all ports have correct designations ConnectPoint testPoint; for (int deviceNum = 0; deviceNum < numDevices; deviceNum++) { @@ -334,7 +317,7 @@ public class EdgeManagerTest { count++; } assertEquals("There are an unexpeceted number of edge points returned.", - (totalPorts - numPorts) * numDevices, count); + (totalPorts - numPorts) * numDevices, count); for (int deviceNumber = 0; deviceNumber < numDevices; deviceNumber++) { count = 0; for (ConnectPoint ignored : mgr.getEdgePoints(NetTestTools.did("1"))) { @@ -349,8 +332,7 @@ public class EdgeManagerTest { public void testEmit() { byte[] arr = new byte[10]; Device referenceDevice; - TopologyEvent event; - List<Event> eventsToAdd = Lists.newArrayList(); + DeviceEvent event; int numDevices = 10; int numInfraPorts = 5; totalPorts = 10; @@ -360,16 +342,16 @@ public class EdgeManagerTest { } for (int i = 0; i < numDevices; i++) { referenceDevice = NetTestTools.device(Integer.toString(i)); - eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, referenceDevice, - new DefaultPort(referenceDevice, PortNumber.portNumber(1), true))); + testDeviceManager.listener.event(new DeviceEvent(DEVICE_ADDED, referenceDevice, + new DefaultPort(referenceDevice, + PortNumber.portNumber(1), + true))); } - event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd); - testTopologyManager.listener.event(event); mgr.emitPacket(ByteBuffer.wrap(arr), Optional.<TrafficTreatment>empty()); assertEquals("There were an unexpected number of emitted packets", - (totalPorts - numInfraPorts) * numDevices, packets.size()); + (totalPorts - numInfraPorts) * numDevices, packets.size()); Iterator<OutboundPacket> packetIter = packets.iterator(); OutboundPacket packet; while (packetIter.hasNext()) { @@ -381,7 +363,7 @@ public class EdgeManagerTest { mgr.emitPacket(NetTestTools.did(Integer.toString(1)), ByteBuffer.wrap(arr), Optional.<TrafficTreatment>empty()); assertEquals("Unexpected number of outbound packets were emitted.", - totalPorts - numInfraPorts, packets.size()); + totalPorts - numInfraPorts, packets.size()); packetIter = packets.iterator(); while (packetIter.hasNext()) { packet = packetIter.next(); @@ -455,6 +437,7 @@ public class EdgeManagerTest { } private class TestDeviceManager extends DeviceServiceAdapter { + private DeviceListener listener; private Map<DeviceId, Device> devices; @@ -490,6 +473,17 @@ public class EdgeManagerTest { public Iterable<Device> getAvailableDevices() { return devices.values(); } + + + @Override + public void addListener(DeviceListener listener) { + this.listener = listener; + } + + @Override + public void removeListener(DeviceListener listener) { + this.listener = null; + } } private class TestPacketManager extends PacketServiceAdapter { @@ -499,6 +493,15 @@ public class EdgeManagerTest { } } + private class TestLinkManager extends LinkServiceAdapter { + private LinkListener listener; + + @Override + public void addListener(LinkListener listener) { + this.listener = listener; + } + } + private class TestListener implements EdgePortListener { private List<EdgePortEvent> events; diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java index eb7f2ccd..7cee0d0e 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java @@ -29,8 +29,10 @@ import org.onlab.junit.TestUtils.TestUtilsException; import org.onosproject.core.IdGenerator; import org.onosproject.event.Event; import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; import org.onosproject.net.Link; import org.onosproject.net.NetworkResource; +import org.onosproject.net.PortNumber; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.intent.Intent; @@ -52,7 +54,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; -import static org.onosproject.net.LinkKey.linkKey; import static org.onosproject.net.newresource.ResourceEvent.Type.*; import static org.onosproject.net.NetTestTools.APP_ID; import static org.onosproject.net.NetTestTools.device; @@ -231,7 +232,7 @@ public class ObjectiveTrackerTest { @Test public void testResourceEvent() throws Exception { ResourceEvent event = new ResourceEvent(RESOURCE_ADDED, - ResourcePath.discrete(linkKey(link("a", 1, "b", 1)))); + ResourcePath.discrete(DeviceId.deviceId("a"), PortNumber.portNumber(1))); resourceListener.event(event); assertThat( diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java index c6d300c9..af2bb74d 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java @@ -20,6 +20,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.Maps; + import org.onlab.util.HexString; import org.onlab.util.SharedExecutors; import org.onlab.util.Tools; @@ -33,6 +34,7 @@ import org.onosproject.store.service.Versioned; import org.slf4j.Logger; import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -92,18 +94,25 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V private static final String ERROR_NULL_KEY = "Key cannot be null"; private static final String ERROR_NULL_VALUE = "Null values are not allowed"; - private final LoadingCache<K, String> keyCache = CacheBuilder.newBuilder() + // String representation of serialized byte[] -> original key Object + private final LoadingCache<String, K> keyCache = CacheBuilder.newBuilder() .softValues() - .build(new CacheLoader<K, String>() { + .build(new CacheLoader<String, K>() { @Override - public String load(K key) { - return HexString.toHexString(serializer.encode(key)); + public K load(String key) { + return serializer.decode(HexString.fromHexString(key)); } }); + protected String sK(K key) { + String s = HexString.toHexString(serializer.encode(key)); + keyCache.put(s, key); + return s; + } + protected K dK(String key) { - return serializer.decode(HexString.fromHexString(key)); + return keyCache.getUnchecked(key); } public DefaultAsyncConsistentMap(String name, @@ -207,7 +216,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V public CompletableFuture<Boolean> containsKey(K key) { checkNotNull(key, ERROR_NULL_KEY); final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_KEY); - return database.mapContainsKey(name, keyCache.getUnchecked(key)) + return database.mapContainsKey(name, sK(key)) .whenComplete((r, e) -> timer.stop(e)); } @@ -223,7 +232,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V public CompletableFuture<Versioned<V>> get(K key) { checkNotNull(key, ERROR_NULL_KEY); final MeteringAgent.Context timer = monitor.startTimer(GET); - return database.mapGet(name, keyCache.getUnchecked(key)) + return database.mapGet(name, sK(key)) .whenComplete((r, e) -> timer.stop(e)) .thenApply(v -> v != null ? v.map(serializer::decode) : null); } @@ -328,10 +337,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V public CompletableFuture<Set<K>> keySet() { final MeteringAgent.Context timer = monitor.startTimer(KEY_SET); return database.mapKeySet(name) - .thenApply(s -> s - .stream() - .map(this::dK) - .collect(Collectors.toSet())) + .thenApply(s -> newMappingKeySet(s)) .whenComplete((r, e) -> timer.stop(e)); } @@ -351,10 +357,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V final MeteringAgent.Context timer = monitor.startTimer(ENTRY_SET); return database.mapEntrySet(name) .whenComplete((r, e) -> timer.stop(e)) - .thenApply(s -> s - .stream() - .map(this::mapRawEntry) - .collect(Collectors.toSet())); + .thenApply(s -> newMappingEntrySet(s)); } @Override @@ -413,17 +416,31 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V checkIfUnmodifiable(); } + private Set<K> newMappingKeySet(Set<String> s) { + return new MappingSet<>(s, Collections::unmodifiableSet, + this::sK, this::dK); + } + + private Set<Entry<K, Versioned<V>>> newMappingEntrySet(Set<Entry<String, Versioned<byte[]>>> s) { + return new MappingSet<>(s, Collections::unmodifiableSet, + this::reverseMapRawEntry, this::mapRawEntry); + } + private Map.Entry<K, Versioned<V>> mapRawEntry(Map.Entry<String, Versioned<byte[]>> e) { return Maps.immutableEntry(dK(e.getKey()), e.getValue().<V>map(serializer::decode)); } + private Map.Entry<String, Versioned<byte[]>> reverseMapRawEntry(Map.Entry<K, Versioned<V>> e) { + return Maps.immutableEntry(sK(e.getKey()), e.getValue().map(serializer::encode)); + } + private CompletableFuture<UpdateResult<K, V>> updateAndGet(K key, Match<V> oldValueMatch, Match<Long> oldVersionMatch, V value) { beforeUpdate(key); return database.mapUpdate(name, - keyCache.getUnchecked(key), + sK(key), oldValueMatch.map(serializer::encode), oldVersionMatch, value == null ? null : serializer.encode(value)) diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MappingSet.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MappingSet.java new file mode 100644 index 00000000..9bf80a73 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MappingSet.java @@ -0,0 +1,131 @@ +/* + * 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 java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.google.common.collect.Iterators; + +/** + * Set view backed by Set with element type {@code <BACK>} but returns + * element as {@code <OUT>} for convenience. + * + * @param <BACK> Backing {@link Set} element type. + * MappingSet will follow this type's equality behavior. + * @param <OUT> external facing element type. + * MappingSet will ignores equality defined by this type. + */ +class MappingSet<BACK, OUT> implements Set<OUT> { + + private final Set<BACK> backedSet; + private final Function<OUT, BACK> toBack; + private final Function<BACK, OUT> toOut; + + public MappingSet(Set<BACK> backedSet, + Function<Set<BACK>, Set<BACK>> supplier, + Function<OUT, BACK> toBack, Function<BACK, OUT> toOut) { + this.backedSet = supplier.apply(backedSet); + this.toBack = toBack; + this.toOut = toOut; + } + + @Override + public int size() { + return backedSet.size(); + } + + @Override + public boolean isEmpty() { + return backedSet.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return backedSet.contains(toBack.apply((OUT) o)); + } + + @Override + public Iterator<OUT> iterator() { + return Iterators.transform(backedSet.iterator(), toOut::apply); + } + + @Override + public Object[] toArray() { + return backedSet.stream() + .map(toOut) + .toArray(); + } + + @Override + public <T> T[] toArray(T[] a) { + return backedSet.stream() + .map(toOut) + .toArray(size -> { + if (size < a.length) { + return (T[]) new Object[size]; + } else { + Arrays.fill(a, null); + return a; + } + }); + } + + @Override + public boolean add(OUT e) { + return backedSet.add(toBack.apply(e)); + } + + @Override + public boolean remove(Object o) { + return backedSet.remove(toBack.apply((OUT) o)); + } + + @Override + public boolean containsAll(Collection<?> c) { + return c.stream() + .map(e -> toBack.apply((OUT) e)) + .allMatch(backedSet::contains); + } + + @Override + public boolean addAll(Collection<? extends OUT> c) { + return backedSet.addAll(c.stream().map(toBack).collect(Collectors.toList())); + } + + @Override + public boolean retainAll(Collection<?> c) { + return backedSet.retainAll(c.stream() + .map(x -> toBack.apply((OUT) x)) + .collect(Collectors.toList())); + } + + @Override + public boolean removeAll(Collection<?> c) { + return backedSet.removeAll(c.stream() + .map(x -> toBack.apply((OUT) x)) + .collect(Collectors.toList())); + } + + @Override + public void clear() { + backedSet.clear(); + } +} 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 83319c3e..cc32a735 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 @@ -350,7 +350,7 @@ public class DistributedGroupStore // Check if a group is existing with the same key Group existingGroup = getGroup(groupDesc.deviceId(), groupDesc.appCookie()); if (existingGroup != null) { - log.warn("Group already exists with the same key {} in dev:{} with id:{}", + log.warn("Group already exists with the same key {} in dev:{} with id:0x{}", groupDesc.appCookie(), groupDesc.deviceId(), Integer.toHexString(existingGroup.id().id())); return; 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/DistributedHostStore.java index 20124576..836a3c22 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/DistributedHostStore.java @@ -15,26 +15,8 @@ */ package org.onosproject.store.host.impl; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static org.onosproject.net.DefaultAnnotations.merge; -import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; -import static org.onosproject.net.host.HostEvent.Type.HOST_MOVED; -import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED; -import static org.onosproject.net.host.HostEvent.Type.HOST_UPDATED; -import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; -import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; -import static org.slf4j.LoggerFactory.getLogger; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Predicate; -import java.util.stream.Collectors; - +import com.google.common.collect.ImmutableSet; +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; @@ -60,22 +42,34 @@ import org.onosproject.net.host.HostStoreDelegate; import org.onosproject.net.provider.ProviderId; import org.onosproject.store.AbstractStore; import org.onosproject.store.serializers.KryoNamespaces; -import org.onosproject.store.service.EventuallyConsistentMap; -import org.onosproject.store.service.EventuallyConsistentMapEvent; -import org.onosproject.store.service.EventuallyConsistentMapListener; -import org.onosproject.store.service.LogicalClockService; +import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.MapEvent; +import org.onosproject.store.service.MapEventListener; +import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; import org.slf4j.Logger; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.onosproject.net.DefaultAnnotations.merge; +import static org.onosproject.net.host.HostEvent.Type.*; +import static org.slf4j.LoggerFactory.getLogger; /** * Manages the inventory of hosts using a {@code EventuallyConsistentMap}. */ @Component(immediate = true) @Service -public class ECHostStore +public class DistributedHostStore extends AbstractStore<HostEvent, HostStoreDelegate> implements HostStore { @@ -84,15 +78,13 @@ public class ECHostStore @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected StorageService storageService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LogicalClockService clockService; - - private EventuallyConsistentMap<HostId, DefaultHost> hosts; + private ConsistentMap<HostId, DefaultHost> host; + private Map<HostId, DefaultHost> hosts; private final ConcurrentHashMap<HostId, DefaultHost> prevHosts = new ConcurrentHashMap<>(); - private EventuallyConsistentMapListener<HostId, DefaultHost> hostLocationTracker = + private MapEventListener<HostId, DefaultHost> hostLocationTracker = new HostLocationTracker(); @Activate @@ -100,21 +92,22 @@ public class ECHostStore KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder() .register(KryoNamespaces.API); - hosts = storageService.<HostId, DefaultHost>eventuallyConsistentMapBuilder() + host = storageService.<HostId, DefaultHost>consistentMapBuilder() .withName("onos-hosts") - .withSerializer(hostSerializer) - .withTimestampProvider((k, v) -> clockService.getTimestamp()) + .withRelaxedReadConsistency() + .withSerializer(Serializer.using(hostSerializer.build())) .build(); - hosts.addListener(hostLocationTracker); + hosts = host.asJavaMap(); + + host.addListener(hostLocationTracker); log.info("Started"); } @Deactivate public void deactivate() { - hosts.removeListener(hostLocationTracker); - hosts.destroy(); + host.removeListener(hostLocationTracker); prevHosts.clear(); log.info("Stopped"); @@ -249,11 +242,11 @@ public class ECHostStore return collection.stream().filter(predicate).collect(Collectors.toSet()); } - private class HostLocationTracker implements EventuallyConsistentMapListener<HostId, DefaultHost> { + private class HostLocationTracker implements MapEventListener<HostId, DefaultHost> { @Override - public void event(EventuallyConsistentMapEvent<HostId, DefaultHost> event) { - DefaultHost host = checkNotNull(event.value()); - if (event.type() == PUT) { + public void event(MapEvent<HostId, DefaultHost> event) { + DefaultHost host = checkNotNull(event.value().value()); + if (event.type() == MapEvent.Type.INSERT) { Host prevHost = prevHosts.put(host.id(), host); if (prevHost == null) { notifyDelegate(new HostEvent(HOST_ADDED, host)); @@ -262,7 +255,7 @@ public class ECHostStore } else if (!Objects.equals(prevHost, host)) { notifyDelegate(new HostEvent(HOST_UPDATED, host, prevHost)); } - } else if (event.type() == REMOVE) { + } else if (event.type() == MapEvent.Type.REMOVE) { if (prevHosts.remove(host.id()) != null) { notifyDelegate(new HostEvent(HOST_REMOVED, host)); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/proxyarp/impl/DistributedProxyArpStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/proxyarp/impl/DistributedProxyArpStore.java index 851185b5..4d7e7f33 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/proxyarp/impl/DistributedProxyArpStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/proxyarp/impl/DistributedProxyArpStore.java @@ -113,7 +113,7 @@ public class DistributedProxyArpStore implements ProxyArpStore { @Override public void forward(ConnectPoint outPort, Host subject, ByteBuffer packet) { - NodeId nodeId = mastershipService.getMasterFor(outPort.deviceId()); + /*NodeId nodeId = mastershipService.getMasterFor(outPort.deviceId()); if (nodeId.equals(localNodeId)) { if (delegate != null) { delegate.emitResponse(outPort, packet); @@ -122,7 +122,10 @@ public class DistributedProxyArpStore implements ProxyArpStore { log.info("Forwarding ARP response from {} to {}", subject.id(), outPort); commService.unicast(new ArpResponseMessage(outPort, subject, packet.array()), ARP_RESPONSE_MESSAGE, serializer::encode, nodeId); - } + }*/ + //FIXME: Code above may be unnecessary and therefore cluster messaging + // and pendingMessages could be pruned as well. + delegate.emitResponse(outPort, packet); } @Override 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 da4e3cc4..2641635d 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 @@ -15,44 +15,43 @@ */ package org.onosproject.store.topology.impl; -import static com.google.common.base.Preconditions.checkArgument; -import static org.onlab.util.Tools.isNullOrEmpty; -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; - 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; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; +import org.onlab.graph.GraphPathSearch; import org.onlab.util.KryoNamespace; +import org.onosproject.cfg.ComponentConfigService; import org.onosproject.common.DefaultTopology; import org.onosproject.event.Event; import org.onosproject.mastership.MastershipService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; -import org.onosproject.net.DisjointPath; +import org.onosproject.net.device.DeviceService; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.topology.ClusterId; import org.onosproject.net.topology.DefaultGraphDescription; +import org.onosproject.net.topology.GeoDistanceLinkWeight; import org.onosproject.net.topology.GraphDescription; import org.onosproject.net.topology.LinkWeight; +import org.onosproject.net.topology.MetricLinkWeight; +import org.onosproject.net.topology.PathAdminService; import org.onosproject.net.topology.Topology; import org.onosproject.net.topology.TopologyCluster; +import org.onosproject.net.topology.TopologyEdge; import org.onosproject.net.topology.TopologyEvent; import org.onosproject.net.topology.TopologyGraph; import org.onosproject.net.topology.TopologyStore; import org.onosproject.net.topology.TopologyStoreDelegate; +import org.onosproject.net.topology.TopologyVertex; import org.onosproject.store.AbstractStore; import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.EventuallyConsistentMap; @@ -60,8 +59,23 @@ import org.onosproject.store.service.EventuallyConsistentMapEvent; import org.onosproject.store.service.EventuallyConsistentMapListener; import org.onosproject.store.service.LogicalClockService; import org.onosproject.store.service.StorageService; +import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; +import java.util.Collections; +import java.util.Dictionary; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.onlab.util.Tools.get; +import static org.onlab.util.Tools.isNullOrEmpty; +import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED; +import static org.slf4j.LoggerFactory.getLogger; + /** * Manages inventory of topology snapshots using trivial in-memory * structures implementation. @@ -73,9 +87,12 @@ import org.slf4j.Logger; @Service public class DistributedTopologyStore extends AbstractStore<TopologyEvent, TopologyStoreDelegate> - implements TopologyStore { + implements TopologyStore, PathAdminService { private final Logger log = getLogger(getClass()); + + private static final String FORMAT = "Settings: linkWeightFunction={}"; + private volatile DefaultTopology current = new DefaultTopology(ProviderId.NONE, new DefaultGraphDescription(0L, System.currentTimeMillis(), @@ -91,6 +108,21 @@ public class DistributedTopologyStore @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected MastershipService mastershipService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService configService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + private static final String HOP_COUNT = "hopCount"; + private static final String LINK_METRIC = "linkMetric"; + private static final String GEO_DISTANCE = "geoDistance"; + + private static final String DEFAULT_LINK_WEIGHT_FUNCTION = "hopCount"; + @Property(name = "linkWeightFunction", value = DEFAULT_LINK_WEIGHT_FUNCTION, + label = "Default link-weight function: hopCount, linkMetric, geoDistance") + private String linkWeightFunction = DEFAULT_LINK_WEIGHT_FUNCTION; + // Cluster root to broadcast points bindings to allow convergence to // a shared broadcast tree; node that is the master of the cluster root // is the primary. @@ -100,7 +132,8 @@ public class DistributedTopologyStore new InternalBroadcastPointListener(); @Activate - public void activate() { + protected void activate() { + configService.registerProperties(getClass()); KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder() .register(KryoNamespaces.API); @@ -114,12 +147,30 @@ public class DistributedTopologyStore } @Deactivate - public void deactivate() { + protected void deactivate() { + configService.unregisterProperties(getClass(), false); broadcastPoints.removeListener(listener); broadcastPoints.destroy(); log.info("Stopped"); } + @Modified + protected void modified(ComponentContext context) { + Dictionary<?, ?> properties = context.getProperties(); + + String newLinkWeightFunction = get(properties, "linkWeightFunction"); + if (newLinkWeightFunction != null && + !Objects.equals(newLinkWeightFunction, linkWeightFunction)) { + linkWeightFunction = newLinkWeightFunction; + LinkWeight weight = linkWeightFunction.equals(LINK_METRIC) ? + new MetricLinkWeight() : + linkWeightFunction.equals(GEO_DISTANCE) ? + new GeoDistanceLinkWeight(deviceService) : null; + setDefaultLinkWeight(weight); + } + log.info(FORMAT, linkWeightFunction); + } + @Override public Topology currentTopology() { return current; @@ -263,6 +314,16 @@ public class DistributedTopologyStore return (DefaultTopology) topology; } + @Override + public void setDefaultLinkWeight(LinkWeight linkWeight) { + DefaultTopology.setDefaultLinkWeight(linkWeight); + } + + @Override + public void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch) { + DefaultTopology.setDefaultGraphPathSearch(graphPathSearch); + } + private class InternalBroadcastPointListener implements EventuallyConsistentMapListener<DeviceId, Set<ConnectPoint>> { @Override diff --git a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMapTest.java b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMapTest.java new file mode 100644 index 00000000..3f6402c5 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMapTest.java @@ -0,0 +1,369 @@ +/* + * 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 java.util.Collections.unmodifiableCollection; +import static java.util.Collections.unmodifiableSet; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import net.kuujo.copycat.Task; +import net.kuujo.copycat.cluster.Cluster; +import net.kuujo.copycat.resource.ResourceState; + +/** + * + */ +public class DefaultAsyncConsistentMapTest { + + private static final ApplicationId APP_ID = new DefaultApplicationId(42, "what"); + + private static final TestData KEY1A = new TestData("One", "a"); + private static final TestData KEY1B = new TestData("One", "b"); + + private static final TestData VALUE2A = new TestData("Two", "a"); + private static final TestData VALUE2B = new TestData("Two", "b"); + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testKeySet() throws Exception { + DefaultAsyncConsistentMap<TestData, TestData> map; + String name = "map_name"; + Database database = new TestDatabase(); + Serializer serializer = Serializer.forTypes(TestData.class); + + map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer, + false, false, false); + map.put(KEY1A, VALUE2A); + map.put(KEY1B, VALUE2A); + + Set<TestData> set = map.keySet().get(); + assertEquals("Should contain 2 keys", + 2, set.size()); + assertThat(set.contains(KEY1A), is(true)); + assertThat(set.contains(KEY1B), is(true)); + assertThat(set.contains(new TestData("One", "a")), is(true)); + } + + @Test + public void testEntrySet() throws Exception { + DefaultAsyncConsistentMap<TestData, TestData> map; + String name = "map_name"; + Database database = new TestDatabase(); + Serializer serializer = Serializer.forTypes(TestData.class); + + map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer, + false, false, false); + map.put(KEY1A, VALUE2A); + map.put(KEY1B, VALUE2A); + + assertEquals("Should contain 2 entry", + 2, + map.entrySet().get().size()); + } + + /** + * Object to be used as a test data. + * + * {@link Object#equals(Object)} use only part of it's fields. + * + * As a result there can be 2 instances which the + * serialized bytes are not-equal but + * {@link Object#equals(Object)}-wise they are equal. + */ + public static class TestData { + + private final String theKey; + + @SuppressWarnings("unused") + private final String notUsedForEquals; + + public TestData(String theKey, String notUsedForEquals) { + this.theKey = theKey; + this.notUsedForEquals = notUsedForEquals; + } + + @Override + public int hashCode() { + return Objects.hashCode(theKey); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestData) { + TestData that = (TestData) obj; + return Objects.equals(this.theKey, that.theKey); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("theKey", theKey) + .add("notUsedForEquals", notUsedForEquals) + .toString(); + } + } + + /** + * {@link Database} implementation for testing. + * + * There is only 1 backing Map, {@code mapName} will be ignored. + */ + public class TestDatabase implements Database { + + Map<String, Versioned<byte[]>> map = new ConcurrentHashMap<>(); + + @Override + public CompletableFuture<Set<String>> maps() { + return CompletableFuture.completedFuture(ImmutableSet.of()); + } + + @Override + public CompletableFuture<Map<String, Long>> counters() { + return CompletableFuture.completedFuture(ImmutableMap.of()); + } + + @Override + public CompletableFuture<Integer> mapSize(String mapName) { + return CompletableFuture.completedFuture(map.size()); + } + + @Override + public CompletableFuture<Boolean> mapIsEmpty(String mapName) { + return CompletableFuture.completedFuture(map.isEmpty()); + } + + @Override + public CompletableFuture<Boolean> mapContainsKey(String mapName, + String key) { + return CompletableFuture.completedFuture(map.containsKey(key)); + } + + @Override + public CompletableFuture<Boolean> mapContainsValue(String mapName, + byte[] value) { + return CompletableFuture.completedFuture(map.containsValue(value)); + } + + @Override + public CompletableFuture<Versioned<byte[]>> mapGet(String mapName, + String key) { + return CompletableFuture.completedFuture(map.get(key)); + } + + @Override + public synchronized CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(String mapName, + String key, + Match<byte[]> valueMatch, + Match<Long> versionMatch, + byte[] value) { + + boolean updated = false; + final Versioned<byte[]> oldValue; + final Versioned<byte[]> newValue; + + Versioned<byte[]> old = map.getOrDefault(key, new Versioned<byte[]>(null, 0)); + if (valueMatch.matches(old.value()) && versionMatch.matches(old.version())) { + updated = true; + oldValue = old; + newValue = new Versioned<>(value, old.version() + 1); + map.put(key, newValue); + } else { + updated = false; + oldValue = old; + newValue = old; + } + return CompletableFuture.completedFuture( + Result.ok(new UpdateResult<String, byte[]>(updated, + mapName, key, oldValue, newValue))); + } + + @Override + public CompletableFuture<Result<Void>> mapClear(String mapName) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Set<String>> mapKeySet(String mapName) { + return CompletableFuture.completedFuture(unmodifiableSet(map.keySet())); + } + + @Override + public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) { + return CompletableFuture.completedFuture(unmodifiableCollection(map.values())); + } + + @Override + public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) { + return CompletableFuture.completedFuture(unmodifiableSet(map.entrySet())); + } + + @Override + public CompletableFuture<Long> counterAddAndGet(String counterName, + long delta) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Long> counterGetAndAdd(String counterName, + long delta) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Void> counterSet(String counterName, + long value) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Boolean> counterCompareAndSet(String counterName, + long expectedValue, + long update) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Long> counterGet(String counterName) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Long> queueSize(String queueName) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Void> queuePush(String queueName, + byte[] entry) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<byte[]> queuePop(String queueName) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<byte[]> queuePeek(String queueName) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<CommitResponse> prepareAndCommit(Transaction transaction) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Boolean> prepare(Transaction transaction) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<CommitResponse> commit(Transaction transaction) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Boolean> rollback(Transaction transaction) { + throw new UnsupportedOperationException(); + } + + @Override + public String name() { + return "name"; + } + + @Override + public ResourceState state() { + return ResourceState.HEALTHY; + } + + @Override + public Cluster cluster() { + throw new UnsupportedOperationException(); + } + + @Override + public Database addStartupTask(Task<CompletableFuture<Void>> task) { + throw new UnsupportedOperationException(); + } + + @Override + public Database addShutdownTask(Task<CompletableFuture<Void>> task) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture<Database> open() { + return CompletableFuture.completedFuture(this); + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public CompletableFuture<Void> close() { + return CompletableFuture.completedFuture(null); + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void registerConsumer(Consumer<StateMachineUpdate> consumer) { + } + + @Override + public void unregisterConsumer(Consumer<StateMachineUpdate> consumer) { + } + } + +} diff --git a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/ecmap/EventuallyConsistentMapImplTest.java b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/ecmap/EventuallyConsistentMapImplTest.java index ef8d9924..b74aa370 100644 --- a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/ecmap/EventuallyConsistentMapImplTest.java +++ b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/ecmap/EventuallyConsistentMapImplTest.java @@ -42,12 +42,13 @@ import org.onosproject.cluster.ControllerNode; import org.onosproject.cluster.DefaultControllerNode; import org.onosproject.cluster.NodeId; import org.onosproject.event.AbstractEvent; -import org.onosproject.persistence.impl.PersistenceManager; +import org.onosproject.persistence.PersistenceService; import org.onosproject.store.Timestamp; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.cluster.messaging.ClusterCommunicationServiceAdapter; import org.onosproject.store.cluster.messaging.MessageSubject; import org.onosproject.store.impl.LogicalTimestamp; +import org.onosproject.store.persistence.TestPersistenceService; import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.serializers.KryoSerializer; import org.onosproject.store.service.EventuallyConsistentMap; @@ -82,7 +83,7 @@ public class EventuallyConsistentMapImplTest { private EventuallyConsistentMap<String, String> ecMap; - private PersistenceManager persistenceService; + private PersistenceService persistenceService; private ClusterService clusterService; private ClusterCommunicationService clusterCommunicator; private SequentialClockService<String, String> clockService; @@ -138,8 +139,7 @@ public class EventuallyConsistentMapImplTest { clusterCommunicator = createMock(ClusterCommunicationService.class); - persistenceService = new PersistenceManager(); - persistenceService.activate(); + persistenceService = new TestPersistenceService(); // Add expectation for adding cluster message subscribers which // delegate to our ClusterCommunicationService implementation. This // allows us to get a reference to the map's internal cluster message 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/DistributedHostStoreTest.java index a7077a81..0732126d 100644 --- 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/DistributedHostStoreTest.java @@ -27,8 +27,6 @@ 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; @@ -37,9 +35,9 @@ import java.util.Set; /** * Tests for the ECHostStore. */ -public class ECHostStoreTest extends TestCase { +public class DistributedHostStoreTest extends TestCase { - private ECHostStore ecXHostStore; + private DistributedHostStore ecXHostStore; private static final HostId HOSTID = HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a")); @@ -50,10 +48,9 @@ public class ECHostStoreTest extends TestCase { @Before public void setUp() { - ecXHostStore = new ECHostStore(); + ecXHostStore = new DistributedHostStore(); ecXHostStore.storageService = new TestStorageService(); - ecXHostStore.clockService = new TestLogicalClockService(); ecXHostStore.activate(); } @@ -83,13 +80,4 @@ public class ECHostStoreTest extends TestCase { 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/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java index 3428bce1..05c577c0 100644 --- a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java @@ -47,7 +47,6 @@ import static org.slf4j.LoggerFactory.getLogger; public class PersistenceManager implements PersistenceService { private static final String DATABASE_PATH = "../data/localDB"; - private static final String ENCLOSING_FOLDER = "../data"; static final String MAP_PREFIX = "map:"; diff --git a/framework/src/onos/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java b/framework/src/onos/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java index 45b4da1a..7df518e2 100644 --- a/framework/src/onos/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java +++ b/framework/src/onos/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java @@ -374,13 +374,13 @@ public class KryoSerializerTest { @Test public void testResourcePath() { - testSerializedEquals(ResourcePath.discrete(LinkKey.linkKey(CP1, CP2), VLAN1)); + testSerializedEquals(ResourcePath.discrete(DID1, P1, VLAN1)); } @Test public void testResourceAllocation() { testSerializedEquals(new org.onosproject.net.newresource.ResourceAllocation( - ResourcePath.discrete(LinkKey.linkKey(CP1, CP2), VLAN1), + ResourcePath.discrete(DID1, P1, VLAN1), IntentId.valueOf(30))); } |