ONOS-5215 protection behaviour
Change-Id: Ia76c034fa9bb95d0048828f6bb80ac965dd053d8
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectedTransportEndpointDescription.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectedTransportEndpointDescription.java
new file mode 100644
index 0000000..2e563de
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectedTransportEndpointDescription.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.behaviour.protection;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.onosproject.net.DeviceId;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Configuration for a protected transport entity endpoint.
+ */
+@Beta
+@Immutable
+public class ProtectedTransportEndpointDescription {
+
+ /**
+ * List of underlying transport entity endpoints in priority order.
+ */
+ private final List<TransportEndpointDescription> paths;
+
+ /**
+ * DeviceId of remote peer of this endpoint.
+ */
+ private final DeviceId peer;
+
+ // Note: Do we need opaque configuration?
+ // ⇨ For device specific configuration,
+ // NO, it should be expressed as org.onosproject.net.config.Config
+ // For information needed for caller to correlate Intent to description,
+ // use fingerprint
+ /**
+ * Caller specified fingerprint to identify this protected transport entity.
+ * <p>
+ * Virtual port corresponding to this description,
+ * should have annotations {@link ProtectionConfigBehaviour#FINGERPRINT}
+ * with the value specified by this field.
+ */
+ private final String fingerprint;
+
+
+ /**
+ * Constructor.
+ *
+ * @param paths {@link TransportEndpointDescription}s
+ * @param peer remote peer of this endpoint
+ * @param fingerprint to identify this protected transport entity.
+ */
+ protected ProtectedTransportEndpointDescription(List<TransportEndpointDescription> paths,
+ DeviceId peer,
+ String fingerprint) {
+ this.paths = ImmutableList.copyOf(paths);
+ this.peer = checkNotNull(peer);
+ this.fingerprint = checkNotNull(fingerprint);
+ }
+
+ /**
+ * Returns List of underlying transport entity endpoints in priority order.
+ *
+ * @return the transport entity endpoint descriptions
+ */
+ public List<TransportEndpointDescription> paths() {
+ return paths;
+ }
+
+ /**
+ * Returns DeviceId of remote peer of this endpoint.
+ * @return the peer
+ */
+ public DeviceId peer() {
+ return peer;
+ }
+
+ /**
+ * Returns fingerprint to identify this protected transport entity.
+ *
+ * @return the fingerprint
+ */
+ public String fingerprint() {
+ return fingerprint;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("paths", paths)
+ .add("peer", peer)
+ .add("fingerprint", fingerprint)
+ .toString();
+ }
+
+ /**
+ * Creates a {@link ProtectedTransportEndpointDescription}.
+ *
+ * @param paths {@link TransportEndpointDescription}s forming protection
+ * @param did DeviceId of remote peer of this endpoint.
+ * @param fingerprint opaque fingerprint object. must be serializable.
+ * @return {@link TransportEndpointDescription}
+ */
+ public static final ProtectedTransportEndpointDescription
+ of(List<TransportEndpointDescription> paths,
+ DeviceId did,
+ String fingerprint) {
+ return new ProtectedTransportEndpointDescription(paths, did, fingerprint);
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectedTransportEndpointState.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectedTransportEndpointState.java
new file mode 100644
index 0000000..f4e8cb5
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectedTransportEndpointState.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.behaviour.protection;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * State of protected path endpoint.
+ */
+@Beta
+@Immutable
+public class ProtectedTransportEndpointState {
+
+ /**
+ * Active path is currently unknown.
+ */
+ public static final int ACTIVE_UNKNOWN = -1;
+
+ /**
+ * List of underlying path/flow in priority order.
+ */
+ private final List<TransportEndpointState> pathStates;
+
+ /**
+ * {@link #pathStates} index of the active Path or {@link #ACTIVE_UNKNOWN}.
+ */
+ private final int activePathIndex;
+
+ // TODO Do we need reference to the config object?
+ private final ProtectedTransportEndpointDescription description;
+
+
+ protected ProtectedTransportEndpointState(ProtectedTransportEndpointDescription description,
+ List<TransportEndpointState> pathStates,
+ int activePathIndex) {
+ this.description = checkNotNull(description);
+ this.pathStates = ImmutableList.copyOf(pathStates);
+ this.activePathIndex = activePathIndex;
+ }
+
+ /**
+ * Returns the description of this ProtectedPathEndPoint.
+ *
+ * @return the description
+ */
+ public ProtectedTransportEndpointDescription description() {
+ return description;
+ }
+
+ /**
+ * Returns the {@link TransportEndpointState}s forming the ProtectedPathEndPoint.
+ *
+ * @return the pathStates
+ */
+ public List<TransportEndpointState> pathStates() {
+ return pathStates;
+ }
+
+ /**
+ * Returns the index of the working Path in {@link #pathStates()} List or
+ * {@link #ACTIVE_UNKNOWN}.
+ *
+ * @return the activePathIndex
+ */
+ public int workingPathIndex() {
+ return activePathIndex;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("pathState", pathStates)
+ .add("activePathIndex", activePathIndex)
+ .add("description", description)
+ .toString();
+ }
+
+ /**
+ * Returns {@link ProtectedTransportEndpointState} builder.
+ *
+ * @return builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private List<TransportEndpointState> pathStates;
+ private int activePathIndex = ACTIVE_UNKNOWN;
+ private ProtectedTransportEndpointDescription description;
+
+ /**
+ * Copies all the fields from {@code src}.
+ *
+ * @param src object to copy from
+ * @return this
+ */
+ public Builder copyFrom(ProtectedTransportEndpointState src) {
+ this.pathStates = src.pathStates();
+ this.activePathIndex = src.workingPathIndex();
+ this.description = src.description();
+ return this;
+ }
+
+ /**
+ * Sets the path states.
+ *
+ * @param pathStates the path states
+ * @return this
+ */
+ public Builder withPathStates(List<TransportEndpointState> pathStates) {
+ this.pathStates = pathStates;
+ return this;
+ }
+
+ /**
+ * Sets the activePathIndex.
+ *
+ * @param activePathIndex the activePathIndex
+ * @return this
+ */
+ public Builder withActivePathIndex(int activePathIndex) {
+ this.activePathIndex = activePathIndex;
+ return this;
+ }
+
+ /**
+ * Sets the description.
+ *
+ * @param description of this {@link ProtectedTransportEndpointState}
+ * @return this
+ */
+ public Builder withDescription(ProtectedTransportEndpointDescription description) {
+ this.description = description;
+ return this;
+ }
+
+ /**
+ * Builds {@link ProtectedTransportEndpointState}.
+ *
+ * @return {@link ProtectedTransportEndpointState}
+ */
+ public ProtectedTransportEndpointState build() {
+ checkNotNull(description, "description field is mandatory");
+ checkNotNull(pathStates, "pathStates field is mandatory");
+ checkArgument(activePathIndex < pathStates.size(),
+ "Invalid active path index %s > %s",
+ activePathIndex, pathStates.size());
+ return new ProtectedTransportEndpointState(description, pathStates, activePathIndex);
+ }
+
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectionConfigBehaviour.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectionConfigBehaviour.java
new file mode 100644
index 0000000..d56a969
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectionConfigBehaviour.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.behaviour.protection;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.driver.HandlerBehaviour;
+
+import com.google.common.annotations.Beta;
+
+
+/**
+ * Behaviour for configuring Device triggered protection mechanism.
+ * <p>
+ * <b>Protected transport entity model</b><br>
+ * <pre>
+ * {@literal
+ * - ProtectedTransportEndpoint
+ * +- TransportEndpoint - working transport entity/path
+ * |
+ * +- TransportEndpoint - standby transport entity/path
+ * ⋮
+ * }
+ * </pre>
+ * ProtectedTransportEndpoint is the entity representing the transport entity endpoint.
+ * Traffic flowing into the protected transport endpoint will flow
+ * through one of it's underlying TransportEndpoint, (=active transport entity).
+ *
+ * After successful creation of ProtectedPathEndpoint, implementation is expected
+ * to advertise virtual Port corresponding to the ProtectedPathEndpoint created.
+ */
+@Beta
+public interface ProtectionConfigBehaviour extends HandlerBehaviour {
+
+ /**
+ * Annotation key for virtual Port.
+ */
+ static String FINGERPRINT = "protection:fingerprint";
+
+ // Implementation is expected to
+ // - Create logical entity representing protection group
+ // - Expose (virtual) Port via Device Subsystem
+ // - implementation of FlowRuleProvider and similar should translate
+ // request forwarding from/to virtual port to corresponding configuration
+ // stitching protection group.
+ /**
+ * Creates protected path endpoint.
+ *
+ * @param configuration {@link ProtectedTransportEndpointDescription}
+ * @return {@link ConnectPoint} for the virtual Port added on success,
+ * or exceptionally return {@link ProtectionException} as cause on error.
+ */
+ CompletableFuture<ConnectPoint>
+ createProtectionEndpoint(ProtectedTransportEndpointDescription configuration);
+
+ /**
+ * Updates protected path endpoint configuration.
+ *
+ * @param identifier {@link ConnectPoint} for the virtual Port representing
+ * protected path endpoint
+ * @param configuration {@link ProtectedTransportEndpointDescription}
+ * @return {@code identifier} on success,
+ * or exceptionally return {@link ProtectionException} as cause on error.
+ */
+ CompletableFuture<ConnectPoint>
+ updateProtectionEndpoint(ConnectPoint identifier,
+ ProtectedTransportEndpointDescription configuration);
+
+ /**
+ * Deletes protected path endpoint.
+ *
+ * @param identifier {@link ConnectPoint} for the virtual Port representing
+ * protected path endpoint
+ * @return true if successfully removed, false otherwise.
+ */
+ // TODO Should we return Boolean or instead return Void and fail exceptionally?
+ CompletableFuture<Boolean>
+ deleteProtectionEndpoint(ConnectPoint identifier);
+
+ /**
+ * Retrieves {@link ProtectedTransportEndpointDescription}s on the Device.
+ *
+ * @return {@link ProtectedTransportEndpointDescription}s on the Device
+ */
+ CompletableFuture<Map<ConnectPoint, ProtectedTransportEndpointDescription>>
+ getProtectionEndpointConfigs();
+
+ /**
+ * Retrieves {@link ProtectedTransportEndpointDescription} with specified ID.
+ *
+ * @param identifier {@link ConnectPoint} for the virtual Port representing
+ * protected path endpoint to retrieve
+ * @return {@link ProtectedTransportEndpointDescription} found or null
+ */
+ default CompletableFuture<ProtectedTransportEndpointDescription>
+ getProtectionEndpointConfig(ConnectPoint identifier) {
+ return getProtectionEndpointConfigs().thenApply(m -> m.get(identifier));
+ }
+
+ /**
+ * Retrieves {@link ProtectedTransportEndpointState}s on the Device.
+ *
+ * @return {@link ProtectedTransportEndpointState}s on the Device
+ */
+ CompletableFuture<Map<ConnectPoint, ProtectedTransportEndpointState>>
+ getProtectionEndpointStates();
+
+ /**
+ * Retrieves {@link ProtectedTransportEndpointState} on the Device.
+ *
+ * @param identifier {@link ConnectPoint} for the virtual Port representing
+ * protected path endpoint to retrieve
+ * @return {@link ProtectedTransportEndpointState} found or null
+ */
+ default CompletableFuture<ProtectedTransportEndpointState>
+ getProtectionEndpointState(ConnectPoint identifier) {
+ return getProtectionEndpointStates().thenApply(m -> m.get(identifier));
+ }
+
+ /**
+ * Retrieves ProtectedTansportEndpoint information
+ * (=virtual Port {@link ConnectPoint} and {@link ProtectedTransportEndpointState} pair)
+ * on the Device.
+ *
+ * @param fingerprint of the protected path endpoint to retrieve
+ * @return ProtectedTansportEndpoint information found or null
+ */
+ default CompletableFuture<Map.Entry<ConnectPoint, ProtectedTransportEndpointState>>
+ getProtectionEndpoint(String fingerprint) {
+ return getProtectionEndpointStates()
+ .thenApply(Map::entrySet)
+ .thenApply(Set::stream)
+ .thenApply(s ->
+ s.filter(e -> fingerprint.equals(e.getValue().description().fingerprint()))
+ .findFirst().orElse(null)
+ );
+ }
+
+ /**
+ * Attempts to manually switch working path to the one specified by {@code index}.
+ *
+ * @param identifier {@link ConnectPoint} for the virtual Port representing
+ * protected path endpoint
+ * @param index working path index to switch to
+ * @return Completes if request was accepted, fails exceptionally on error.
+ * Note: completion does not always assure working path has switched.
+ */
+ CompletableFuture<Void> switchWorkingPath(ConnectPoint identifier, int index);
+
+ // TODO How to let one listen to async events? e.g., working path changed event
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectionException.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectionException.java
new file mode 100644
index 0000000..10a4d06
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/ProtectionException.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.behaviour.protection;
+
+
+
+/**
+ * Base class for Protection related Exceptions.
+ */
+public abstract class ProtectionException extends Exception {
+
+ private static final long serialVersionUID = 5230741971525527020L;
+
+ /**
+ * Exception thrown when specified configuration was invalid.
+ */
+ public static class InvalidConfigException extends ProtectionException {
+
+ private static final long serialVersionUID = 6532157856911418461L;
+
+ /**
+ * {@link InvalidConfigException}.
+ */
+ public InvalidConfigException() {
+ }
+
+ /**
+ * {@link InvalidConfigException}.
+ *
+ * @param message describing error
+ */
+ public InvalidConfigException(String message) {
+ super(message);
+ }
+
+ /**
+ * {@link InvalidConfigException}.
+ *
+ * @param cause of this Exception
+ */
+ public InvalidConfigException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * {@link InvalidConfigException}.
+ *
+ * @param message describing error
+ * @param cause of this Exception
+ */
+ public InvalidConfigException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ /**
+ * Default constructor.
+ */
+ protected ProtectionException() {}
+
+ /**
+ * Creates an exception.
+ * @param message describing error
+ */
+ protected ProtectionException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates an exception.
+ * @param cause of this Exception
+ */
+ protected ProtectionException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates an exception.
+ * @param message describing error
+ * @param cause of this Exception
+ */
+ protected ProtectionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointDescription.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointDescription.java
new file mode 100644
index 0000000..fc3100d
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointDescription.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.behaviour.protection;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.onosproject.net.FilteredConnectPoint;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+
+/**
+ * Configuration for a underlying path endpoint, forming protected path.
+ */
+@Beta
+@Immutable
+public class TransportEndpointDescription {
+
+ // TODO is there a better field name for this?
+ // Only VLAN selector expected in practice for now.
+ private final FilteredConnectPoint output;
+
+ /**
+ * True if this endpoint is administratively enabled, false otherwise.
+ */
+ private final boolean enabled;
+
+ // Do we need opaque config per path/flow?
+ // ⇨ No it should probably be expressed as org.onosproject.net.config.Config
+
+ protected TransportEndpointDescription(FilteredConnectPoint output,
+ boolean enabled) {
+ this.output = checkNotNull(output);
+ this.enabled = enabled;
+ }
+
+ /**
+ * @return the output
+ */
+ public FilteredConnectPoint output() {
+ return output;
+ }
+
+ /**
+ * Returns administrative state.
+ *
+ * @return the enabled
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("output", output)
+ .add("enabled", enabled)
+ .toString();
+ }
+
+
+ /**
+ * Returns {@link TransportEndpointDescription} builder.
+ *
+ * @return the builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private FilteredConnectPoint output;
+ private boolean enabled = true;
+
+ /**
+ * Copies all the fields from {@code src}.
+ *
+ * @param src object to copy from
+ * @return this
+ */
+ public Builder copyFrom(TransportEndpointDescription src) {
+ this.output = src.output();
+ this.enabled = src.isEnabled();
+ return this;
+ }
+
+ /**
+ * Sets output configuration.
+ *
+ * @param output configuration to set
+ * @return this
+ */
+ public Builder withOutput(FilteredConnectPoint output) {
+ this.output = output;
+ return this;
+ }
+
+ /**
+ * Sets enabled state.
+ *
+ * @param enabled state to set
+ * @return this
+ */
+ public Builder withEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ /**
+ * Builds {@link TransportEndpointDescription}.
+ *
+ * @return {@link TransportEndpointDescription}
+ */
+ public TransportEndpointDescription build() {
+ checkNotNull(output, "output field is mandatory");
+ return new TransportEndpointDescription(output, enabled);
+ }
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointId.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointId.java
new file mode 100644
index 0000000..7cfd2ef
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointId.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.behaviour.protection;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.onlab.util.Identifier;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Identifier for a transport entity endpoint.
+ * <p>
+ * Identifier will be assigned by the implementation of this Behaviour.
+ * It must be unique within the Device.
+ */
+@Beta
+@Immutable
+public class TransportEndpointId extends Identifier<String> {
+
+ /**
+ * Creates a {@link TransportEndpointId} from given String.
+ *
+ * @param id identifier expressed in String
+ * @return {@link TransportEndpointId}
+ */
+ public static TransportEndpointId of(String id) {
+ return new TransportEndpointId(id);
+ }
+
+ protected TransportEndpointId(String id) {
+ super(id);
+ }
+
+ /*
+ * Constructor for serialization.
+ */
+ protected TransportEndpointId() {
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointState.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointState.java
new file mode 100644
index 0000000..8a2c49a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/TransportEndpointState.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.behaviour.protection;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.concurrent.Immutable;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * State of a underlying path endpoint, forming protected path.
+ */
+@Beta
+@Immutable
+public class TransportEndpointState {
+
+ /**
+ * ID assigned by the implementation.
+ */
+ private final TransportEndpointId id;
+
+ // meant to show liveness state by OAM probe, etc.
+ private final boolean live;
+
+ // TODO do we need opaque config here? ⇨ May be. Comments?
+ @Beta
+ private final Map<String, String> attributes;
+
+ // TODO Do we need reference to the config object?
+ private final TransportEndpointDescription description;
+
+ protected TransportEndpointState(TransportEndpointDescription description,
+ TransportEndpointId id,
+ boolean live,
+ Map<String, String> attributes) {
+ this.id = checkNotNull(id);
+ this.live = live;
+ this.description = checkNotNull(description);
+ this.attributes = ImmutableMap.copyOf(attributes);
+ }
+
+ /**
+ * Returns {@link TransportEndpointId}.
+ *
+ * @return identifier
+ */
+ public TransportEndpointId id() {
+ return id;
+ }
+
+ /**
+ * Returns liveness state of this endpoint.
+ *
+ * @return true if this endpoint is live.
+ */
+ public boolean isLive() {
+ return live;
+ }
+
+ /**
+ * Returns description associated to this state.
+ *
+ * @return the description
+ */
+ public TransportEndpointDescription description() {
+ return description;
+ }
+
+ /**
+ * Returns implementation defined attributes.
+ *
+ * @return the attributes
+ */
+ @Beta
+ public Map<String, String> attributes() {
+ return attributes;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("id", id)
+ .add("live", live)
+ .add("description", description)
+ .add("attributes", attributes)
+ .toString();
+ }
+
+ /**
+ * Returns {@link TransportEndpointState} builder.
+ *
+ * @return builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private TransportEndpointId id;
+ private boolean live;
+ private Map<String, String> attributes = new HashMap<>();
+ private TransportEndpointDescription description;
+
+ /**
+ * Copies all the fields from {@code src}.
+ *
+ * @param src object to copy from
+ * @return this
+ */
+ public Builder copyFrom(TransportEndpointState src) {
+ this.id = src.id();
+ this.live = src.isLive();
+ this.attributes.putAll(src.attributes());
+ this.description = src.description();
+ return this;
+ }
+
+ /**
+ * Sets id.
+ *
+ * @param id {@link TransportEndpointId}
+ * @return this
+ */
+ public Builder withId(TransportEndpointId id) {
+ this.id = checkNotNull(id);
+ return this;
+ }
+
+ /**
+ * Sets liveness state.
+ *
+ * @param live liveness state
+ * @return this
+ */
+ public Builder withLive(boolean live) {
+ this.live = live;
+ return this;
+ }
+
+ /**
+ * Sets the description.
+ *
+ * @param description description
+ * @return this
+ */
+ public Builder withDescription(TransportEndpointDescription description) {
+ this.description = checkNotNull(description);
+ return this;
+ }
+
+ /**
+ * Adds specified attributes.
+ *
+ * @param attributes to add
+ * @return this
+ */
+ public Builder addAttributes(Map<String, String> attributes) {
+ this.attributes.putAll(attributes);
+ return this;
+ }
+
+ /**
+ * Replaces attributes with the specified Map.
+ *
+ * @param attributes to add
+ * @return this
+ */
+ public Builder replaceAttributes(Map<String, String> attributes) {
+ this.attributes.clear();
+ return addAttributes(attributes);
+ }
+
+ /**
+ * Builds {@link TransportEndpointState}.
+ *
+ * @return {@link TransportEndpointState}
+ */
+ public TransportEndpointState build() {
+ checkNotNull(id, "id field is mandatory");
+ checkNotNull(description, "description field is mandatory");
+ return new TransportEndpointState(description, id, live, attributes);
+ }
+
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/protection/package-info.java b/core/api/src/main/java/org/onosproject/net/behaviour/protection/package-info.java
new file mode 100644
index 0000000..bd68fc2
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/protection/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Protection behaviour and related classes.
+ */
+package org.onosproject.net.behaviour.protection;