andrea
Committed by Gerrit Code Review

[ONOS-3253/3144] Insert support for Netconf device configuration, set and get controllers commands

Change-Id: I99188aa18207b9d0b0d935b9f9e61e547f4ddab1
Showing 33 changed files with 1299 additions and 183 deletions
......@@ -59,8 +59,11 @@ public class DeviceSetControllersCommand extends AbstractShellCommand {
ControllerConfig config = h.behaviour(ControllerConfig.class);
print("before:");
config.getControllers().forEach(c -> print(c.target()));
try {
config.setControllers(newControllers);
} catch (NullPointerException e) {
print("No Device with requested parameters {} ", uri);
}
print("after:");
config.getControllers().forEach(c -> print(c.target()));
print("size %d", config.getControllers().size());
......
......@@ -24,5 +24,7 @@
<bundle>mvn:${project.groupId}/onos-ovsdb-api/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-ovsdb-rfc/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-netconf-api/${project.version}</bundle>
</feature>
</features>
......
......@@ -67,6 +67,11 @@
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-netconf-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
......
/*
* 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.driver.netconf;
import com.google.common.base.Preconditions;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.ControllerConfig;
import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.netconf.NetconfController;
import org.onosproject.netconf.NetconfDevice;
import org.slf4j.Logger;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Implementation of controller config which allows to get and set controllers
* through the Netconf protocol.
*/
public class NetconfControllerConfig extends AbstractHandlerBehaviour
implements ControllerConfig {
private final Logger log = getLogger(NetconfControllerConfig.class);
@Override
public List<ControllerInfo> getControllers() {
DriverHandler handler = handler();
NetconfController controller = handler.get(NetconfController.class);
DeviceId ofDeviceId = handler.data().deviceId();
Preconditions.checkNotNull(controller, "Netconf controller is null");
List<ControllerInfo> controllers = new ArrayList<>();
controllers.addAll(XmlConfigParser.parseStreamControllers(XmlConfigParser.
loadXml(new ByteArrayInputStream(controller.
getDevicesMap().get(ofDeviceId).getSession().
getConfig("running").getBytes(StandardCharsets.UTF_8)))));
return controllers;
}
@Override
public void setControllers(List<ControllerInfo> controllers) {
DriverHandler handler = handler();
NetconfController controller = handler.get(NetconfController.class);
DeviceId deviceId = handler.data().deviceId();
Preconditions.checkNotNull(controller, "Netconf controller is null");
try {
NetconfDevice device = controller.getNetconfDevice(deviceId);
log.warn("provider map {}", controller.getDevicesMap());
String config = XmlConfigParser.createControllersConfig(
XmlConfigParser.loadXml(getClass().getResourceAsStream("controllers.xml")),
XmlConfigParser.loadXml(
new ByteArrayInputStream(device.getSession()
.getConfig("running")
.getBytes(
StandardCharsets.UTF_8))),
"running", "merge", "create", controllers
);
device.getSession().editConfig(config.substring(config.indexOf("-->") + 3));
} catch (NullPointerException e) {
log.warn("No NETCONF device with requested parameters " + e);
throw new NullPointerException("No NETCONF device with requested parameters " + e);
}
}
//TODO maybe put method getNetconfClientService like in ovsdb if we need it
}
/*
* 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.driver.netconf;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.tree.ConfigurationNode;
import org.onlab.packet.IpAddress;
import org.onosproject.net.behaviour.ControllerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
/**
* Parser for Netconf XML configurations and replys.
*/
final class XmlConfigParser {
public static final Logger log = LoggerFactory
.getLogger(XmlConfigParser.class);
private XmlConfigParser() {
//not called, preventing any allocation
}
protected static HierarchicalConfiguration loadXml(InputStream xmlStream) {
XMLConfiguration cfg = new XMLConfiguration();
try {
cfg.load(xmlStream);
return cfg;
} catch (ConfigurationException e) {
throw new IllegalArgumentException("Cannot load xml from Stream", e);
}
}
protected static List<ControllerInfo> parseStreamControllers(HierarchicalConfiguration cfg) {
List<ControllerInfo> controllers = new ArrayList<>();
List<HierarchicalConfiguration> fields =
cfg.configurationsAt("data.capable-switch." +
"logical-switches." +
"switch.controllers.controller");
for (HierarchicalConfiguration sub : fields) {
controllers.add(new ControllerInfo(
IpAddress.valueOf(sub.getString("ip-address")),
Integer.parseInt(sub.getString("port")),
sub.getString("protocol")));
}
return controllers;
}
protected static String parseSwitchId(HierarchicalConfiguration cfg) {
HierarchicalConfiguration field =
cfg.configurationAt("data.capable-switch." +
"logical-switches." +
"switch");
return field.getProperty("id").toString();
}
protected static String parseCapableSwitchId(HierarchicalConfiguration cfg) {
HierarchicalConfiguration field =
cfg.configurationAt("data.capable-switch");
return field.getProperty("id").toString();
}
protected static String createControllersConfig(HierarchicalConfiguration cfg,
HierarchicalConfiguration actualCfg,
String target, String netconfOperation,
String controllerOperation,
List<ControllerInfo> controllers) {
//cfg.getKeys().forEachRemaining(key -> System.out.println(key));
cfg.setProperty("edit-config.target", target);
cfg.setProperty("edit-config.default-operation", netconfOperation);
cfg.setProperty("edit-config.config.capable-switch.id",
parseCapableSwitchId(actualCfg));
cfg.setProperty("edit-config.config.capable-switch." +
"logical-switches.switch.id", parseSwitchId(actualCfg));
List<ConfigurationNode> newControllers = new ArrayList<>();
for (ControllerInfo ci : controllers) {
XMLConfiguration controller = new XMLConfiguration();
controller.setRoot(new HierarchicalConfiguration.Node("controller"));
String id = ci.type() + ":" + ci.ip() + ":" + ci.port();
controller.setProperty("id", id);
controller.setProperty("ip-address", ci.ip());
controller.setProperty("port", ci.port());
controller.setProperty("protocol", ci.type());
newControllers.add(controller.getRootNode());
}
cfg.addNodes("edit-config.config.capable-switch.logical-switches." +
"switch.controllers", newControllers);
XMLConfiguration editcfg = (XMLConfiguration) cfg;
StringWriter stringWriter = new StringWriter();
try {
editcfg.save(stringWriter);
} catch (ConfigurationException e) {
e.printStackTrace();
}
String s = stringWriter.toString()
.replaceAll("<controller>",
"<controller nc:operation=\"" + controllerOperation + "\">");
s = s.replace("<target>" + target + "</target>",
"<target><" + target + "/></target>");
return s;
}
//TODO implement mor methods for parsing configuration when you need them
}
/*
* 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.
*/
/**
* Implementations of the Netconf driver behaviours.
*/
package org.onosproject.driver.netconf;
\ No newline at end of file
......@@ -37,6 +37,13 @@
<behaviour api="org.onosproject.net.behaviour.ExtensionResolver"
impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
</driver>
<driver name="ovs-netconf" extends="default"
manufacturer="Nicira, Inc\." hwVersion="Open vSwitch" swVersion="2\..*">
<behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
<behaviour api="org.onosproject.net.behaviour.ControllerConfig"
impl="org.onosproject.driver.netconf.NetconfControllerConfig"/>
</driver>
<driver name="ovs-corsa" extends="ovs"
manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0">
<behaviour api="org.onosproject.net.behaviour.Pipeliner"
......
<!--
~ 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.
-->
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
</target>
<default-operation>
</default-operation>
<config>
<capable-switch xmlns="urn:onf:config:yang">
<id></id>
<logical-switches>
<switch>
<id></id>
<controllers>
</controllers>
</switch>
</logical-switches>
</capable-switch>
</config>
</edit-config>
</rpc>
\ No newline at end of file
/*
* 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.driver.netconf;
import org.junit.Test;
import org.onlab.packet.IpAddress;
import org.onosproject.net.behaviour.ControllerInfo;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertTrue;
import static org.onosproject.driver.netconf.XmlConfigParser.*;
//import static org.junit.Assert.*;
/**
* Test the XML document Parsing for netconf configuration.
*/
public class XmlConfigParserTest {
@Test
public void basics() throws IOException {
InputStream stream = getClass().getResourceAsStream("testConfig.xml");
List<ControllerInfo> controllers = parseStreamControllers(loadXml(stream));
assertTrue(controllers.get(0).equals(new ControllerInfo(
IpAddress.valueOf("10.128.12.1"), 6653, "tcp")));
assertTrue(controllers.get(1).equals(new ControllerInfo(
IpAddress.valueOf("10.128.12.2"), 6654, "tcp")));
}
@Test
public void switchId() {
InputStream stream = getClass().getResourceAsStream("testConfig.xml");
String switchId = parseSwitchId(loadXml(stream));
assertTrue(switchId.equals("ofc-bridge"));
}
@Test
public void capableSwitchId() {
InputStream stream = getClass().getResourceAsStream("testConfig.xml");
String capableSwitchId = parseCapableSwitchId(loadXml(stream));
assertTrue(capableSwitchId.equals("openvswitch"));
}
@Test
public void controllersConfig() {
InputStream streamOrig = getClass().getResourceAsStream("testConfig.xml");
InputStream streamCFG = XmlConfigParser.class
.getResourceAsStream("controllers.xml");
String config = createControllersConfig(loadXml(streamCFG),
loadXml(streamOrig), "running", "merge",
"create", new ArrayList<>(Arrays.asList(
new ControllerInfo(IpAddress.valueOf("192.168.1.1"),
5000, "tcp"))));
assertTrue(config.contains("192.168.1.1"));
assertTrue(config.contains("tcp"));
assertTrue(config.contains("5000"));
}
}
\ No newline at end of file
<?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.
-->
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="7">
<data>
<capable-switch xmlns="urn:onf:config:yang">
<id>openvswitch</id>
<resources>
<port>
<name>ofc-bridge</name>
<requested-number>666</requested-number>
<configuration>
<admin-state>down</admin-state>
<no-receive>false</no-receive>
<no-forward>false</no-forward>
<no-packet-in>false</no-packet-in>
</configuration>
</port>
</resources>
<logical-switches>
<switch>
<id>ofc-bridge</id>
<datapath-id>00:01:02:03:04:05:06:07</datapath-id>
<lost-connection-behavior>failSecureMode</lost-connection-behavior>
<controllers>
<controller>
<id>(null)</id>
<ip-address>10.128.12.1</ip-address>
<port>6653</port>
<protocol>tcp</protocol>
</controller>
<controller>
<id>(null)</id>
<ip-address>10.128.12.2</ip-address>
<port>6654</port>
<protocol>tcp</protocol>
</controller>
</controllers>
<resources>
<port>ofc-bridge</port>
</resources>
</switch>
</logical-switches>
</capable-switch>
</data>
</rpc-reply>
\ No newline at end of file
......@@ -40,11 +40,6 @@
<artifactId>netty-transport-native-epoll</artifactId>
<version>${netty4.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-netconf-rfc</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
......
package org.onosproject.netconf;
/**
* Created by tom on 10/19/15.
*/
public class Foo {
}
/*
* 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);
}
/*
* 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
/*
* 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;
}
}
/*
* 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);
}
/*
* 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);
}
......@@ -39,9 +39,53 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-netconf-rfc</artifactId>
<version>${project.version}</version>
<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>
......
package org.onosproject.netconf.ctl;
/**
* Created by tom on 10/19/15.
*/
public class Foo {
}
/*
* 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;
}
}
/*
* 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;
}
}
......@@ -27,6 +27,12 @@
<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>
......@@ -54,6 +60,11 @@
<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>
......@@ -68,10 +79,4 @@
</plugin>
</plugins>
</build>
<modules>
<module>api</module>
<module>rfc</module>
<module>ctl</module>
</modules>
</project>
......
......@@ -27,5 +27,4 @@
<artifactId>onos-netconf-rfc</artifactId>
<packaging>bundle</packaging>
</project>
......
......@@ -19,6 +19,13 @@
features="${project.artifactId}">
<description>${project.description}</description>
<artifact>mvn:${project.groupId}/onos-netconf-rfc/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-netconf-api/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-netconf-ctl/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-drivers/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</artifact>
<!--<artifact>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</artifact>-->
<!-- Question: should there be the jnc stuff here? Or is it just for testing -->
</app>
......
......@@ -20,6 +20,9 @@
description="${project.description}">
<feature>onos-api</feature>
<bundle>mvn:io.netty/netty/3.9.2.Final</bundle>
<bundle>mvn:${project.groupId}/onos-netconf-api/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-netconf-ctl/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</bundle>
<!-- Question: should there be the jnc stuff here? Or is it just for testing -->
</feature>
......
......@@ -33,129 +33,29 @@
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>262</version>
</dependency>
<dependency>
<!-- TODO: change this appropriately when the official TailF JNC is available -->
<groupId>org.onosproject</groupId>
<artifactId>jnc</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.4</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<artifactId>onlab-junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onlab-junit</artifactId>
<scope>test</scope>
<artifactId>onos-netconf-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
<groupId>org.onosproject</groupId>
<artifactId>onos-netconf-ctl</artifactId>
<version>${project.version}</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>com.tailf:JNC</artifact>
<includes>
<include>com/tailf/jnc/**</include>
</includes>
</filter>
<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-scr-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Export-Package>
com.tailf.jnc,
ch.ethz.ssh2,
ch.ethz.ssh2.auth,
ch.ethz.ssh2.channel,
ch.ethz.ssh2.crypto,
ch.ethz.ssh2.crypto.cipher,
ch.ethz.ssh2.crypto.dh,
ch.ethz.ssh2.crypto.digest,
ch.ethz.ssh2.log,
ch.ethz.ssh2.packets,
ch.ethz.ssh2.server,
ch.ethz.ssh2.sftp,
ch.ethz.ssh2.signature,
ch.ethz.ssh2.transport,
ch.ethz.ssh2.util,
org.jdom2,
org.jdom2.input,
org.jdom2.output,
org.jdom2.adapters,
org.jdom2.filter,
org.jdom2.internal,
org.jdom2.located,
org.jdom2.transform,
org.jdom2.util,
org.jdom2.xpath,
org.jdom2.input.sax,
org.jdom2.input.stax,
org.jdom2.output.support,
org.jdom2.xpath.jaxen,
org.jdom2.xpath.util
</Export-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.onosproject</groupId>
<artifactId>onos-maven-plugin</artifactId>
</plugin>
......
/*
* 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.provider.netconf.device.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.annotations.Beta;
import com.google.common.collect.Sets;
import org.onlab.packet.IpAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.net.config.Config;
import java.util.Set;
/**
* Configuration for Netconf provider.
*/
@Beta
public class NetconfProviderConfig extends Config<ApplicationId> {
public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
private static final String IP = "ip";
private static final int DEFAULT_TCP_PORT = 830;
private static final String PORT = "port";
private static final String NAME = "name";
private static final String PASSWORD = "password";
public Set<NetconfDeviceAddress> getDevicesAddresses() throws ConfigException {
Set<NetconfDeviceAddress> devicesAddresses = Sets.newHashSet();
try {
for (JsonNode node : array) {
String ip = node.path(IP).asText();
IpAddress ipAddr = ip.isEmpty() ? null : IpAddress.valueOf(ip);
int port = node.path(PORT).asInt(DEFAULT_TCP_PORT);
String name = node.path(NAME).asText();
String password = node.path(PASSWORD).asText();
devicesAddresses.add(new NetconfDeviceAddress(ipAddr, port, name, password));
}
} catch (IllegalArgumentException e) {
throw new ConfigException(CONFIG_VALUE_ERROR, e);
}
return devicesAddresses;
}
public class NetconfDeviceAddress {
private final IpAddress ip;
private final int port;
private final String name;
private final String password;
public NetconfDeviceAddress(IpAddress ip, int port, String name, String password) {
this.ip = ip;
this.port = port;
this.name = name;
this.password = password;
}
public IpAddress ip() {
return ip;
}
public int port() {
return port;
}
public String name() {
return name;
}
public String password() {
return password;
}
}
}
/*
* 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.provider.netconf.device.impl;
public final class NetconfDeviceProviderTestConstant {
private NetconfDeviceProviderTestConstant() {
}
public static final int ZERO = 0;
public static final int EVENTINTERVAL = 5;
public static final String DEV_CONFIG = "devConfigs";
public static final String CONFIG_WITH_INVALID_ENTRY_NUMBER = "cisco:cisco"
+ "@10.18.11.14:cisco:active";
public static final String CONFIG_WITH_NULL_ENTRY = "null:null@null:0:active";
public static final String CONFIG_WITH_DIFFERENT_DEVICE_STATE = "cisco:cisco@10.18.11.14:22:active,"
+ "cisco:cisco@10.18.11.18:22:inactive,cisco:cisco@10.18.11.14:22:invalid,"
+ "cisco:cisco@10.18.11.14:22:null";
public static final String CONFIG_WITH_ARRAY_OUT_OF_BOUNDEX = "@10.18.11.14:22:active";
public static final String CONFIG_ENTRY_FOR_DEACTIVATE = "netconf:cisco"
+ "@10.18.11.14:22:active";
public static final String DEVICE_IP = "10.18.14.19";
public static final int DEVICE_PORT = 22;
public static final String DEVICE_USERNAME = "cisco";
public static final String DEVICE_PASSWORD = "cisco";
public static final String AT_THE_RATE = "@";
public static final String COLON = ":";
public static final String NULL = "";
public static final String NULL_NULL = "null,null";
public static final String SCHEME_NETCONF = "netconf";
public static final String DEVICE_ID = "of:0000000000000001";
}
{
"devices":{
"netconf:mininet@10.1.9.24:1830":{
"basic":{
"driver":"ovs-netconf"
}
}
},
"apps":{
"org.onosproject.netconf":{
"devices":[{
"name":"mininet",
"password":"mininet",
"ip":"10.1.9.24",
"port":1830
}]
}
}
}
\ No newline at end of file