[ONOS-6844] inject ports via net-cfg
Change-Id: I3052e8b43fd26960b111200d6e506fd91e1f01fd
diff --git a/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java b/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java
index 630fc79..88b656a 100644
--- a/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java
+++ b/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java
@@ -24,6 +24,7 @@
import org.apache.felix.scr.annotations.Service;
import org.onosproject.core.CoreService;
import org.onosproject.incubator.net.config.basics.InterfaceConfig;
+import org.onosproject.incubator.net.config.basics.PortDescriptionsConfig;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
@@ -61,6 +62,7 @@
private static final String BASIC = "basic";
private static final String INTERFACES = "interfaces";
+ private static final String PORTS = "ports";
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -121,7 +123,16 @@
public PortAnnotationConfig createConfig() {
return new PortAnnotationConfig();
}
+ },
+ new ConfigFactory<DeviceId, PortDescriptionsConfig>(DEVICE_SUBJECT_FACTORY,
+ PortDescriptionsConfig.class,
+ PORTS) {
+ @Override
+ public PortDescriptionsConfig createConfig() {
+ return new PortDescriptionsConfig();
+ }
}
+
);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index c0bf128..ebdb973 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -29,6 +29,7 @@
import org.onlab.util.Tools;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.NodeId;
+import org.onosproject.incubator.net.config.basics.PortDescriptionsConfig;
import org.onosproject.mastership.MastershipEvent;
import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService;
@@ -451,6 +452,7 @@
log.warn("Device {} is not allowed", deviceId);
return;
}
+ PortDescriptionsConfig portConfig = networkConfigService.getConfig(deviceId, PortDescriptionsConfig.class);
// Generate updated description and establish my Role
deviceDescription = BasicDeviceOperator.combine(cfg, deviceDescription);
Futures.getUnchecked(mastershipService.requestRoleFor(deviceId)
@@ -461,11 +463,23 @@
DeviceEvent event = store.createOrUpdateDevice(provider().id(), deviceId,
deviceDescription);
+ if (portConfig != null) {
+ //updating the ports if configration exists
+ List<PortDescription> complete = store.getPortDescriptions(provider().id(), deviceId)
+ .collect(Collectors.toList());
+ complete.addAll(portConfig.portDescriptions());
+ List<PortDescription> portDescriptions = complete.stream()
+ .map(e -> applyAllPortOps(deviceId, e))
+ .collect(Collectors.toList());
+ store.updatePorts(provider().id(), deviceId, portDescriptions);
+ }
+
if (deviceDescription.isDefaultAvailable()) {
log.info("Device {} connected", deviceId);
} else {
log.info("Device {} registered", deviceId);
}
+
if (event != null) {
log.trace("event: {} {}", event.type(), event);
post(event);
@@ -548,6 +562,11 @@
log.trace("Ignoring {} port updates on standby node. {}", deviceId, portDescriptions);
return;
}
+ PortDescriptionsConfig portConfig = networkConfigService.getConfig(deviceId, PortDescriptionsConfig.class);
+ if (portConfig != null) {
+ //updating the ports if configration exists
+ portDescriptions.addAll(portConfig.portDescriptions());
+ }
portDescriptions = portDescriptions.stream()
.map(e -> applyAllPortOps(deviceId, e))
.collect(Collectors.toList());
@@ -898,16 +917,17 @@
return (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED
|| event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)
&& (event.configClass().equals(BasicDeviceConfig.class)
- || portOpsIndex.containsKey(event.configClass()));
+ || portOpsIndex.containsKey(event.configClass())
+ || event.configClass().equals(PortDescriptionsConfig.class));
}
@Override
public void event(NetworkConfigEvent event) {
DeviceEvent de = null;
+ DeviceId did = (DeviceId) event.subject();
+ DeviceProvider dp = getProvider(did);
if (event.configClass().equals(BasicDeviceConfig.class)) {
log.debug("Detected device network config event {}", event.type());
- DeviceId did = (DeviceId) event.subject();
- DeviceProvider dp = getProvider(did);
BasicDeviceConfig cfg =
networkConfigService.getConfig(did, BasicDeviceConfig.class);
@@ -923,10 +943,17 @@
}
}
}
+ if (event.configClass().equals(PortDescriptionsConfig.class) && event.config().isPresent()
+ && getDevice(did) != null && dp != null) {
+ PortDescriptionsConfig portConfig = (PortDescriptionsConfig) event.config().get();
+ //updating the ports if configration exists
+ List<PortDescription> complete = store.getPortDescriptions(dp.id(), did)
+ .collect(Collectors.toList());
+ complete.addAll(portConfig.portDescriptions());
+ store.updatePorts(dp.id(), did, complete);
+ }
if (portOpsIndex.containsKey(event.configClass())) {
ConnectPoint cpt = (ConnectPoint) event.subject();
- DeviceId did = cpt.deviceId();
- DeviceProvider dp = getProvider(did);
// Note: assuming PortOperator can modify existing port,
// but cannot add new port purely from Config.
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/PortDescriptionsConfig.java b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/PortDescriptionsConfig.java
new file mode 100644
index 0000000..6c0b1ba
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/PortDescriptionsConfig.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2015-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.incubator.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()
+ .withPortNumer(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 (it.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/tools/test/configs/sample-ports.json b/tools/test/configs/sample-ports.json
new file mode 100644
index 0000000..921d938
--- /dev/null
+++ b/tools/test/configs/sample-ports.json
@@ -0,0 +1,31 @@
+{
+ "devices": {
+ "null:0000000000000001": {
+ "basic": {
+ "allowed": true,
+ "owner": "Luigi"
+ },
+ "ports": {
+ "1":{
+ "number": 1,
+ "name": "test",
+ "enabled": true,
+ "removed": false,
+ "type": "copper",
+ "speed": 40000
+ },
+ "2":{
+ "number": 2,
+ "name": "test2",
+ "enabled": true,
+ "removed": false,
+ "type": "copper",
+ "speed": 40000,
+ "annotations":{
+ "testann": "testann"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file