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;