Detangling incubator: virtual nets, tunnels, resource labels, oh my
- virtual networking moved to /apps/virtual; with CLI & REST API
- tunnels and labels moved to /apps/tunnel; with CLI & REST API; UI disabled for now
- protobuf/models moved to /core/protobuf/models
- defunct grpc/rpc registry stuff left under /graveyard
- compile dependencies on /incubator moved to respective modules for compilation
- run-time dependencies will need to be re-tested for dependent apps
- /graveyard will be removed in not-too-distant future
Change-Id: I0a0b995c635487edcf95a352f50dd162186b0b39
diff --git a/core/api/src/main/java/org/onosproject/alarm/Alarm.java b/core/api/src/main/java/org/onosproject/alarm/Alarm.java
new file mode 100644
index 0000000..1460cc7
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/Alarm.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.net.DeviceId;
+
+/**
+ * Representation of an Alarm. At a given instant there can be only one alarm
+ * with the same deviceId + description + source combination.
+ */
+public interface Alarm {
+
+ /**
+ * Returns the unique alarm id within this ONOS instance.
+ *
+ * @return alarm identifier
+ */
+ AlarmId id();
+
+ /**
+ * The device to which this alarm is related.
+ *
+ * @return a device id
+ */
+ DeviceId deviceId();
+
+ /**
+ * Returns a description of alarm.
+ * <p>
+ * It may encapsulate Event Type as described by ITU Recommendation X.736
+ * ITU, Quoting https://tools.ietf.org/html/rfc3877 these include: other,
+ * communicationsAlarm, qualityOfServiceAlarm, processingErrorAlarm,
+ * equipmentAlarm, environmentalAlarm, integrityViolation,
+ * operationalViolation, physicalViolation,
+ * securityServiceOrMechanismViolation, timeDomainViolation
+ * <p>
+ * It may encapsulate Probable Cause as described by ITU Recommendation
+ * X.736 ITU, Quoting
+ * https://www.iana.org/assignments/ianaitualarmtc-mib/ianaitualarmtc-mib
+ * these include : aIS, callSetUpFailure, degradedSignal,
+ * farEndReceiverFailure, framingError, and hundreds more constants.
+ * <p>
+ * It may encapsulate a vendor-specific description of the underlying fault.
+ *
+ * @return description of alarm
+ */
+ String description();
+
+ /**
+ * Returns an entity within the context of this alarm's device. It may be
+ * null if deviceId sufficiently identifies the location. As an example, the
+ * source may indicate a port number
+ *
+ * @return source of alarm within the alarm's referenced Device.
+ */
+ AlarmEntityId source();
+
+ /**
+ * Returns the time when raised.
+ *
+ * @return time when raised, in milliseconds since start of epoch
+ */
+ long timeRaised();
+
+ /**
+ * Returns time at which the alarm was updated most recently, due to some
+ * change in the device, or ONOS. If the alarm has been cleared, this is the
+ * time at which the alarm was cleared.
+ *
+ * @return time when last updated, in milliseconds since start of epoch
+ */
+ long timeUpdated();
+
+ /**
+ * Returns the time when cleared. Null indicated no clear time, i.e. the
+ * alarm is still active.
+ *
+ * @return time when cleared, in milliseconds since start of epoch or null
+ * if uncleared.
+ */
+ Long timeCleared();
+
+ /**
+ * Returns the severity. Note, that cleared alarms may have EITHER
+ * SeverityLevel = CLEARED, or may be not present; both scenarios should be
+ * handled.
+ *
+ * @return severity of the alarm
+ */
+ SeverityLevel severity();
+
+ /**
+ * Returns true if alarm is service affecting Note: Whilst X.733 combines
+ * service-affecting state with severity (where severities of critical and
+ * major are deemed service-affecting) ONOS keeps these attributes separate.
+ *
+ * @return whether service affecting (true indicates it is)
+ */
+ boolean serviceAffecting();
+
+ /**
+ * Returns a flag to indicate if this alarm has been acknowledged. All
+ * alarms are unacknowledged until and unless an ONOS user takes action to
+ * indicate so.
+ *
+ * @return whether alarm is currently acknowledged (true indicates it is)
+ */
+ boolean acknowledged();
+
+ /**
+ * Returns a flag to indicate if this alarm has been cleared. All
+ * alarms are not cleared until and unless an ONOS user or app takes action to
+ * indicate so.
+ *
+ * @return whether alarm is currently cleared (true indicates it is)
+ */
+ default boolean cleared() {
+ return false;
+ }
+
+ /**
+ * Returns a flag to indicate if this alarm is manually-cleared by a user action within ONOS. Some stateless events
+ * e.g. backup-failure or upgrade-failure, may be mapped by ONOS to alarms, and these may be deemed manually-
+ * clearable. The more typical case is that an alarm represents a persistent fault on or related to a device and
+ * such alarms are never manually clearable, i.e. a configuration or operational state must occur for the alarm to
+ * clear.
+ *
+ * @return whether it may be cleared by a user action (true indicates it is)
+ */
+ boolean manuallyClearable();
+
+ /**
+ * Returns the user to whom this alarm is assigned; this is for future use
+ * and always returns null in this release. It is anticipated that in future ONOS
+ * releases, the existing JAAS user/key/role configuration will be extended
+ * to include a mechanism whereby some groups of users may allocate alarms
+ * to other users for bookkeeping and administrative purposes, and that ONOS
+ * will additionally provide a REST based mechanism, to retrieve from JAAS,
+ * the set of users to whom alarm assignment is possible for the current
+ * user.
+ *
+ * @return the assigned user; always null in this release.
+ */
+ String assignedUser();
+
+ /**
+ * Represents the severity level on an alarm, as per ITU-T X.733
+ * specifications.
+ * <p>
+ * The precedence is as follows for : Critical > Major > Minor > Warning.
+ */
+ enum SeverityLevel {
+
+ /**
+ * From X.733: This indicates the clearing of one or more previously
+ * reported alarms. This alarm clears all alarms for this managed object
+ * that have the same Alarm type, Probable cause and Specific problems
+ * (if given). Multiple associated notifications may be cleared by using
+ * the Correlated notifications parameter (defined below). This
+ * Recommendation | International Standard does not require that the
+ * clearing of previously reported alarms be reported. Therefore, a
+ * managing system cannot assume that the absence of an alarm with the
+ * Cleared severity level means that the condition that caused the
+ * generation of previous alarms is still present. Managed object
+ * definers shall state if, and under which conditions, the Cleared
+ * severity level is used.
+ */
+ CLEARED,
+ /**
+ * From X.733: This indicates that the severity level cannot be
+ * determined.
+ */
+ INDETERMINATE,
+ /**
+ * From X.733: This indicates that a service affecting condition has
+ * occurred and an immediate corrective action is required. Such a
+ * severity can be reported, for example, when a managed object becomes
+ * totally out of service and its capability must be restored.
+ */
+ CRITICAL,
+ /**
+ * X.733 definition: This indicates that a service affecting condition
+ * has developed and an urgent corrective action is required. Such a
+ * severity can be reported, for example, when there is a severe
+ * degradation in the capability of the managed object and its full
+ * capability must be restored.
+ */
+ MAJOR,
+ /**
+ * From X.733: This indicates the existence of a non-service affecting
+ * fault condition and that corrective action should be taken in order
+ * to prevent a more serious (for example, service affecting) fault.
+ * Such a severity can be reported, for example, when the detected alarm
+ * condition is not currently degrading the capacity of the managed
+ * object.
+ */
+ MINOR,
+ /**
+ * From X.733: This indicates the detection of a potential or impending
+ * service affecting fault, before any significant effects have been
+ * felt. Action should be taken to further diagnose (if necessary) and
+ * correct the problem in order to prevent it from becoming a more
+ * serious service affecting fault.
+ */
+ WARNING
+
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmConsumer.java b/core/api/src/main/java/org/onosproject/alarm/AlarmConsumer.java
new file mode 100644
index 0000000..d791c07
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmConsumer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.net.driver.HandlerBehaviour;
+
+import java.util.List;
+
+/**
+ * Abstraction of a device behaviour capable of retrieving/consuming list of
+ * pending alarms from the device.
+ */
+public interface AlarmConsumer extends HandlerBehaviour {
+
+ /**
+ * Returns the list of active alarms consumed from the device.
+ * This means that subsequent retrieval of alarms will not contain
+ * any duplicates.
+ *
+ * @return list of alarms consumed from the device
+ */
+ List<Alarm> consumeAlarms();
+
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmEntityId.java b/core/api/src/main/java/org/onosproject/alarm/AlarmEntityId.java
new file mode 100644
index 0000000..9debd0a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmEntityId.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import com.google.common.collect.ImmutableSet;
+import org.onlab.util.Identifier;
+
+import java.net.URI;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Immutable representation of a alarm source. It is meaningful within the
+ * context of a device.
+ */
+public final class AlarmEntityId extends Identifier<URI> {
+
+ public static final AlarmEntityId NONE = new AlarmEntityId(URI.create("none:none"));
+ public static final Set<String> SCHEMES = ImmutableSet.of("none", "port", "och", "other");
+
+ private AlarmEntityId(final URI uri) {
+ super(uri);
+ }
+
+ protected AlarmEntityId() {
+ super(NONE.identifier);
+ }
+
+ public static AlarmEntityId alarmEntityId(final String string) {
+ return alarmEntityId(URI.create(string));
+ }
+
+ public static AlarmEntityId alarmEntityId(final URI uri) {
+ checkArgument(SCHEMES.contains(uri.getScheme()), "Unexpected scheme");
+ return new AlarmEntityId(uri);
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmEvent.java b/core/api/src/main/java/org/onosproject/alarm/AlarmEvent.java
new file mode 100644
index 0000000..376d110
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Entity that represents Alarm events. Note: although the event will itself have a time,
+ * consumers may be more interested in the times embedded in the alarms themselves.
+ */
+public class AlarmEvent extends AbstractEvent<AlarmEvent.Type, Alarm> {
+
+ /**
+ * Type of alarm event.
+ */
+ public enum Type {
+
+ /**
+ * Individual alarm updated.
+ */
+ CREATED,
+ /**
+ * Individual alarm updated.
+ */
+ UPDATED,
+ /**
+ * Alarm set updated for a given device.
+ */
+ REMOVED,
+ }
+
+ /**
+ * Creates an event due to one alarm.
+ *
+ * @param type alarm type
+ * @param alarm the alarm related to the event.
+ */
+ public AlarmEvent(AlarmEvent.Type type, Alarm alarm) {
+ super(type, alarm);
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmId.java b/core/api/src/main/java/org/onosproject/alarm/AlarmId.java
new file mode 100644
index 0000000..39cd5b6
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmId.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Alarm identifier suitable as an external key.
+ * <p>
+ * This class is immutable.</p>
+ */
+@Beta
+public final class AlarmId extends Identifier<String> {
+
+ /**
+ * Instantiates a new Alarm id.
+ *
+ * @param id the device id
+ * @param uniqueIdentifier the unique identifier of the Alarm on that device
+ */
+ private AlarmId(DeviceId id, String uniqueIdentifier) {
+ super(id.toString() + ":" + uniqueIdentifier);
+ checkNotNull(id, "device id must not be null");
+ checkNotNull(uniqueIdentifier, "unique identifier must not be null");
+ checkArgument(!uniqueIdentifier.isEmpty(), "unique identifier must not be empty");
+ }
+
+ /**
+ * Instantiates a new Alarm id, primarily meant for lookup.
+ *
+ * @param globallyUniqueIdentifier the globally unique identifier of the Alarm,
+ * device Id + local unique identifier on the device
+ */
+ private AlarmId(String globallyUniqueIdentifier) {
+ super(globallyUniqueIdentifier);
+ checkArgument(!globallyUniqueIdentifier.isEmpty(), "unique identifier must not be empty");
+ }
+
+ /**
+ * Creates an alarm identifier from the specified device id and
+ * unique identifier provided representation.
+ *
+ * @param id device id
+ * @param uniqueIdentifier per device unique identifier of the alarm
+ * @return alarm identifier
+ */
+ public static AlarmId alarmId(DeviceId id, String uniqueIdentifier) {
+ return new AlarmId(id, uniqueIdentifier);
+ }
+
+ /**
+ * Creates an alarm identifier from the specified globally unique identifier.
+ *
+ * @param globallyUniqueIdentifier the globally unique identifier of the Alarm,
+ * device Id + local unique identifier on the device
+ * @return alarm identifier
+ */
+ public static AlarmId alarmId(String globallyUniqueIdentifier) {
+ return new AlarmId(globallyUniqueIdentifier);
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmListener.java b/core/api/src/main/java/org/onosproject/alarm/AlarmListener.java
new file mode 100644
index 0000000..4977f66
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmListener.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Entity capable of receiving alarm related events.
+ */
+public interface AlarmListener extends EventListener<AlarmEvent> {
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmProvider.java b/core/api/src/main/java/org/onosproject/alarm/AlarmProvider.java
new file mode 100644
index 0000000..14c20b3
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.provider.Provider;
+
+/**
+ * Abstraction of an entity capable of supplying alarms collected from
+ * network devices.
+ */
+public interface AlarmProvider extends Provider {
+
+ /**
+ * Triggers an asynchronous discovery of the alarms on the specified device,
+ * intended to refresh internal alarm model for the device. An indirect
+ * result of this should be a event sent later with discovery result
+ * ie a set of alarms.
+ *
+ * @param deviceId ID of device to be probed
+ */
+ void triggerProbe(DeviceId deviceId);
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmProviderRegistry.java b/core/api/src/main/java/org/onosproject/alarm/AlarmProviderRegistry.java
new file mode 100644
index 0000000..32e812d
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmProviderRegistry.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+
+import org.onosproject.net.provider.ProviderRegistry;
+
+/**
+ * Abstraction of a alarm provider registry.
+ */
+public interface AlarmProviderRegistry extends ProviderRegistry<AlarmProvider, AlarmProviderService> {
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmProviderService.java b/core/api/src/main/java/org/onosproject/alarm/AlarmProviderService.java
new file mode 100644
index 0000000..674c0b1
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmProviderService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.provider.ProviderService;
+
+import java.util.Collection;
+
+/**
+ * The interface Alarm provider service.
+ */
+
+public interface AlarmProviderService extends ProviderService<AlarmProvider> {
+
+ /**
+ * Sends active alarm list for a device.
+ *
+ * @param deviceId identity of the device
+ * @param alarms list of device alarms
+ */
+ void updateAlarmList(DeviceId deviceId, Collection<Alarm> alarms);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmService.java b/core/api/src/main/java/org/onosproject/alarm/AlarmService.java
new file mode 100644
index 0000000..7be4d80
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmService.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.event.ListenerService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Service for interacting with the alarm handling of devices. Unless stated otherwise, getter methods
+ * return active AND recently-cleared alarms.
+ */
+public interface AlarmService extends ListenerService<AlarmEvent, AlarmListener> {
+
+ /**
+ * Update book-keeping (ie administrative) fields for the alarm matching the specified identifier.
+ *
+ * @param id alarm identifier
+ * @param clear true if the alarm has to be cleared
+ * @param isAcknowledged new acknowledged state
+ * @param assignedUser new assigned user, null clear
+ * @return updated alarm (including any recent device-derived changes)
+ */
+ Alarm updateBookkeepingFields(AlarmId id, boolean clear, boolean isAcknowledged, String assignedUser);
+
+ /**
+ * Remove an alarm from ONOS.
+ *
+ * @param id alarm
+ */
+ void remove(AlarmId id);
+
+ /**
+ * Returns summary of alarms on a given device.
+ *
+ * @param deviceId the device
+ * @return map of severity (if applicable) vs alarm counts; empty map if either the device has no alarms or
+ * identified device is not managed.
+ */
+ Map<Alarm.SeverityLevel, Long> getAlarmCounts(DeviceId deviceId);
+
+ /**
+ * Returns summary of alarms on all devices.
+ *
+ * @return map of severity (if applicable) vs alarm counts; empty map if no alarms.
+ */
+ Map<Alarm.SeverityLevel, Long> getAlarmCounts();
+
+ /**
+ * Returns the alarm with the specified identifier.
+ *
+ * @param alarmId alarm identifier
+ * @return alarm matching id; null if no alarm matches the identifier.
+ */
+ Alarm getAlarm(AlarmId alarmId);
+
+ /**
+ * Returns all of the alarms.
+ *
+ * @return set of alarms; empty set if no alarms
+ */
+ Set<Alarm> getAlarms();
+
+ /**
+ * Returns all of the ACTIVE alarms. Recently cleared alarms excluded.
+ *
+ * @return set of alarms; empty set if no alarms
+ */
+ Set<Alarm> getActiveAlarms();
+
+ /**
+ * Returns the alarms with the specified severity.
+ *
+ * @param severity the alarm severity
+ * @return set of alarms with a particular severity; empty set if no alarms
+ */
+ Set<Alarm> getAlarms(Alarm.SeverityLevel severity);
+
+ /**
+ * Returns the alarm matching a given device, regardless of source within that device.
+ *
+ * @param deviceId the device to use when searching alarms.
+ * @return set of alarms; empty set if no alarms
+ */
+ Set<Alarm> getAlarms(DeviceId deviceId);
+
+ /**
+ * Returns all of the ACTIVE alarms for a specific device. Recently cleared alarms excluded.
+ *
+ * @param deviceId the device to use when searching alarms.
+ * @return set of alarms; empty set if no alarms
+ */
+ default Set<Alarm> getActiveAlarms(DeviceId deviceId) {
+ return getActiveAlarms().stream()
+ .filter(a -> deviceId.equals(a.deviceId()))
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Returns the alarm for a given device and source.
+ *
+ * @param deviceId the device
+ * @param source the source within the device
+ * @return set of alarms; empty set if no alarms
+ */
+ Set<Alarm> getAlarms(DeviceId deviceId, AlarmEntityId source);
+
+ /**
+ * Returns the alarm affecting a given link.
+ *
+ * @param src one end of the link
+ * @param dst one end of the link
+ * @return set of alarms; empty set if no alarms
+ */
+ Set<Alarm> getAlarmsForLink(ConnectPoint src, ConnectPoint dst);
+
+ /**
+ * Returns the alarm affecting a given flow.
+ *
+ * @param deviceId the device
+ * @param flowId the flow
+ * @return set of alarms; empty set if no alarms
+ */
+ Set<Alarm> getAlarmsForFlow(DeviceId deviceId, long flowId);
+
+ // TODO Support retrieving alarms affecting other entity types may be added in future release
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/AlarmTranslator.java b/core/api/src/main/java/org/onosproject/alarm/AlarmTranslator.java
new file mode 100644
index 0000000..ad29535
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/AlarmTranslator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.net.DeviceId;
+
+import java.io.InputStream;
+import java.util.Collection;
+
+/**
+ * Abstraction of ability to translate device messages into alarms.
+ */
+public interface AlarmTranslator {
+
+ /**
+ * Translates message from device into an alarm with appropriate
+ * information.
+ *
+ * @param deviceId device
+ * @param message message from device to translate to alarm
+ * @return Alarm with information determined by given message
+ */
+ Collection<Alarm> translateToAlarm(DeviceId deviceId, InputStream message);
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/DefaultAlarm.java b/core/api/src/main/java/org/onosproject/alarm/DefaultAlarm.java
new file mode 100644
index 0000000..278be4b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/DefaultAlarm.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onosproject.net.DeviceId;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default implementation of an alarm.
+ */
+public final class DefaultAlarm implements Alarm {
+
+ private final AlarmId id;
+
+ private final DeviceId deviceId;
+ private final String description;
+ private final AlarmEntityId source;
+ private final long timeRaised;
+ private final boolean isServiceAffecting;
+ private final boolean isAcknowledged;
+ private final boolean isManuallyClearable;
+ private final String assignedUser;
+
+ private final SeverityLevel severity;
+ private final long timeUpdated;
+ private final Long timeCleared;
+
+
+ //Only for Kryo
+ DefaultAlarm() {
+ id = null;
+ deviceId = null;
+ description = null;
+ source = null;
+ timeRaised = -1;
+ timeUpdated = -1;
+ timeCleared = null;
+ severity = null;
+ isServiceAffecting = false;
+ isAcknowledged = false;
+ isManuallyClearable = false;
+ assignedUser = null;
+ }
+
+ /**
+ * Instantiates a new Default alarm.
+ *
+ * @param id the id
+ * @param deviceId the device id
+ * @param description the description
+ * @param source the source, null indicates none.
+ * @param timeRaised the time raised.
+ * @param timeUpdated the time last updated.
+ * @param timeCleared the time cleared, null indicates uncleared.
+ * @param severity the severity
+ * @param isServiceAffecting the service affecting
+ * @param isAcknowledged the acknowledged
+ * @param isManuallyClearable the manually clearable
+ * @param assignedUser the assigned user, `null` indicates none.
+ */
+ private DefaultAlarm(final AlarmId id,
+ final DeviceId deviceId,
+ final String description,
+ final AlarmEntityId source,
+ final long timeRaised,
+ final long timeUpdated,
+ final Long timeCleared,
+ final SeverityLevel severity,
+ final boolean isServiceAffecting,
+ final boolean isAcknowledged,
+ final boolean isManuallyClearable,
+ final String assignedUser) {
+ this.id = id;
+ this.deviceId = deviceId;
+ this.description = description;
+ this.source = source;
+ this.timeRaised = timeRaised;
+ this.timeUpdated = timeUpdated;
+ this.timeCleared = timeCleared;
+ this.severity = severity;
+ this.isServiceAffecting = isServiceAffecting;
+ this.isAcknowledged = isAcknowledged;
+ this.isManuallyClearable = isManuallyClearable;
+ this.assignedUser = assignedUser;
+ }
+
+ @Override
+ public AlarmId id() {
+ return id;
+ }
+
+ @Override
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ @Override
+ public String description() {
+ return description;
+ }
+
+ @Override
+ public AlarmEntityId source() {
+ return source;
+ }
+
+ @Override
+ public long timeRaised() {
+ return timeRaised;
+ }
+
+ @Override
+ public long timeUpdated() {
+ return timeUpdated;
+ }
+
+ @Override
+ public Long timeCleared() {
+ return timeCleared;
+ }
+
+ @Override
+ public SeverityLevel severity() {
+ return severity;
+ }
+
+ @Override
+ public boolean serviceAffecting() {
+ return isServiceAffecting;
+ }
+
+ @Override
+ public boolean acknowledged() {
+ return isAcknowledged;
+ }
+
+ @Override
+ public boolean cleared() {
+ return severity.equals(SeverityLevel.CLEARED);
+ }
+
+ @Override
+ public boolean manuallyClearable() {
+ return isManuallyClearable;
+ }
+
+ @Override
+ public String assignedUser() {
+ return assignedUser;
+ }
+
+ @Override
+ public int hashCode() {
+ // id or timeRaised or timeUpdated may differ
+ return Objects.hash(deviceId, description,
+ source, timeCleared, severity,
+ isServiceAffecting, isAcknowledged,
+ isManuallyClearable, assignedUser);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ // Make sure equals() is tune with hashCode() so works ok in a hashSet !
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final DefaultAlarm other = (DefaultAlarm) obj;
+
+ // id or timeRaised or timeUpdated may differ
+ if (!Objects.equals(this.deviceId, other.deviceId)) {
+ return false;
+ }
+ if (!Objects.equals(this.description, other.description)) {
+ return false;
+ }
+ if (!Objects.equals(this.source, other.source)) {
+ return false;
+ }
+
+ if (!Objects.equals(this.timeCleared, other.timeCleared)) {
+ return false;
+ }
+ if (this.severity != other.severity) {
+ return false;
+ }
+ if (this.isServiceAffecting != other.isServiceAffecting) {
+ return false;
+ }
+ if (this.isAcknowledged != other.isAcknowledged) {
+ return false;
+ }
+ if (this.isManuallyClearable != other.isManuallyClearable) {
+ return false;
+ }
+ if (!Objects.equals(this.assignedUser, other.assignedUser)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("deviceId", deviceId)
+ .add("description", description)
+ .add("source", source)
+ .add("timeRaised", timeRaised)
+ .add("timeUpdated", timeUpdated)
+ .add("timeCleared", timeCleared)
+ .add("severity", severity)
+ .add("serviceAffecting", isServiceAffecting)
+ .add("acknowledged", isAcknowledged)
+ .add("manuallyClearable", isManuallyClearable)
+ .add("assignedUser", assignedUser)
+ .toString();
+ }
+
+ /**
+ * Builder for the DefaultAlarm object.
+ */
+ public static class Builder {
+
+ // Manadatory fields when constructing alarm ...
+ private AlarmId id;
+ private final DeviceId deviceId;
+ private final String description;
+ private SeverityLevel severity;
+ private final long timeRaised;
+
+ // Optional fields ..
+ private AlarmEntityId source = AlarmEntityId.NONE;
+ private long timeUpdated;
+ private Long timeCleared = null;
+ private boolean isServiceAffecting = false;
+ private boolean isAcknowledged = false;
+ private boolean isManuallyClearable = false;
+ private String assignedUser = null;
+
+ /**
+ * Constructs a Builder to create a Default Alarm based on another alarm.
+ *
+ * @param alarm the other alarm
+ */
+ public Builder(final Alarm alarm) {
+ this(alarm.id(), alarm.deviceId(), alarm.description(), alarm.severity(), alarm.timeRaised());
+ this.source = alarm.source();
+ this.timeUpdated = alarm.timeUpdated();
+ this.timeCleared = alarm.timeCleared();
+ this.isServiceAffecting = alarm.serviceAffecting();
+ this.isAcknowledged = alarm.acknowledged();
+ this.isManuallyClearable = alarm.manuallyClearable();
+ this.assignedUser = alarm.assignedUser();
+
+ }
+
+ /**
+ * Constructs a Builder to create a Default Alarm.
+ *
+ * @param id the AlarmId
+ * @param deviceId the device ID
+ * @param description the Alarm description
+ * @param severity the severity
+ * @param timeRaised when the alarm was raised
+ */
+ public Builder(final AlarmId id, final DeviceId deviceId,
+ final String description, final SeverityLevel severity, final long timeRaised) {
+ super();
+ this.id = id;
+ this.deviceId = deviceId;
+ this.description = description;
+ this.severity = severity;
+ this.timeRaised = timeRaised;
+ // Unless specified time-updated is same as raised.
+ this.timeUpdated = timeRaised;
+ }
+
+ /**
+ * Sets the new alarm source.
+ *
+ * @param source the source
+ * @return self for chaining
+ */
+ public Builder forSource(final AlarmEntityId source) {
+ this.source = source;
+ return this;
+ }
+
+ /**
+ * Sets the new alarm time updated.
+ *
+ * @param timeUpdated the time
+ * @return self for chaining
+ */
+ public Builder withTimeUpdated(final long timeUpdated) {
+ this.timeUpdated = timeUpdated;
+ return this;
+ }
+
+ /**
+ * Sets the new alarm time cleared.
+ *
+ * @param timeCleared the time
+ * @return self for chaining
+ */
+ public Builder withTimeCleared(final Long timeCleared) {
+ this.timeCleared = timeCleared;
+ return this;
+ }
+
+ /**
+ * Clears the alarm that is being created.
+ *
+ * @return self for chaining
+ */
+ public Builder clear() {
+ this.severity = SeverityLevel.CLEARED;
+ final long now = System.currentTimeMillis();
+ return withTimeCleared(now).withTimeUpdated(now);
+ }
+
+ /**
+ * Sets the new alarm service affecting flag.
+ *
+ * @param isServiceAffecting the service affecting flag
+ * @return self for chaining
+ */
+ public Builder withServiceAffecting(final boolean isServiceAffecting) {
+ this.isServiceAffecting = isServiceAffecting;
+ return this;
+ }
+
+ /**
+ * Sets the new alarm acknowledged flag.
+ *
+ * @param isAcknowledged the acknowledged flag
+ * @return self for chaining
+ */
+ public Builder withAcknowledged(final boolean isAcknowledged) {
+ this.isAcknowledged = isAcknowledged;
+ return this;
+ }
+
+ /**
+ * Sets the new alarm the manually clearable flag.
+ *
+ * @param isManuallyClearable the manually clearable flag
+ * @return self for chaining
+ */
+ public Builder withManuallyClearable(final boolean isManuallyClearable) {
+ this.isManuallyClearable = isManuallyClearable;
+ return this;
+ }
+
+ /**
+ * Sets the new alarm assigned user.
+ *
+ * @param assignedUser the user
+ * @return self for chaining
+ */
+ public Builder withAssignedUser(final String assignedUser) {
+ this.assignedUser = assignedUser;
+ return this;
+ }
+
+ /**
+ * Builds the alarm.
+ *
+ * @return self for chaining
+ */
+ public DefaultAlarm build() {
+ checkNotNull(id, "Must specify an alarm id");
+ checkNotNull(deviceId, "Must specify a device");
+ checkNotNull(description, "Must specify a description");
+ checkNotNull(severity, "Must specify a severity");
+
+ return new DefaultAlarm(id, deviceId, description, source, timeRaised, timeUpdated, timeCleared,
+ severity, isServiceAffecting, isAcknowledged, isManuallyClearable, assignedUser);
+ }
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/DeviceAlarmConfig.java b/core/api/src/main/java/org/onosproject/alarm/DeviceAlarmConfig.java
new file mode 100644
index 0000000..8d6146f
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/DeviceAlarmConfig.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.driver.HandlerBehaviour;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Abstraction of a device behaviour capable of translating a list of
+ * alarms from a device. Also provides a method to configure the address where to
+ * send the alarms/traps/notifications.
+ */
+public interface DeviceAlarmConfig extends HandlerBehaviour {
+
+ /**
+ * Configures the device to send alarms to a particular Ip and port combination.
+ *
+ * @param address address to wich the device should send alarms
+ * @param port port on which the controller is listening
+ * @param protocol tcp or udp
+ * @return boolean true if the device was properly configured
+ */
+ boolean configureDevice(IpAddress address, int port, String protocol);
+
+ /**
+ * Returns the list of translated alarms from device-specific representation
+ * to ONOS alarms.
+ *
+ * @param unparsedAlarms alarms arrived from the device depending on protocol
+ * @param <T> type of object given from the device
+ * @return list of alarms consumed from the device
+ */
+ <T> Set<Alarm> translateAlarms(List<T> unparsedAlarms);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/XmlEventParser.java b/core/api/src/main/java/org/onosproject/alarm/XmlEventParser.java
new file mode 100644
index 0000000..0154cb9
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/XmlEventParser.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.alarm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.DateTimeException;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * Parser for Netconf notifications.
+ */
+public final class XmlEventParser {
+ public static final Logger log = LoggerFactory
+ .getLogger(XmlEventParser.class);
+
+ private static final String DISALLOW_DTD_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
+ private static final String DISALLOW_EXTERNAL_DTD =
+ "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+ private static final String EVENTTIME_TAGNAME = "eventTime";
+
+ private XmlEventParser() {
+ }
+
+ /**
+ * Creates a document from the input stream message and returns the result.
+ *
+ * @param message input stream message
+ * @return the document result
+ * @throws SAXException Throws SAX Exception
+ * @throws IOException Throws IO Exception
+ * @throws ParserConfigurationException Throws ParserConfigurationException
+ */
+ public static Document createDocFromMessage(InputStream message)
+ throws SAXException, IOException, ParserConfigurationException {
+ DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
+ //Disabling DTDs in order to avoid XXE xml-based attacks.
+ disableFeature(dbfactory, DISALLOW_DTD_FEATURE);
+ disableFeature(dbfactory, DISALLOW_EXTERNAL_DTD);
+ dbfactory.setXIncludeAware(false);
+ dbfactory.setExpandEntityReferences(false);
+ DocumentBuilder builder = dbfactory.newDocumentBuilder();
+ return builder.parse(new InputSource(message));
+ }
+
+ private static void disableFeature(DocumentBuilderFactory dbfactory, String feature) {
+ try {
+ dbfactory.setFeature(feature, true);
+ } catch (ParserConfigurationException e) {
+ // This should catch a failed setFeature feature
+ log.info("ParserConfigurationException was thrown. The feature '" +
+ feature + "' is probably not supported by your XML processor.");
+ }
+ }
+
+ public static long getEventTime(String dateTime)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ try {
+ OffsetDateTime date = OffsetDateTime.parse(dateTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+ return date.toInstant().toEpochMilli();
+ } catch (DateTimeException e) {
+ log.error("Cannot parse exception {} {}", dateTime, e);
+ }
+ return System.currentTimeMillis();
+ }
+
+ public static long getEventTime(Document doc)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ String dateTime = getEventTimeNode(doc).getTextContent();
+ return getEventTime(dateTime);
+ }
+
+ public static Node getDescriptionNode(Document doc) {
+ return getEventTimeNode(doc).getNextSibling();
+ }
+
+ private static Node getEventTimeNode(Document doc) {
+ return doc.getElementsByTagName(EVENTTIME_TAGNAME).item(0);
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/alarm/package-info.java b/core/api/src/main/java/org/onosproject/alarm/package-info.java
new file mode 100644
index 0000000..4003645
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/alarm/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+/**
+ * Abstractions for interacting with alarms. An alarm is a persistent indication
+ * of a fault that clears only when the triggering condition has been resolved.
+ */
+package org.onosproject.alarm;
diff --git a/core/api/src/main/java/org/onosproject/net/TenantId.java b/core/api/src/main/java/org/onosproject/net/TenantId.java
new file mode 100644
index 0000000..1b8fadb
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/TenantId.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net;
+
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Representation of network tenant.
+ */
+public final class TenantId extends Identifier<String> {
+
+ /**
+ * Represents no tenant, or an unspecified tenant.
+ */
+ public static final TenantId NONE = new TenantId();
+
+ // Public construction is prohibited
+ private TenantId(String id) {
+ super(id);
+ checkArgument(id != null && id.length() > 0, "Tenant ID cannot be null or empty");
+ }
+
+ // Default constructor for serialization
+ protected TenantId() {
+ super("");
+ }
+
+ /**
+ * Creates a tenant id using the supplied backing id.
+ *
+ * @param id network id
+ * @return network identifier
+ */
+ public static TenantId tenantId(String id) {
+ return new TenantId(id);
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/config/basics/PortDescriptionsConfig.java b/core/api/src/main/java/org/onosproject/net/config/basics/PortDescriptionsConfig.java
new file mode 100644
index 0000000..484660e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/config/basics/PortDescriptionsConfig.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.config.basics;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.PortDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Configuration for Ports. Creates a list of PortDescription based on the given Json.
+ */
+@Beta
+public class PortDescriptionsConfig extends Config<DeviceId> {
+ private static Logger log = LoggerFactory.getLogger(PortDescriptionsConfig.class);
+
+ private static final String NUMBER = "number";
+ private static final String NAME = "name";
+ private static final String ENABLED = "enabled";
+ private static final String REMOVED = "removed";
+ private static final String TYPE = "type";
+ private static final String SPEED = "speed";
+ private static final String ANNOTATIONS = "annotations";
+
+ private static final String CONFIG_VALUE_ERROR = "Error parsing config value";
+
+ @Override
+ public boolean isValid() {
+ for (Iterator<Map.Entry<String, JsonNode>> it = node.fields(); it.hasNext();) {
+ JsonNode nodePort = it.next().getValue();
+ if (!hasOnlyFields((ObjectNode) nodePort, NUMBER, NAME, ENABLED, REMOVED, TYPE,
+ SPEED, ANNOTATIONS)) {
+ return false;
+ }
+ ObjectNode obj = (ObjectNode) nodePort;
+
+ if (!(isNumber(obj, NUMBER, FieldPresence.MANDATORY) &&
+ isString(obj, NAME, FieldPresence.OPTIONAL) &&
+ isBoolean(obj, ENABLED, FieldPresence.OPTIONAL) &&
+ isBoolean(obj, REMOVED, FieldPresence.OPTIONAL) &&
+ isString(obj, TYPE, FieldPresence.OPTIONAL) &&
+ isIntegralNumber(obj, SPEED, FieldPresence.OPTIONAL))) {
+ return false;
+ }
+
+ if (node.has(ANNOTATIONS) && !node.get(ANNOTATIONS).isObject()) {
+ log.error("Annotations must be an inner json node");
+ return false;
+ }
+
+ }
+ return true;
+ }
+
+ /**
+ * Retrieves all port descriptions.
+ *
+ * @return set of port descriptions
+ */
+ public List<PortDescription> portDescriptions() {
+
+ try {
+ ImmutableList.Builder<PortDescription> portDescriptions = ImmutableList.builder();
+ for (Iterator<Map.Entry<String, JsonNode>> it = node.fields(); it.hasNext();) {
+ JsonNode portNode = it.next().getValue();
+ long number = portNode.path(NUMBER).asLong();
+
+ String name = portNode.path(NAME).asText(null);
+
+ PortNumber portNumber = createPortNumber(number, name);
+
+ DefaultPortDescription.Builder builder = DefaultPortDescription.builder()
+ .withPortNumber(portNumber);
+ if (portNode.has(ENABLED)) {
+ builder.isEnabled(portNode.path(ENABLED).asBoolean());
+ }
+
+ if (portNode.has(REMOVED)) {
+ builder.isRemoved(portNode.path(REMOVED).asBoolean());
+ }
+
+ if (portNode.has(TYPE)) {
+ builder.type(Port.Type.valueOf(portNode.path(TYPE).asText().toUpperCase()));
+ }
+
+ if (portNode.has(SPEED)) {
+ builder.portSpeed(portNode.path(SPEED).asLong());
+ }
+
+ if (portNode.has(ANNOTATIONS)) {
+ DefaultAnnotations.Builder annotationsBuilder = DefaultAnnotations.builder();
+ Iterator<Map.Entry<String, JsonNode>> annotationsIt = portNode.get(ANNOTATIONS).fields();
+ while (annotationsIt.hasNext()) {
+ Map.Entry<String, JsonNode> entry = annotationsIt.next();
+ annotationsBuilder.set(entry.getKey(), entry.getValue().asText());
+ }
+ builder.annotations(annotationsBuilder.build());
+ }
+
+ portDescriptions.add(builder.build());
+ }
+
+ return portDescriptions.build();
+
+ } catch (IllegalArgumentException e) {
+ log.error(CONFIG_VALUE_ERROR, e);
+ return ImmutableList.of();
+ }
+ }
+
+ private PortNumber createPortNumber(long number, String name) {
+ if (name == null) {
+ return PortNumber.portNumber(number);
+ }
+ return PortNumber.portNumber(number, name);
+ }
+
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/statistic/PortStatisticsService.java b/core/api/src/main/java/org/onosproject/net/statistic/PortStatisticsService.java
new file mode 100644
index 0000000..4ed782b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/statistic/PortStatisticsService.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.statistic;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Service for obtaining statistic information about device ports.
+ */
+@Beta
+public interface PortStatisticsService {
+
+ /** Specifies the type of metric. */
+ enum MetricType {
+ /** Load is to be given in bytes/second. */
+ BYTES,
+
+ /** Load is to be given in packets/second. */
+ PACKETS
+ }
+
+ /**
+ * Obtain the egress load for the given port in terms of bytes per second.
+ *
+ * @param connectPoint the port to query
+ * @return egress traffic load
+ */
+ Load load(ConnectPoint connectPoint);
+
+ /**
+ * Obtain the egress load for the given port in terms of the specified metric.
+ *
+ * @param connectPoint the port to query
+ * @param metricType metric type
+ * @return egress traffic load
+ */
+ default Load load(ConnectPoint connectPoint, MetricType metricType) {
+ return load(connectPoint);
+ }
+
+}