diff options
author | Ashlee Young <ashlee@wildernessvoice.com> | 2015-12-01 05:49:27 -0800 |
---|---|---|
committer | Ashlee Young <ashlee@wildernessvoice.com> | 2015-12-01 05:49:27 -0800 |
commit | e63291850fd0795c5700e25e67e5dee89ba54c5f (patch) | |
tree | 9707289536ad95bb739c9856761ad43275e07d8c /framework/src/onos/protocols/netconf | |
parent | 671823e12bc13be9a8b87a5d7de33da1bb7a44e8 (diff) |
onos commit hash c2999f30c69e50df905a9d175ef80b3f23a98514
Change-Id: I2bb8562c4942b6d6a6d60b663db2e17540477b81
Signed-off-by: Ashlee Young <ashlee@wildernessvoice.com>
Diffstat (limited to 'framework/src/onos/protocols/netconf')
16 files changed, 1395 insertions, 0 deletions
diff --git a/framework/src/onos/protocols/netconf/api/pom.xml b/framework/src/onos/protocols/netconf/api/pom.xml new file mode 100644 index 00000000..ed8a5302 --- /dev/null +++ b/framework/src/onos/protocols/netconf/api/pom.xml @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<!-- + ~ Copyright 2015 Open Networking Laboratory + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-netconf</artifactId> + <version>1.4.0-SNAPSHOT</version> + </parent> + <artifactId>onos-netconf-api</artifactId> + <packaging>bundle</packaging> + + <description>ONOS NETCONF plugin API</description> + <dependencies> + <dependency> + <groupId>commons-pool</groupId> + <artifactId>commons-pool</artifactId> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-transport</artifactId> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-transport-native-epoll</artifactId> + <version>${netty4.version}</version> + </dependency> + </dependencies> + +</project> diff --git a/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfController.java b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfController.java new file mode 100644 index 00000000..6411c011 --- /dev/null +++ b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfController.java @@ -0,0 +1,84 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf; + +import org.onlab.packet.IpAddress; +import org.onosproject.net.DeviceId; + +import java.util.Map; + +/** + * Abstraction of an NETCONF controller. Serves as a one stop shop for obtaining + * NetconfDevice and (un)register listeners on NETCONF device events. + */ +public interface NetconfController { + + /** + * Adds Device Event Listener. + * + * @param listener node listener + */ + void addDeviceListener(NetconfDeviceListener listener); + + /** + * Removes Device Listener. + * + * @param listener node listener + */ + void removeDeviceListener(NetconfDeviceListener listener); + + /** + * Tries to connect to a specific NETCONF device, if the connection is succesful + * it creates and adds the device to the ONOS core as a NetconfDevice. + * + * @param deviceInfo info about the device to add + * @return NetconfDevice Netconf device + */ + NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo); + + /** + * Removes a Netconf device. + * + * @param deviceInfo info about the device to remove + */ + void removeDevice(NetconfDeviceInfo deviceInfo); + + /** + * Gets all the nodes information. + * + * @return map of devices + */ + Map<DeviceId, NetconfDevice> getDevicesMap(); + + /** + * Gets a Netconf Device by node identifier. + * + * @param deviceInfo node identifier + * @return NetconfDevice Netconf device + */ + NetconfDevice getNetconfDevice(DeviceId deviceInfo); + + /** + * Gets a Netconf Device by node identifier. + * + * @param ip device ip + * @param port device port + * @return NetconfDevice Netconf device + */ + NetconfDevice getNetconfDevice(IpAddress ip, int port); + +} diff --git a/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDevice.java b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDevice.java new file mode 100644 index 00000000..1974782b --- /dev/null +++ b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDevice.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf; + +/** + * Interface representing a NETCONF device. + */ +public interface NetconfDevice { + + + /** + * Returns whether a device is a NETCONF device with a capabilities list + * and is accessible. + * + * @return true if device is accessible, false otherwise + */ + boolean isActive(); + + /** + * Returns a NETCONF session context for this device. + * + * @return netconf session + */ + NetconfSession getSession(); + + /** + * Ensures that all sessions are closed. + * A device cannot be used after disconnect is called. + */ + void disconnect(); + + /** + * return all the info associated with this device. + * @return NetconfDeviceInfo + */ + NetconfDeviceInfo getDeviceInfo(); +}
\ No newline at end of file diff --git a/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java new file mode 100644 index 00000000..cb0e240a --- /dev/null +++ b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java @@ -0,0 +1,173 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf; + +import com.google.common.base.Preconditions; +import org.onlab.packet.IpAddress; +import org.onosproject.net.DeviceId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Objects; + +/** + * Represents a Netconf device information. + */ +public class NetconfDeviceInfo { + + public static final Logger log = LoggerFactory + .getLogger(NetconfDeviceInfo.class); + + private String name; + private String password; + private IpAddress ipAddress; + private int port; + private File keyFile; + + + /** + * Information for contacting the controller. + * + * @param name the connection type + * @param password the password for the device + * @param ipAddress the ip address + * @param port the tcp port + */ + public NetconfDeviceInfo(String name, String password, IpAddress ipAddress, + int port) { + Preconditions.checkArgument(!name.equals(""), "Empty device name"); + Preconditions.checkNotNull(port > 0, "Negative port"); + Preconditions.checkNotNull(ipAddress, "Null ip address"); + this.name = name; + this.password = password; + this.ipAddress = ipAddress; + this.port = port; + } + + /** + * Information for contacting the controller. + * + * @param name the connection type + * @param password the password for the device + * @param ipAddress the ip address + * @param port the tcp port + * @param keyString the string cointaing the key. + */ + public NetconfDeviceInfo(String name, String password, IpAddress ipAddress, + int port, String keyString) { + Preconditions.checkArgument(!name.equals(""), "Empty device name"); + Preconditions.checkNotNull(port > 0, "Negative port"); + Preconditions.checkNotNull(ipAddress, "Null ip address"); + this.name = name; + this.password = password; + this.ipAddress = ipAddress; + this.port = port; + this.keyFile = new File(keyString); + } + + /** + * Exposes the name of the controller. + * + * @return String name + */ + public String name() { + return name; + } + + /** + * Exposes the password of the controller. + * + * @return String password + */ + public String password() { + return password; + } + + /** + * Exposes the ip address of the controller. + * + * @return IpAddress ip address + */ + public IpAddress ip() { + return ipAddress; + } + + /** + * Exposes the port of the controller. + * + * @return int port address + */ + public int port() { + return port; + } + + /** + * Exposes the keyFile of the controller. + * + * @return int port address + */ + public File getKeyFile() { + return keyFile; + } + + /** + * Return the info about the device in a string. + * String format: "netconf:name@ip:port" + * + * @return String device info + */ + public String toString() { + return "netconf:" + name + "@" + ipAddress + ":" + port; + } + + /** + * Return the DeviceId about the device containing the URI. + * + * @return DeviceId + */ + public DeviceId getDeviceId() { + + try { + return DeviceId.deviceId(new URI(this.toString())); + } catch (URISyntaxException e) { + log.debug("Unable to build deviceID for device {} ", this, e); + } + return null; + } + + @Override + public int hashCode() { + return Objects.hash(ipAddress, port, name); + } + + @Override + public boolean equals(Object toBeCompared) { + if (toBeCompared instanceof NetconfDeviceInfo) { + NetconfDeviceInfo netconfDeviceInfo = (NetconfDeviceInfo) toBeCompared; + if (netconfDeviceInfo.name().equals(name) + && netconfDeviceInfo.ip().equals(ipAddress) + && netconfDeviceInfo.port() == port + && netconfDeviceInfo.password().equals(password)) { + return true; + } + } + return false; + } +} diff --git a/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceListener.java b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceListener.java new file mode 100644 index 00000000..9c46d4f6 --- /dev/null +++ b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceListener.java @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf; + +/** + * Allows for providers interested in node events to be notified. + */ +public interface NetconfDeviceListener { + + /** + * Notifies that the node was added. + * + * @param nodeId the node where the event occurred + */ + void deviceAdded(NetconfDeviceInfo nodeId); + + /** + * Notifies that the node was removed. + * + * @param nodeId the node where the event occurred + */ + void deviceRemoved(NetconfDeviceInfo nodeId); +} diff --git a/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java new file mode 100644 index 00000000..73c435f6 --- /dev/null +++ b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java @@ -0,0 +1,129 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf; + +import java.util.List; + +/** + * NETCONF session object that allows NETCONF operations on top with the physical + * device on top of an SSH connection. + */ +// TODO change return type of methdos to <Capability, XMLdoc, string or yang obj> +public interface NetconfSession { + + /** + * Retrives the requested configuration, different from get-config. + * @param request the XML containing the request to the server. + * @return device running configuration + */ + String get(String request); + + /** + * Executes an RPC to the server. + * @param request the XML containing the RPC for the server. + * @return Server response or ERROR + */ + String doRPC(String request); + + /** + * Retrives the specified configuration. + * + * @param targetConfiguration the type of configuration to retrieve. + * @return specified configuration. + */ + String getConfig(String targetConfiguration); + + /** + * Retrives part of the specivied configuration based on the filterSchema. + * + * @param targetConfiguration the type of configuration to retrieve. + * @param configurationFilterSchema XML schema to filter the configuration + * elements we are interested in + * @return device running configuration. + */ + String getConfig(String targetConfiguration, String configurationFilterSchema); + + /** + * Retrives part of the specified configuration based on the filterSchema. + * + * @param newConfiguration configuration to set + * @return true if the configuration was edited correctly + */ + + boolean editConfig(String newConfiguration); + + /** + * Copies the new configuration, an Url or a complete configuration xml tree + * to the target configuration. + * The target configuration can't be the running one + * + * @param targetConfiguration the type of configuration to retrieve. + * @param newConfiguration configuration to set + * @return true if the configuration was copied correctly + */ + boolean copyConfig(String targetConfiguration, String newConfiguration); + + /** + * Deletes part of the specified configuration based on the filterSchema. + * + * @param targetConfiguration the name of the configuration to delete + * @return true if the configuration was copied correctly + */ + boolean deleteConfig(String targetConfiguration); + + /** + * Locks the candidate configuration. + * + * @return true if successful. + */ + boolean lock(); + + /** + * Unlocks the candidate configuration. + * + * @return true if successful. + */ + boolean unlock(); + + /** + * Closes the Netconf session with the device. + * the first time it tries gracefully, then kills it forcefully + * @return true if closed + */ + boolean close(); + + /** + * Gets the session ID of the Netconf session. + * + * @return Session ID as a string. + */ + String getSessionId(); + + /** + * Gets the capabilities of the Netconf server associated to this session. + * + * @return Network capabilities as a string. + */ + String getServerCapabilities(); + + /** + * Sets the device capabilities. + * @param capabilities list of capabilities the device has. + */ + void setDeviceCapabilities(List<String> capabilities); + +} diff --git a/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/package-info.java b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/package-info.java new file mode 100644 index 00000000..5562bd33 --- /dev/null +++ b/framework/src/onos/protocols/netconf/api/src/main/java/org/onosproject/netconf/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf; diff --git a/framework/src/onos/protocols/netconf/ctl/pom.xml b/framework/src/onos/protocols/netconf/ctl/pom.xml new file mode 100644 index 00000000..e022acba --- /dev/null +++ b/framework/src/onos/protocols/netconf/ctl/pom.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2015 Open Networking Laboratory + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-netconf</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-netconf-ctl</artifactId> + <packaging>bundle</packaging> + + <dependencies> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-netconf-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>ch.ethz.ganymed</groupId> + <artifactId>ganymed-ssh2</artifactId> + <version>262</version> + </dependency> + </dependencies> + + <build> + <plugins> + <!--plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>2.3</version> + <configuration> + <filters> + <filter> + <artifact>ch.ethz.ganymed:ganymed-ssh2</artifact> + <includes> + <include>ch/ethz/ssh2/**</include> + </includes> + </filter> + <filter> + <artifact>org.jdom:jdom2</artifact> + <includes> + <include>org/jdom2/**</include> + </includes> + </filter> + </filters> + </configuration> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + </execution> + </executions> + </plugin--> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <configuration> + <instructions> + <Private-Package>ch.ethz.ssh2.*</Private-Package> + <Embed-Dependecy>ganymed-ssh2</Embed-Dependecy> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java new file mode 100644 index 00000000..a572a2bc --- /dev/null +++ b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java @@ -0,0 +1,143 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf.ctl; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Service; +import org.onlab.packet.IpAddress; +import org.onosproject.net.DeviceId; +import org.onosproject.netconf.NetconfController; +import org.onosproject.netconf.NetconfDevice; +import org.onosproject.netconf.NetconfDeviceInfo; +import org.onosproject.netconf.NetconfDeviceListener; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * The implementation of NetconfController. + */ +@Component(immediate = true) +@Service +public class NetconfControllerImpl implements NetconfController { + + public static final Logger log = LoggerFactory + .getLogger(NetconfControllerImpl.class); + + public Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<>(); + + protected Set<NetconfDeviceListener> netconfDeviceListeners = new CopyOnWriteArraySet<>(); + + @Activate + public void activate(ComponentContext context) { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + netconfDeviceMap.clear(); + log.info("Stopped"); + } + + @Override + public void addDeviceListener(NetconfDeviceListener listener) { + if (!netconfDeviceListeners.contains(listener)) { + netconfDeviceListeners.add(listener); + } + } + + @Override + public void removeDeviceListener(NetconfDeviceListener listener) { + netconfDeviceListeners.remove(listener); + } + + @Override + public NetconfDevice getNetconfDevice(DeviceId deviceInfo) { + return netconfDeviceMap.get(deviceInfo); + } + + @Override + public NetconfDevice getNetconfDevice(IpAddress ip, int port) { + NetconfDevice device = null; + for (DeviceId info : netconfDeviceMap.keySet()) { + if (IpAddress.valueOf(info.uri().getHost()).equals(ip) && + info.uri().getPort() == port) { + return netconfDeviceMap.get(info); + } + } + return device; + } + + @Override + public NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) { + if (netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) { + log.warn("Device {} is already present"); + return netconfDeviceMap.get(deviceInfo.getDeviceId()); + } else { + log.info("Creating NETCONF device {}", deviceInfo); + return createDevice(deviceInfo); + } + } + + @Override + public void removeDevice(NetconfDeviceInfo deviceInfo) { + if (netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) { + log.warn("Device {} is not present"); + } else { + stopDevice(deviceInfo); + } + } + + private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) { + NetconfDevice netconfDevice = null; + try { + netconfDevice = new NetconfDeviceImpl(deviceInfo); + for (NetconfDeviceListener l : netconfDeviceListeners) { + l.deviceAdded(deviceInfo); + } + netconfDeviceMap.put(deviceInfo.getDeviceId(), netconfDevice); + } catch (IOException e) { + throw new IllegalStateException("Cannot create NETCONF device " + + "with device Info: " + + deviceInfo + " \n" + e); + } + return netconfDevice; + } + + private void stopDevice(NetconfDeviceInfo deviceInfo) { + netconfDeviceMap.get(deviceInfo.getDeviceId()).disconnect(); + netconfDeviceMap.remove(deviceInfo.getDeviceId()); + for (NetconfDeviceListener l : netconfDeviceListeners) { + l.deviceRemoved(deviceInfo); + } + } + + @Override + public Map<DeviceId, NetconfDevice> getDevicesMap() { + return netconfDeviceMap; + } + + +} diff --git a/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfDeviceImpl.java b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfDeviceImpl.java new file mode 100644 index 00000000..3141aafc --- /dev/null +++ b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfDeviceImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf.ctl; + +import org.onosproject.netconf.NetconfDevice; +import org.onosproject.netconf.NetconfDeviceInfo; +import org.onosproject.netconf.NetconfSession; + +import java.io.IOException; + +/** + * Implementation of a NETCONF device. + */ +public class NetconfDeviceImpl implements NetconfDevice { + + private NetconfDeviceInfo netconfDeviceInfo; + private boolean deviceState = false; + private NetconfSession netconfSession; + //private String config; + + public NetconfDeviceImpl(NetconfDeviceInfo deviceInfo) throws IOException { + netconfDeviceInfo = deviceInfo; + try { + netconfSession = new NetconfSessionImpl(netconfDeviceInfo); + } catch (IOException e) { + throw new IOException("Cannot create connection and session", e); + } + deviceState = true; + //config = netconfSession.getConfig("running"); + } + + @Override + public boolean isActive() { + return deviceState; + } + + @Override + public NetconfSession getSession() { + return netconfSession; + } + + @Override + public void disconnect() { + deviceState = false; + netconfSession.close(); + } + + @Override + public NetconfDeviceInfo getDeviceInfo() { + return netconfDeviceInfo; + } +} diff --git a/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java new file mode 100644 index 00000000..8619abc0 --- /dev/null +++ b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java @@ -0,0 +1,396 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.netconf.ctl; + +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; +import com.google.common.base.Preconditions; +import org.onosproject.netconf.NetconfDeviceInfo; +import org.onosproject.netconf.NetconfSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Implementation of a NETCONF session to talk to a device. + */ +public class NetconfSessionImpl implements NetconfSession { + + public static final Logger log = LoggerFactory + .getLogger(NetconfSessionImpl.class); + private static final int CONNECTION_TIMEOUT = 0; + + + private Connection netconfConnection; + private NetconfDeviceInfo deviceInfo; + private Session sshSession; + private boolean connectionActive; + private BufferedReader bufferReader = null; + private PrintWriter out = null; + private int messageID = 0; + + private List<String> deviceCapabilities = + new ArrayList<>( + Arrays.asList("urn:ietf:params:netconf:base:1.0")); + + private String serverCapabilities; + private String endpattern = "]]>]]>"; + + + public NetconfSessionImpl(NetconfDeviceInfo deviceInfo) throws IOException { + this.deviceInfo = deviceInfo; + connectionActive = false; + startConnection(); + } + + + private void startConnection() throws IOException { + if (!connectionActive) { + netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port()); + netconfConnection.connect(null, CONNECTION_TIMEOUT, 0); + boolean isAuthenticated; + try { + if (deviceInfo.getKeyFile() != null) { + isAuthenticated = netconfConnection.authenticateWithPublicKey( + deviceInfo.name(), deviceInfo.getKeyFile(), + deviceInfo.password()); + } else { + log.info("authenticate with username {} and password {}", + deviceInfo.name(), deviceInfo.password()); + isAuthenticated = netconfConnection.authenticateWithPassword( + deviceInfo.name(), deviceInfo.password()); + } + } catch (IOException e) { + throw new IOException("Authentication connection failed:" + + e.getMessage()); + } + + connectionActive = true; + Preconditions.checkArgument(isAuthenticated, + "Authentication password and username failed"); + startSshSession(); + } + } + + private void startSshSession() throws IOException { + try { + sshSession = netconfConnection.openSession(); + sshSession.startSubSystem("netconf"); + bufferReader = new BufferedReader(new InputStreamReader( + sshSession.getStdout())); + out = new PrintWriter(sshSession.getStdin()); + sendHello(); + } catch (IOException e) { + throw new IOException("Failed to create ch.ethz.ssh2.Session session:" + + e.getMessage()); + } + } + + private void sendHello() throws IOException { + serverCapabilities = doRequest(createHelloString()); + } + + private String createHelloString() { + StringBuilder hellobuffer = new StringBuilder(); + hellobuffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); + hellobuffer.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"); + hellobuffer.append(" <capabilities>\n"); + deviceCapabilities.forEach( + cap -> hellobuffer.append(" <capability>" + cap + "</capability>\n")); + hellobuffer.append(" </capabilities>\n"); + hellobuffer.append("</hello>\n"); + hellobuffer.append(endpattern); + return hellobuffer.toString(); + + } + + @Override + public String doRPC(String request) { + String reply = "ERROR"; + try { + reply = doRequest(request); + if (checkReply(reply)) { + return reply; + } else { + return "ERROR " + reply; + } + } catch (IOException e) { + log.error("Problem in the reading from the SSH connection " + e); + } + return reply; + } + + private String doRequest(String request) throws IOException { + log.info("sshState " + sshSession.getState() + "request" + request); + if (sshSession.getState() != 2) { + try { + startSshSession(); + } catch (IOException e) { + log.info("the connection had to be reopened"); + startConnection(); + } + sendHello(); + } + log.info("sshState after" + sshSession.getState()); + out.print(request); + out.flush(); + messageID++; + return readOne(); + } + + @Override + public String get(String request) { + return doRPC(request); + } + + @Override + public String getConfig(String targetConfiguration) { + return getConfig(targetConfiguration, null); + } + + @Override + public String getConfig(String targetConfiguration, String configurationSchema) { + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + rpc.append("<rpc message-id=\"" + messageID + "\" " + + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"); + rpc.append("<get-config>\n"); + rpc.append("<source>\n"); + rpc.append("<" + targetConfiguration + "/>"); + rpc.append("</source>"); + if (configurationSchema != null) { + rpc.append("<filter type=\"subtree\">\n"); + rpc.append(configurationSchema + "\n"); + rpc.append("</filter>\n"); + } + rpc.append("</get-config>\n"); + rpc.append("</rpc>\n"); + rpc.append(endpattern); + String reply = null; + try { + reply = doRequest(rpc.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + + return checkReply(reply) ? reply : null; + } + + @Override + public boolean editConfig(String newConfiguration) { + newConfiguration = newConfiguration + endpattern; + String reply = null; + try { + reply = doRequest(newConfiguration); + } catch (IOException e) { + e.printStackTrace(); + } + return checkReply(reply); + } + + @Override + public boolean copyConfig(String targetConfiguration, String newConfiguration) { + newConfiguration = newConfiguration.trim(); + if (!newConfiguration.startsWith("<configuration>")) { + newConfiguration = "<configuration>" + newConfiguration + + "</configuration>"; + } + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " + + "encoding=\"UTF-8\"?>"); + rpc.append("<rpc>"); + rpc.append("<copy-config>"); + rpc.append("<target>"); + rpc.append("<" + targetConfiguration + "/>"); + rpc.append("</target>"); + rpc.append("<source>"); + rpc.append("<" + newConfiguration + "/>"); + rpc.append("</source>"); + rpc.append("</copy-config>"); + rpc.append("</rpc>"); + rpc.append(endpattern); + String reply = null; + try { + reply = doRequest(rpc.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + + return checkReply(reply); + } + + @Override + public boolean deleteConfig(String targetConfiguration) { + if (targetConfiguration.equals("running")) { + log.warn("Target configuration for delete operation can't be \"running\"", + targetConfiguration); + return false; + } + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " + + "encoding=\"UTF-8\"?>"); + rpc.append("<rpc>"); + rpc.append("<delete-config>"); + rpc.append("<target>"); + rpc.append("<" + targetConfiguration + "/>"); + rpc.append("</target>"); + rpc.append("</delete-config>"); + rpc.append("</rpc>"); + rpc.append(endpattern); + String reply = null; + try { + reply = doRequest(rpc.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + + return checkReply(reply); + } + + @Override + public boolean lock() { + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " + + "encoding=\"UTF-8\"?>"); + rpc.append("<rpc>"); + rpc.append("<lock>"); + rpc.append("<target>"); + rpc.append("<candidate/>"); + rpc.append("</target>"); + rpc.append("</lock>"); + rpc.append("</rpc>"); + rpc.append(endpattern); + String reply = null; + try { + reply = doRequest(rpc.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + return checkReply(reply); + } + + @Override + public boolean unlock() { + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " + + "encoding=\"UTF-8\"?>"); + rpc.append("<rpc>"); + rpc.append("<unlock>"); + rpc.append("<target>"); + rpc.append("<candidate/>"); + rpc.append("</target>"); + rpc.append("</unlock>"); + rpc.append("</rpc>"); + rpc.append(endpattern); + String reply = null; + try { + reply = doRequest(rpc.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + return checkReply(reply); + } + + @Override + public boolean close() { + return close(false); + } + + private boolean close(boolean force) { + StringBuilder rpc = new StringBuilder(); + rpc.append("<rpc>"); + if (force) { + rpc.append("<kill-configuration/>"); + } else { + rpc.append("<close-configuration/>"); + } + rpc.append("<close-configuration/>"); + rpc.append("</rpc>"); + rpc.append(endpattern); + return checkReply(rpc.toString()) ? true : close(true); + } + + @Override + public String getSessionId() { + if (serverCapabilities.contains("<session-id>")) { + String[] outer = serverCapabilities.split("<session-id>"); + Preconditions.checkArgument(outer.length != 1, + "Error in retrieving the session id"); + String[] value = outer[1].split("</session-id>"); + Preconditions.checkArgument(value.length != 1, + "Error in retrieving the session id"); + return value[0]; + } else { + return String.valueOf(-1); + } + } + + @Override + public String getServerCapabilities() { + return serverCapabilities; + } + + @Override + public void setDeviceCapabilities(List<String> capabilities) { + deviceCapabilities = capabilities; + } + + private boolean checkReply(String reply) { + if (reply != null) { + if (!reply.contains("<rpc-error>")) { + return true; + } else if (reply.contains("<ok/>") + || (reply.contains("<rpc-error>") + && reply.contains("warning"))) { + return true; + } + } + return false; + } + + private String readOne() throws IOException { + //TODO try a simple string + final StringWriter reply = new StringWriter(); + while (true) { + int charRead = bufferReader.read(); + if (charRead == -1) { + throw new IOException("Session closed"); + } + + for (int i = 0; i < endpattern.length(); i++) { + if (charRead == endpattern.charAt(i)) { + if (i < endpattern.length() - 1) { + charRead = bufferReader.read(); + } else { + return reply.getBuffer().toString(); + } + } else { + String s = endpattern.substring(0, i); + for (int j = 0; i < s.length(); j++) { + reply.write(s.charAt(j)); + } + reply.write(charRead); + break; + } + } + } + } + +} diff --git a/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java new file mode 100644 index 00000000..84992bf2 --- /dev/null +++ b/framework/src/onos/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf.ctl; diff --git a/framework/src/onos/protocols/netconf/pom.xml b/framework/src/onos/protocols/netconf/pom.xml new file mode 100644 index 00000000..d2f5c432 --- /dev/null +++ b/framework/src/onos/protocols/netconf/pom.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2015 Open Networking Laboratory + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-protocols</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-netconf</artifactId> + <packaging>pom</packaging> + + <modules> + <module>api</module> + <module>rfc</module> + <module>ctl</module> + </modules> + + <description>ONOS NETCONF southbound libraries</description> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-misc</artifactId> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-junit</artifactId> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-buffer</artifactId> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-handler</artifactId> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-core-net</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + </plugins> + </build> +</project> diff --git a/framework/src/onos/protocols/netconf/rfc/pom.xml b/framework/src/onos/protocols/netconf/rfc/pom.xml new file mode 100644 index 00000000..832937bc --- /dev/null +++ b/framework/src/onos/protocols/netconf/rfc/pom.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2015 Open Networking Laboratory + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-netconf</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-netconf-rfc</artifactId> + <packaging>bundle</packaging> +</project> diff --git a/framework/src/onos/protocols/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/Foo.java b/framework/src/onos/protocols/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/Foo.java new file mode 100644 index 00000000..06963b0c --- /dev/null +++ b/framework/src/onos/protocols/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/Foo.java @@ -0,0 +1,7 @@ +package org.onosproject.netconf.rfc; + +/** + * Created by tom on 10/19/15. + */ +public class Foo { +} diff --git a/framework/src/onos/protocols/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java b/framework/src/onos/protocols/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java new file mode 100644 index 00000000..616a7ce5 --- /dev/null +++ b/framework/src/onos/protocols/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf.rfc; |