netconf chunked framing v2
Change-Id: I93fad5c44315960ca6aebe5b0944947ac8bf6a51
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
index 8fdd5ff..1b5e7fa 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
@@ -27,7 +27,6 @@
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@@ -35,6 +34,7 @@
import java.util.concurrent.FutureTask;
import java.util.regex.Pattern;
+import com.google.common.collect.ImmutableList;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.SshServer;
@@ -53,7 +53,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.collect.ImmutableList;
/**
* Unit tests for NetconfSession.
@@ -89,22 +88,10 @@
+ "</edit-config>\n"
+ "</rpc>]]>]]>";
- static final List<String> DEFAULT_CAPABILITIES = ImmutableList.<String>builder()
- .add("urn:ietf:params:netconf:base:1.0")
- .add("urn:ietf:params:netconf:base:1.1")
- .add("urn:ietf:params:netconf:capability:writable-running:1.0")
- .add("urn:ietf:params:netconf:capability:candidate:1.0")
- .add("urn:ietf:params:netconf:capability:startup:1.0")
- .add("urn:ietf:params:netconf:capability:rollback-on-error:1.0")
- .add("urn:ietf:params:netconf:capability:interleave:1.0")
- .add("urn:ietf:params:netconf:capability:notification:1.0")
- .add("urn:ietf:params:netconf:capability:validate:1.0")
- .add("urn:ietf:params:netconf:capability:validate:1.1")
- .build();
-
-
private static NetconfSession session1;
private static NetconfSession session2;
+ private static NetconfSession session3;
+ private static NetconfSession session4;
private static SshServer sshServerNetconf;
@BeforeClass
@@ -132,17 +119,30 @@
NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(
TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), PORT_NUMBER);
- session1 = new NetconfSessionImpl(deviceInfo);
+ session1 = new NetconfSessionImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session1.getSessionId());
assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("-1"));
assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("0"));
- assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
-
- session2 = new NetconfSessionImpl(deviceInfo);
+ assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(
+ NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES.toArray()));
+ session2 = new NetconfSessionImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session2.getSessionId());
assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("-1"));
assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("0"));
- assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
+ assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(
+ NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES.toArray()));
+ session3 = new NetconfSessionImpl(deviceInfo);
+ log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session3.getSessionId());
+ assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("-1"));
+ assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("0"));
+ assertThat(session3.getDeviceCapabilitiesSet(), containsInAnyOrder(
+ NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES_1_1.toArray()));
+ session4 = new NetconfSessionImpl(deviceInfo);
+ log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session4.getSessionId());
+ assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("-1"));
+ assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("0"));
+ assertThat(session4.getDeviceCapabilitiesSet(), containsInAnyOrder(
+ NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES_1_1.toArray()));
}
@AfterClass
@@ -153,6 +153,12 @@
if (session2 != null) {
session2.close();
}
+ if (session3 != null) {
+ session3.close();
+ }
+ if (session4 != null) {
+ session4.close();
+ }
sshServerNetconf.stop();
}
@@ -163,8 +169,23 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF edit-config command failed",
- session1.editConfig(DatastoreId.RUNNING,
- null, SAMPLE_REQUEST));
+ session1.editConfig(DatastoreId.RUNNING,
+ null, SAMPLE_REQUEST));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF edit-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing edit-config async");
+ }
+
+ @Test
+ public void testEditConfigRequestWithChunkedFraming() {
+ log.info("Starting edit-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF edit-config command failed",
+ session3.editConfig(DatastoreId.RUNNING,
+ null, SAMPLE_REQUEST));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -178,7 +199,21 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF edit-config command failed",
- session1.editConfig(EDIT_CONFIG_REQUEST));
+ session1.editConfig(NetconfSessionMinaImplTest.EDIT_CONFIG_REQUEST));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF edit-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing edit-config async");
+ }
+
+ @Test
+ public void testEditConfigRequestWithOnlyNewConfigurationWithChunkedFraming() {
+ log.info("Starting edit-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF edit-config command failed",
+ session3.editConfig(NetconfSessionMinaImplTest.EDIT_CONFIG_REQUEST));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -192,7 +227,21 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertFalse("NETCONF delete-config command failed",
- session1.deleteConfig(DatastoreId.RUNNING));
+ session1.deleteConfig(DatastoreId.RUNNING));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF delete-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing delete-config async");
+ }
+
+ @Test
+ public void testDeleteConfigRequestWithRunningTargetConfigurationWithChunkedFraming() {
+ log.info("Starting delete-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertFalse("NETCONF delete-config command failed",
+ session3.deleteConfig(DatastoreId.RUNNING));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF delete-config test failed: " + e.getMessage());
@@ -206,8 +255,23 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF copy-config command failed",
- session1.copyConfig(DatastoreId.RUNNING,
- DatastoreId.CANDIDATE));
+ session1.copyConfig(DatastoreId.RUNNING,
+ DatastoreId.CANDIDATE));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF copy-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing copy-config async");
+ }
+
+ @Test
+ public void testCopyConfigRequestWithChunkedFraming() {
+ log.info("Starting copy-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF copy-config command failed",
+ session3.copyConfig(DatastoreId.RUNNING,
+ DatastoreId.CANDIDATE));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF copy-config test failed: " + e.getMessage());
@@ -221,8 +285,23 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF copy-config command failed",
- session1.copyConfig(DatastoreId.RUNNING,
- "<configuration><device-specific/></configuration>"));
+ session1.copyConfig(DatastoreId.RUNNING,
+ "<configuration><device-specific/></configuration>"));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF copy-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing copy-config XML async");
+ }
+
+ @Test
+ public void testCopyConfigXmlWithChunkedFraming() {
+ log.info("Starting copy-config XML async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF copy-config command failed",
+ session3.copyConfig(DatastoreId.RUNNING,
+ "<configuration><device-specific/></configuration>"));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF copy-config test failed: " + e.getMessage());
@@ -237,10 +316,27 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF copy-config command failed",
- session1.copyConfig(DatastoreId.RUNNING,
- "<config>"
- + "<configuration><device-specific/></configuration>"
- + "</config>"));
+ session1.copyConfig(DatastoreId.RUNNING,
+ "<config>"
+ + "<configuration><device-specific/></configuration>"
+ + "</config>"));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF copy-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing copy-config bare XML async");
+ }
+
+ @Test
+ public void testCopyConfigBareXmlWithChunkedFraming() {
+ log.info("Starting copy-config bare XML async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF copy-config command failed",
+ session3.copyConfig(DatastoreId.RUNNING,
+ "<config>"
+ + "<configuration><device-specific/></configuration>"
+ + "</config>"));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF copy-config test failed: " + e.getMessage());
@@ -254,10 +350,32 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF get-config running command failed. ",
- GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+ NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING,
+ SAMPLE_REQUEST)).matches());
assertTrue("NETCONF get-config candidate command failed. ",
- GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+ NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE,
+ SAMPLE_REQUEST)).matches());
+
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF get-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing get-config async");
+ }
+
+ @Test
+ public void testGetConfigRequestWithChunkedFraming() {
+ log.info("Starting get-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF get-config running command failed. ",
+ NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session3.getConfig(RUNNING,
+ SAMPLE_REQUEST)).matches());
+
+ assertTrue("NETCONF get-config candidate command failed. ",
+ NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session3.getConfig(CANDIDATE,
+ SAMPLE_REQUEST)).matches());
} catch (NetconfException e) {
e.printStackTrace();
@@ -272,7 +390,23 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF get running command failed. ",
- GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+ NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST,
+ null)).matches());
+
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF get test failed: " + e.getMessage());
+ }
+ log.info("Finishing get async");
+ }
+
+ @Test
+ public void testGetRequestWithChunkedFraming() {
+ log.info("Starting get async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF get running command failed. ",
+ NetconfSessionMinaImplTest.GET_REPLY_PATTERN.matcher(session3.get(SAMPLE_REQUEST, null)).matches());
} catch (NetconfException e) {
e.printStackTrace();
@@ -295,6 +429,19 @@
}
@Test
+ public void testLockRequestWithChunkedFraming() {
+ log.info("Starting lock async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF lock request failed", session3.lock());
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF lock test failed: " + e.getMessage());
+ }
+ log.info("Finishing lock async");
+ }
+
+ @Test
public void testUnLockRequest() {
log.info("Starting unlock async");
assertNotNull("Incorrect sessionId", session1.getSessionId());
@@ -307,6 +454,19 @@
log.info("Finishing unlock async");
}
+ @Test
+ public void testUnLockRequestWithChunkedFraming() {
+ log.info("Starting unlock async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF unlock request failed", session3.unlock());
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF unlock test failed: " + e.getMessage());
+ }
+ log.info("Finishing unlock async");
+ }
+
@Test
public void testConcurrentSameSessionAccess() throws InterruptedException {
@@ -335,6 +495,32 @@
}
@Test
+ public void testConcurrentSameSessionAccessWithChunkedFraming() throws InterruptedException {
+ NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+ NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session3, RUNNING, "startup");
+
+ FutureTask<Boolean> futureCopyConfig1 = new FutureTask<>(testCopyConfig1);
+ FutureTask<Boolean> futureCopyConfig2 = new FutureTask<>(testCopyConfig2);
+
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ log.info("Starting concurrent execution of copy-config through same session");
+ executor.execute(futureCopyConfig1);
+ executor.execute(futureCopyConfig2);
+
+ int count = 0;
+ while (count < 10) {
+ if (futureCopyConfig1.isDone() && futureCopyConfig2.isDone()) {
+ executor.shutdown();
+ log.info("Finished concurrent same session execution");
+ return;
+ }
+ Thread.sleep(100L);
+ count++;
+ }
+ fail("NETCONF test failed to complete.");
+ }
+
+ @Test
public void test2SessionAccess() throws InterruptedException {
NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session2, RUNNING, "candidate");
@@ -360,9 +546,39 @@
fail("NETCONF test failed to complete.");
}
+ @Test
+ public void test2SessionAccessWithChunkedFraming() throws InterruptedException {
+ NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+ NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session4, RUNNING, "candidate");
- public static String getTestHelloReply(Optional<Long> sessionId) {
- return getTestHelloReply(DEFAULT_CAPABILITIES, sessionId);
+ FutureTask<Boolean> futureCopySession1 = new FutureTask<>(testCopySession1);
+ FutureTask<Boolean> futureCopySession2 = new FutureTask<>(testCopySession2);
+
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ log.info("Starting concurrent execution of copy-config through 2 different sessions");
+ executor.execute(futureCopySession1);
+ executor.execute(futureCopySession2);
+
+ int count = 0;
+ while (count < 10) {
+ if (futureCopySession1.isDone() && futureCopySession2.isDone()) {
+ executor.shutdown();
+ log.info("Finished concurrent 2 session execution");
+ return;
+ }
+ Thread.sleep(100L);
+ count++;
+ }
+ fail("NETCONF test failed to complete.");
+ }
+
+
+ public static String getTestHelloReply(Optional<Long> sessionId, boolean useChunkedFraming) {
+ if (useChunkedFraming) {
+ return getTestHelloReply(NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES_1_1, sessionId);
+ } else {
+ return getTestHelloReply(NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES, sessionId);
+ }
}
public static String getTestHelloReply(Collection<String> capabilities, Optional<Long> sessionId) {
@@ -414,11 +630,21 @@
public static final Pattern HELLO_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
- + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
- + "( *)(<capabilities>)\\R?"
- + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
- + "( *)(</capabilities>)\\R?"
- + "(</hello>)\\R? *",
+ + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ + "( *)(<capabilities>)\\R?"
+ + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
+ + "( *)(</capabilities>)\\R?"
+ + "(</hello>)\\R? *",
+ Pattern.DOTALL);
+
+ public static final Pattern HELLO_REQ_PATTERN_1_1 =
+ Pattern.compile("(<\\?xml).*"
+ + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ + "( *)(<capabilities>)\\R?"
+ + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
+ + "( *)(<capability>urn:ietf:params:netconf:base:1.1</capability>)\\R?"
+ + "( *)(</capabilities>)\\R?"
+ + "(</hello>)\\R? *",
Pattern.DOTALL);
public static final Pattern EDIT_CONFIG_REQ_PATTERN =
@@ -426,8 +652,8 @@
+ "(<rpc message-id=\")[0-9]*(\") *(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ "(<edit-config>)\\R?"
+ "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
- + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
- + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+ + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ ".*"
+ "(</config>)\\R?(</edit-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
@@ -435,23 +661,23 @@
public static final Pattern LOCK_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
- + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
- + "message-id=\")[0-9]*(\">)\\R?"
- + "(<lock>)\\R?"
- + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
- + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
- + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
- + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+ + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+ + "message-id=\")[0-9]*(\">)\\R?"
+ + "(<lock>)\\R?"
+ + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+ + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+ + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
public static final Pattern UNLOCK_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
- + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
- + "message-id=\")[0-9]*(\">)\\R?"
- + "(<unlock>)\\R?"
- + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
- + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
- + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
- + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+ + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+ + "message-id=\")[0-9]*(\">)\\R?"
+ + "(<unlock>)\\R?"
+ + "(<target>\\R?((<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+ + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+ + "(<" + DatastoreId.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
public static final Pattern COPY_CONFIG_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
@@ -459,17 +685,17 @@
+ "(<copy-config>)\\R?"
+ "(<target>\\R?"
+ "("
- + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
- + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
- + "(<" + DatastoreId.STARTUP.toString() + "/>)"
+ + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+ + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+ + "(<" + DatastoreId.STARTUP.toString() + "/>)"
+ ")\\R?"
+ "</target>)\\R?"
+ "(<source>)\\R?"
+ "("
- + "(<config>)(.*)(</config>)|"
- + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
- + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
- + "(<" + DatastoreId.STARTUP.toString() + "/>)"
+ + "(<config>)(.*)(</config>)|"
+ + "(<" + DatastoreId.CANDIDATE.toString() + "/>)|"
+ + "(<" + DatastoreId.RUNNING.toString() + "/>)|"
+ + "(<" + DatastoreId.STARTUP.toString() + "/>)"
+ ")\\R?"
+ "(</source>)\\R?"
+ "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
@@ -478,18 +704,14 @@
Pattern.compile("(<\\?xml).*"
+ "(<rpc message-id=\")[0-9]*(\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ "(<get-config>)\\R?" + "(<source>)\\R?((<"
- + DatastoreId.CANDIDATE.toString()
- + "/>)|(<" + DatastoreId.RUNNING.toString()
- + "/>)|(<" + DatastoreId.STARTUP.toString()
- + "/>))\\R?(</source>)\\R?"
+ + DatastoreId.CANDIDATE.toString()
+ + "/>)|(<" + DatastoreId.RUNNING.toString()
+ + "/>)|(<" + DatastoreId.STARTUP.toString()
+ + "/>))\\R?(</source>)\\R?"
+ "(<filter type=\"subtree\">).*(</filter>)\\R?"
+ "(</get-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
- public static final Pattern GET_REPLY_PATTERN =
- Pattern.compile("(<\\?xml).*"
- + "(<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
- + "(<data>).*(</data>)\\R?"
- + "(</rpc-reply>)\\R?", Pattern.DOTALL);
+
public static final Pattern GET_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
@@ -514,4 +736,4 @@
return session.copyConfig(target, source);
}
}
-}
+}
\ No newline at end of file
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
index 4665125..8fd4a86 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
@@ -26,11 +26,11 @@
import org.junit.BeforeClass;
import org.junit.Test;
import org.onlab.junit.TestTools;
-import org.onlab.packet.Ip4Address;
import org.onosproject.netconf.NetconfDeviceInfo;
import org.onosproject.netconf.NetconfException;
import org.onosproject.netconf.NetconfSession;
-import org.onosproject.netconf.TargetConfig;
+import org.onosproject.netconf.DatastoreId;
+import org.onlab.packet.Ip4Address;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,9 +46,14 @@
import java.util.regex.Pattern;
import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.junit.Assert.*;
-import static org.onosproject.netconf.TargetConfig.CANDIDATE;
-import static org.onosproject.netconf.TargetConfig.RUNNING;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.junit.Assert.assertFalse;
+import static org.onosproject.netconf.DatastoreId.CANDIDATE;
+import static org.onosproject.netconf.DatastoreId.RUNNING;
+import static org.onosproject.netconf.DatastoreId.STARTUP;
/**
* Unit tests for NetconfSession.
@@ -73,7 +78,7 @@
+ "<some-child-element/>"
+ "</some-yang-element>";
- private static final String EDIT_CONFIG_REQUEST =
+ protected static final String EDIT_CONFIG_REQUEST =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><rpc message-id=\"6\" "
+ "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ "<edit-config>\n"
@@ -86,6 +91,18 @@
static final List<String> DEFAULT_CAPABILITIES = ImmutableList.<String>builder()
.add("urn:ietf:params:netconf:base:1.0")
+ .add("urn:ietf:params:netconf:capability:writable-running:1.0")
+ .add("urn:ietf:params:netconf:capability:candidate:1.0")
+ .add("urn:ietf:params:netconf:capability:startup:1.0")
+ .add("urn:ietf:params:netconf:capability:rollback-on-error:1.0")
+ .add("urn:ietf:params:netconf:capability:interleave:1.0")
+ .add("urn:ietf:params:netconf:capability:notification:1.0")
+ .add("urn:ietf:params:netconf:capability:validate:1.0")
+ .add("urn:ietf:params:netconf:capability:validate:1.1")
+ .build();
+
+ static final List<String> DEFAULT_CAPABILITIES_1_1 = ImmutableList.<String>builder()
+ .add("urn:ietf:params:netconf:base:1.0")
.add("urn:ietf:params:netconf:base:1.1")
.add("urn:ietf:params:netconf:capability:writable-running:1.0")
.add("urn:ietf:params:netconf:capability:candidate:1.0")
@@ -100,6 +117,8 @@
private static NetconfSession session1;
private static NetconfSession session2;
+ private static NetconfSession session3;
+ private static NetconfSession session4;
private static SshServer sshServerNetconf;
@BeforeClass
@@ -127,17 +146,29 @@
NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(
TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), PORT_NUMBER);
- session1 = new NetconfSessionMinaImpl(deviceInfo);
+ session1 = new NetconfSessionMinaImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session1.getSessionId());
assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("-1"));
assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("0"));
assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
- session2 = new NetconfSessionMinaImpl(deviceInfo);
+ session2 = new NetconfSessionMinaImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session2.getSessionId());
assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("-1"));
assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("0"));
assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
+
+ session3 = new NetconfSessionMinaImpl(deviceInfo);
+ log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session3.getSessionId());
+ assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("-1"));
+ assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("0"));
+ assertThat(session3.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES_1_1.toArray()));
+
+ session4 = new NetconfSessionMinaImpl(deviceInfo);
+ log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session4.getSessionId());
+ assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("-1"));
+ assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("0"));
+ assertThat(session4.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES_1_1.toArray()));
}
@AfterClass
@@ -148,6 +179,12 @@
if (session2 != null) {
session2.close();
}
+ if (session3 != null) {
+ session3.close();
+ }
+ if (session4 != null) {
+ session4.close();
+ }
sshServerNetconf.stop();
}
@@ -158,8 +195,24 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF edit-config command failed",
- session1.editConfig(TargetConfig.RUNNING.toString(),
- null, SAMPLE_REQUEST));
+ session1.editConfig(RUNNING.toString(),
+ null, SAMPLE_REQUEST));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF edit-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing edit-config async");
+ }
+
+ @Test
+ public void testEditConfigRequestWithChunkedFraming() {
+ log.info("Starting edit-config async");
+
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF edit-config command failed",
+ session3.editConfig(RUNNING.toString(),
+ null, SAMPLE_REQUEST));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -173,7 +226,7 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF edit-config command failed",
- session1.editConfig(EDIT_CONFIG_REQUEST));
+ session1.editConfig(EDIT_CONFIG_REQUEST));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -182,12 +235,40 @@
}
@Test
- public void testDeleteConfigRequestWithRunningTargetConfiguration() {
+ public void testEditConfigRequestWithOnlyNewConfigurationWithChunkedFraming() {
+ log.info("Starting edit-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF edit-config command failed",
+ session3.editConfig(EDIT_CONFIG_REQUEST));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF edit-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing edit-config async");
+ }
+
+ @Test
+ public void testDeleteConfigRequestWithRunningDatastoreIdDuration() {
log.info("Starting delete-config async");
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertFalse("NETCONF delete-config command failed",
- session1.deleteConfig(TargetConfig.RUNNING));
+ session1.deleteConfig(RUNNING));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF delete-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing delete-config async");
+ }
+
+ @Test
+ public void testDeleteConfigRequestWithRunningDatastoreIdDurationWithChunkedFraming() {
+ log.info("Starting delete-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertFalse("NETCONF delete-config command failed",
+ session3.deleteConfig(RUNNING));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF delete-config test failed: " + e.getMessage());
@@ -201,8 +282,23 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF copy-config command failed",
- session1.copyConfig(TargetConfig.RUNNING.toString(),
- "candidate"));
+ session1.copyConfig(RUNNING.toString(),
+ "candidate"));
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF edit-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing copy-config async");
+ }
+
+ @Test
+ public void testCopyConfigRequestWithChunkedFraming() {
+ log.info("Starting copy-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF copy-config command failed",
+ session3.copyConfig(RUNNING.toString(),
+ "candidate"));
} catch (NetconfException e) {
e.printStackTrace();
fail("NETCONF edit-config test failed: " + e.getMessage());
@@ -216,10 +312,28 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF get-config running command failed. ",
- GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+ GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
assertTrue("NETCONF get-config candidate command failed. ",
- GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+ GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF get-config test failed: " + e.getMessage());
+ }
+ log.info("Finishing get-config async");
+ }
+
+ @Test
+ public void testGetConfigRequestWithChunkedFraming() {
+ log.info("Starting get-config async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF get-config running command failed. ",
+ GET_REPLY_PATTERN.matcher(session3.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+
+ assertTrue("NETCONF get-config candidate command failed. ",
+ GET_REPLY_PATTERN.matcher(session3.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
} catch (NetconfException e) {
e.printStackTrace();
@@ -234,7 +348,22 @@
assertNotNull("Incorrect sessionId", session1.getSessionId());
try {
assertTrue("NETCONF get running command failed. ",
- GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+ GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF get test failed: " + e.getMessage());
+ }
+ log.info("Finishing get async");
+ }
+
+ @Test
+ public void testGetRequestWithChunkedFraming() {
+ log.info("Starting get async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF get running command failed. ",
+ GET_REPLY_PATTERN.matcher(session3.get(SAMPLE_REQUEST, null)).matches());
} catch (NetconfException e) {
e.printStackTrace();
@@ -257,6 +386,19 @@
}
@Test
+ public void testLockRequestWithChunkedFraming() {
+ log.info("Starting lock async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF lock request failed", session3.lock());
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF lock test failed: " + e.getMessage());
+ }
+ log.info("Finishing lock async");
+ }
+
+ @Test
public void testUnLockRequest() {
log.info("Starting unlock async");
assertNotNull("Incorrect sessionId", session1.getSessionId());
@@ -269,6 +411,19 @@
log.info("Finishing unlock async");
}
+ @Test
+ public void testUnLockRequestWithChunkedFraming() {
+ log.info("Starting unlock async");
+ assertNotNull("Incorrect sessionId", session3.getSessionId());
+ try {
+ assertTrue("NETCONF unlock request failed", session3.unlock());
+ } catch (NetconfException e) {
+ e.printStackTrace();
+ fail("NETCONF unlock test failed: " + e.getMessage());
+ }
+ log.info("Finishing unlock async");
+ }
+
@Test
public void testConcurrentSameSessionAccess() throws InterruptedException {
@@ -297,6 +452,32 @@
}
@Test
+ public void testConcurrentSameSessionAccessWithChunkedFraming() throws InterruptedException {
+ NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+ NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session3, RUNNING, "startup");
+
+ FutureTask<Boolean> futureCopyConfig1 = new FutureTask<>(testCopyConfig1);
+ FutureTask<Boolean> futureCopyConfig2 = new FutureTask<>(testCopyConfig2);
+
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ log.info("Starting concurrent execution of copy-config through same session");
+ executor.execute(futureCopyConfig1);
+ executor.execute(futureCopyConfig2);
+
+ int count = 0;
+ while (count < 10) {
+ if (futureCopyConfig1.isDone() && futureCopyConfig2.isDone()) {
+ executor.shutdown();
+ log.info("Finished concurrent same session execution");
+ return;
+ }
+ Thread.sleep(100L);
+ count++;
+ }
+ fail("NETCONF test failed to complete.");
+ }
+
+ @Test
public void test2SessionAccess() throws InterruptedException {
NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session2, RUNNING, "candidate");
@@ -322,6 +503,32 @@
fail("NETCONF test failed to complete.");
}
+ @Test
+ public void test2SessionAccessWithChunkedFraming() throws InterruptedException {
+ NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
+ NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session4, RUNNING, "candidate");
+
+ FutureTask<Boolean> futureCopySession1 = new FutureTask<>(testCopySession1);
+ FutureTask<Boolean> futureCopySession2 = new FutureTask<>(testCopySession2);
+
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ log.info("Starting concurrent execution of copy-config through 2 different sessions");
+ executor.execute(futureCopySession1);
+ executor.execute(futureCopySession2);
+
+ int count = 0;
+ while (count < 10) {
+ if (futureCopySession1.isDone() && futureCopySession2.isDone()) {
+ executor.shutdown();
+ log.info("Finished concurrent 2 session execution");
+ return;
+ }
+ Thread.sleep(100L);
+ count++;
+ }
+ fail("NETCONF test failed to complete.");
+ }
+
public static String getTestHelloReply(Optional<Long> sessionId) {
return getTestHelloReply(DEFAULT_CAPABILITIES, sessionId);
@@ -376,20 +583,21 @@
public static final Pattern HELLO_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
- + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
- + "( *)(<capabilities>)\\R?"
- + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
- + "( *)(</capabilities>)\\R?"
- + "(</hello>)\\R? *",
+ + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ + "( *)(<capabilities>)\\R?"
+ + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
+ + "( *)(<capability>urn:ietf:params:netconf:base:1.1</capability>)\\R?"
+ + "( *)(</capabilities>)\\R?"
+ + "(</hello>)\\R? *",
Pattern.DOTALL);
public static final Pattern EDIT_CONFIG_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
+ "(<rpc message-id=\")[0-9]*(\") *(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ "(<edit-config>)\\R?"
- + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
- + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
- + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+ + "(<" + RUNNING.toString() + "/>)|"
+ + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ ".*"
+ "(</config>)\\R?(</edit-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
@@ -397,46 +605,46 @@
public static final Pattern LOCK_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
- + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
- + "message-id=\")[0-9]*(\">)\\R?"
- + "(<lock>)\\R?"
- + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
- + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
- + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
- + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+ + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+ + "message-id=\")[0-9]*(\">)\\R?"
+ + "(<lock>)\\R?"
+ + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+ + "(<" + RUNNING.toString() + "/>)|"
+ + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
public static final Pattern UNLOCK_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
- + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
- + "message-id=\")[0-9]*(\">)\\R?"
- + "(<unlock>)\\R?"
- + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
- + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
- + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
- + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+ + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+ + "message-id=\")[0-9]*(\">)\\R?"
+ + "(<unlock>)\\R?"
+ + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+ + "(<" + RUNNING.toString() + "/>)|"
+ + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
public static final Pattern COPY_CONFIG_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
+ "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
+ "(<copy-config>)\\R?"
- + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
- + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
- + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
- + "(<source>)\\R?(<config>)(("
- + TargetConfig.CANDIDATE.toString() + ")|("
- + TargetConfig.RUNNING.toString() + ")|("
- + TargetConfig.STARTUP.toString()
- + "))(</config>)\\R?(</source>)\\R?"
- + "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+ + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
+ + "(<" + RUNNING.toString() + "/>)|"
+ + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
+ + "(<source>)\\R?(<config>)(("
+ + CANDIDATE.toString() + ")|("
+ + RUNNING.toString() + ")|("
+ + STARTUP.toString()
+ + "))(</config>)\\R?(</source>)\\R?"
+ + "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
public static final Pattern GET_CONFIG_REQ_PATTERN =
Pattern.compile("(<\\?xml).*"
+ "(<rpc message-id=\")[0-9]*(\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+ "(<get-config>)\\R?" + "(<source>)\\R?((<"
- + TargetConfig.CANDIDATE.toString()
- + "/>)|(<" + TargetConfig.RUNNING.toString()
- + "/>)|(<" + TargetConfig.STARTUP.toString()
- + "/>))\\R?(</source>)\\R?"
+ + CANDIDATE.toString()
+ + "/>)|(<" + RUNNING.toString()
+ + "/>)|(<" + STARTUP.toString()
+ + "/>))\\R?(</source>)\\R?"
+ "(<filter type=\"subtree\">).*(</filter>)\\R?"
+ "(</get-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
@@ -455,10 +663,10 @@
public class NCCopyConfigCallable implements Callable<Boolean> {
private NetconfSession session;
- private TargetConfig target;
+ private DatastoreId target;
private String source;
- public NCCopyConfigCallable(NetconfSession session, TargetConfig target, String source) {
+ public NCCopyConfigCallable(NetconfSession session, DatastoreId target, String source) {
this.session = session;
this.target = target;
this.source = source;
@@ -469,4 +677,4 @@
return session.copyConfig(target, source);
}
}
-}
+}
\ No newline at end of file
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
index f13f17c..27e4247 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
@@ -15,13 +15,15 @@
*/
package org.onosproject.netconf.ctl.impl;
+
import java.io.BufferedReader;
-import java.io.EOFException;
-import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.EOFException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.Collection;
@@ -29,6 +31,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.sshd.server.Command;
@@ -111,6 +114,11 @@
*/
private static final String CLOSE_SESSION = "<close-session";
private static final String END_PATTERN = "]]>]]>";
+ private static final String HASH = "#";
+ private static final String LF = "\n";
+ private static final String MSGLEN_REGEX_PATTERN = "\n#\\d+\n";
+ private static final String MSGLEN_PART_REGEX_PATTERN = "\\d+\n";
+ private static final String CHUNKED_END_REGEX_PATTERN = "\n##\n";
private ExecutorService executors;
private boolean shutdownExecutor;
@@ -191,34 +199,68 @@
log.info("Client Request on session {}. MsgId {}: {}",
session.getSessionId(), messageId, deviceRequest);
synchronized (outputStream) {
+
if (NetconfSessionImplTest.HELLO_REQ_PATTERN.matcher(deviceRequest).matches()) {
+
String helloReply =
NetconfSessionImplTest.getTestHelloReply(Optional.of(ByteBuffer.wrap(
- session.getSessionId()).asLongBuffer().get()));
+ session.getSessionId()).asLongBuffer().get()), false);
outputStream.write(helloReply + END_PATTERN);
outputStream.flush();
- } else if (NetconfSessionImplTest.EDIT_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
- || NetconfSessionImplTest.COPY_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
- || NetconfSessionImplTest.LOCK_REQ_PATTERN.matcher(deviceRequest).matches()
- || NetconfSessionImplTest.UNLOCK_REQ_PATTERN.matcher(deviceRequest).matches()) {
- outputStream.write(NetconfSessionImplTest.getOkReply(messageId) + END_PATTERN);
- outputStream.flush();
- } else if (NetconfSessionImplTest.GET_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
- || NetconfSessionImplTest.GET_REQ_PATTERN.matcher(deviceRequest).matches()) {
- outputStream.write(NetconfSessionImplTest.getGetReply(messageId) + END_PATTERN);
- outputStream.flush();
- } else if (deviceRequest.contains(CLOSE_SESSION)) {
- socketClosed = true;
- outputStream.write(NetconfSessionImplTest.getOkReply(messageId) + END_PATTERN);
+ } else if (NetconfSessionImplTest.HELLO_REQ_PATTERN_1_1.matcher(deviceRequest).matches()) {
+
+ String helloReply =
+ NetconfSessionImplTest.getTestHelloReply(Optional.of(ByteBuffer.wrap(
+ session.getSessionId()).asLongBuffer().get()), true);
+ outputStream.write(helloReply + END_PATTERN);
outputStream.flush();
} else {
- log.error("Unexpected NETCONF message structure on session {} : {}",
- ByteBuffer.wrap(
- session.getSessionId()).asLongBuffer().get(), deviceRequest);
+ Pair replyClosedPair = dealWithRequest(deviceRequest, messageId);
+ String reply = (String) replyClosedPair.getLeft();
+ if (reply != null) {
+ Boolean newSockedClosed = (Boolean) replyClosedPair.getRight();
+ socketClosed = newSockedClosed.booleanValue();
+ outputStream.write(reply + END_PATTERN);
+ outputStream.flush();
+ }
}
}
deviceRequestBuilder.setLength(0);
}
+ } else if (state == NetconfMessageState.END_CHUNKED_PATTERN) {
+ String deviceRequest = deviceRequestBuilder.toString();
+ if (!validateChunkedFraming(deviceRequest)) {
+ log.error("Netconf client send badly framed message {}",
+ deviceRequest);
+ } else {
+ deviceRequest = deviceRequest.replaceAll(MSGLEN_REGEX_PATTERN, "");
+ deviceRequest = deviceRequest.replaceAll(CHUNKED_END_REGEX_PATTERN, "");
+ Optional<Integer> messageId = NetconfStreamThread.getMsgId(deviceRequest);
+ log.info("Client Request on session {}. MsgId {}: {}",
+ session.getSessionId(), messageId, deviceRequest);
+
+ synchronized (outputStream) {
+
+ if (NetconfSessionImplTest.HELLO_REQ_PATTERN.matcher(deviceRequest).matches()) {
+ String helloReply =
+ NetconfSessionImplTest.getTestHelloReply(Optional.of(ByteBuffer.wrap(
+ session.getSessionId()).asLongBuffer().get()), true);
+ outputStream.write(helloReply + END_PATTERN);
+ outputStream.flush();
+ } else {
+ Pair replyClosedPair = dealWithRequest(deviceRequest, messageId);
+ String reply = (String) replyClosedPair.getLeft();
+ if (reply != null) {
+ Boolean newSockedClosed = (Boolean) replyClosedPair.getRight();
+ socketClosed = newSockedClosed.booleanValue();
+ outputStream.write(formatChunkedMessage(reply));
+ outputStream.flush();
+ }
+ }
+ }
+
+ }
+ deviceRequestBuilder.setLength(0);
}
}
} catch (Throwable t) {
@@ -236,6 +278,69 @@
}
}
+ private boolean validateChunkedFraming(String reply) {
+ String[] strs = reply.split(LF + HASH);
+ int strIndex = 0;
+ while (strIndex < strs.length) {
+ String str = strs[strIndex];
+ if ((str.equals(HASH + LF))) {
+ return true;
+ }
+ if (!str.equals("")) {
+ try {
+ if (str.equals(LF)) {
+ return false;
+ }
+ int len = Integer.parseInt(str.split(LF)[0]);
+ if (str.split(MSGLEN_PART_REGEX_PATTERN)[1].getBytes("UTF-8").length != len) {
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ return false;
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ strIndex++;
+ }
+ return true;
+ }
+
+ private Pair<String, Boolean> dealWithRequest(String deviceRequest, Optional<Integer> messageId) {
+ if (NetconfSessionImplTest.EDIT_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
+ || NetconfSessionImplTest.COPY_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
+ || NetconfSessionImplTest.LOCK_REQ_PATTERN.matcher(deviceRequest).matches()
+ || NetconfSessionImplTest.UNLOCK_REQ_PATTERN.matcher(deviceRequest).matches()) {
+ return Pair.of(NetconfSessionImplTest.getOkReply(messageId), false);
+
+ } else if (NetconfSessionImplTest.GET_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
+ || NetconfSessionImplTest.GET_REQ_PATTERN.matcher(deviceRequest).matches()) {
+ return Pair.of(NetconfSessionImplTest.getGetReply(messageId), false);
+ } else if (deviceRequest.contains(CLOSE_SESSION)) {
+ return Pair.of(NetconfSessionImplTest.getOkReply(messageId), true);
+ } else {
+ log.error("Unexpected NETCONF message structure on session {} : {}",
+ ByteBuffer.wrap(
+ session.getSessionId()).asLongBuffer().get(), deviceRequest);
+ return null;
+ }
+ }
+
+ private String formatChunkedMessage(String message) {
+ if (message.endsWith(END_PATTERN)) {
+ message = message.split(END_PATTERN)[0];
+ }
+ if (!message.startsWith(LF + HASH)) {
+ try {
+ message = LF + HASH + message.getBytes("UTF-8").length + LF + message + LF + HASH + HASH + LF;
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ return message;
+ }
+
+
@Override
public void setInputStream(InputStream in) {
this.in = in;
@@ -310,4 +415,4 @@
protected void process(Buffer buffer) throws IOException {
log.warn("Receieved buffer:" + buffer);
}
-}
+}
\ No newline at end of file