Juniper driver - fix NETCONF discovery of JUNOS v19 devices regarding chassis-mac-addresses RPC
Added UT based on XML responses from v15 and v19 devices
Change-Id: Id4e0fe34b12dea6034e75f2276495282ea2e6aa2
diff --git a/drivers/juniper/BUILD b/drivers/juniper/BUILD
index 9bc897d..efc11d3 100644
--- a/drivers/juniper/BUILD
+++ b/drivers/juniper/BUILD
@@ -8,9 +8,12 @@
"//drivers/utilities:onos-drivers-utilities",
]
+TEST_DEPS = TEST_ADAPTERS
+
osgi_jar_with_tests(
resources = glob(["src/main/resources/**"]),
resources_root = "src/main/resources",
+ test_deps = TEST_DEPS,
deps = COMPILE_DEPS,
)
diff --git a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
index 14fb38a..1fc4f6c 100644
--- a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
+++ b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
@@ -16,6 +16,7 @@
package org.onosproject.drivers.juniper;
+import com.google.common.base.MoreObjects;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.lang.StringUtils;
import org.onlab.packet.ChassisId;
@@ -54,6 +55,7 @@
import static org.onosproject.drivers.juniper.StaticRoute.DEFAULT_METRIC_STATIC_ROUTE;
import static org.onosproject.drivers.juniper.StaticRoute.toFlowRulePriority;
+import static org.onosproject.drivers.utilities.XmlConfigParser.loadXmlString;
import static org.onosproject.net.Device.Type.ROUTER;
import static org.onosproject.net.PortNumber.portNumber;
import static org.slf4j.LoggerFactory.getLogger;
@@ -113,10 +115,10 @@
private static final String LLDP_REM_PORT_DES = "lldp-remote-port-description";
private static final String LLDP_SUBTYPE_MAC = "Mac address";
private static final String LLDP_SUBTYPE_INTERFACE_NAME = "Interface name";
- private static final String REGEX_ADD =
- ".*Private base address\\s*([:,0-9,a-f,A-F]*).*";
- private static final Pattern ADD_PATTERN =
- Pattern.compile(REGEX_ADD, Pattern.DOTALL);
+ // For older JUNOS e.g. 15.1
+ private static final Pattern ADD_PATTERN_JUNOS15_1 =
+ Pattern.compile(".*Private base address\\s*([:,0-9,a-f,A-F]*).*", Pattern.DOTALL);
+
public static final String PROTOCOL_NAME = "protocol-name";
@@ -263,12 +265,12 @@
*
* @param deviceId the id of the device
* @param sysInfoCfg system configuration
- * @param chassisText chassis string
+ * @param chassisMacAddresses chassis MAC addresses response. Its format depends on JUNOS version of device.
* @return device description
*/
public static DeviceDescription parseJuniperDescription(DeviceId deviceId,
HierarchicalConfiguration sysInfoCfg,
- String chassisText) {
+ String chassisMacAddresses) {
HierarchicalConfiguration info = sysInfoCfg.configurationAt(SYS_INFO);
String hw = info.getString(HW_MODEL) == null ? UNKNOWN : info.getString(HW_MODEL);
@@ -278,18 +280,36 @@
}
String serial = info.getString(SER_NUM) == null ? UNKNOWN : info.getString(SER_NUM);
- Matcher matcher = ADD_PATTERN.matcher(chassisText);
- if (matcher.lookingAt()) {
- String chassis = matcher.group(1);
- MacAddress chassisMac = MacAddress.valueOf(chassis);
- return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
- JUNIPER, hw, sw, serial,
- new ChassisId(chassisMac.toLong()),
- DefaultAnnotations.EMPTY);
- }
return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
- JUNIPER, hw, sw, serial,
- null, DefaultAnnotations.EMPTY);
+ JUNIPER, hw, sw, serial,
+ extractChassisId(chassisMacAddresses),
+ DefaultAnnotations.EMPTY);
+ }
+
+ /**
+ * Parses the chassisMacAddresses argument to find the private-base-address and maps it to a chassis id.
+ * @param chassisMacAddresses XML response
+ * @return the corresponding chassisId, or null if supplied chassisMacAddresses could not be parsed.
+ */
+ private static ChassisId extractChassisId(final String chassisMacAddresses) {
+
+ ChassisId result = null;
+
+ // Old JUNOS versions used CLI-style text for chassisMacAddresses, whereas recent versions provide a
+ // chassis-mac-addresses XML.
+ Matcher matcher = ADD_PATTERN_JUNOS15_1.matcher(chassisMacAddresses);
+ if (matcher.lookingAt()) {
+ result = new ChassisId(MacAddress.valueOf(matcher.group(1)).toLong());
+ } else {
+ String pba = loadXmlString(chassisMacAddresses)
+ .configurationAt("chassis-mac-addresses")
+ .configurationAt("mac-address-information")
+ .getString("private-base-address");
+ if (StringUtils.isNotBlank(pba)) {
+ result = new ChassisId(MacAddress.valueOf(pba).toLong());
+ }
+ }
+ return result;
}
/**
@@ -598,6 +618,16 @@
this.remotePortId = pPortId;
this.remotePortDescription = pDescription;
}
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass()).omitNullValues()
+ .add("localPortName", localPortName)
+ .add("remoteChassisId", remoteChassisId)
+ .add("remotePortIndex", remotePortIndex)
+ .add("remotePortId", remotePortId)
+ .add("remotePortDescription", remotePortDescription)
+ .toString();
+ }
}
enum OperationType {
diff --git a/drivers/juniper/src/test/java/org/onosproject/drivers/juniper/JuniperUtilsTest.java b/drivers/juniper/src/test/java/org/onosproject/drivers/juniper/JuniperUtilsTest.java
new file mode 100644
index 0000000..5898612
--- /dev/null
+++ b/drivers/juniper/src/test/java/org/onosproject/drivers/juniper/JuniperUtilsTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.juniper;
+
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.onosproject.net.Device.Type.ROUTER;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.junit.Test;
+import org.onlab.packet.ChassisId;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DeviceDescription;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+
+import com.google.common.io.CharStreams;
+
+public class JuniperUtilsTest {
+
+
+ private static final String DEVICE_ID = "netconf:1.2.3.4:830";
+ private final DeviceId deviceId = DeviceId.deviceId(DEVICE_ID);
+
+ @Test
+ public void testDeviceDescriptionParsedFromJunos15() throws IOException {
+
+ HierarchicalConfiguration getSystemInfoResp = XmlConfigParser.loadXml(
+ getClass().getResourceAsStream("/Junos_get-system-information_response_15.1.xml"));
+ String chassisText = CharStreams.toString(
+ new InputStreamReader(
+ getClass().getResourceAsStream("/Junos_get-chassis-mac-addresses_response_15.1.xml")));
+
+ DeviceDescription actual = JuniperUtils.parseJuniperDescription(deviceId, getSystemInfoResp, chassisText);
+ DeviceDescription expected =
+ new DefaultDeviceDescription(URI.create(DEVICE_ID), ROUTER, "JUNIPER", "mx240",
+ "junos 15.1R5.5", "JN11AC665AFC", new ChassisId("8418889983c0"));
+
+ assertEquals(expected, actual);
+
+ }
+
+
+ @Test
+ public void testDeviceDescriptionParsedFromJunos19() throws IOException {
+
+ HierarchicalConfiguration getSystemInfoResp = XmlConfigParser.loadXml(
+ getClass().getResourceAsStream("/Junos_get-system-information_response_19.2.xml"));
+ String chassisText = CharStreams.toString(
+ new InputStreamReader(
+ getClass().getResourceAsStream("/Junos_get-chassis-mac-addresses_response_19.2.xml")));
+
+ DeviceDescription actual = JuniperUtils.parseJuniperDescription(deviceId, getSystemInfoResp, chassisText);
+ DeviceDescription expected =
+ new DefaultDeviceDescription(URI.create(DEVICE_ID), ROUTER, "JUNIPER", "acx6360-or",
+ "junos 19.2I-20190228_dev_common.0.2316", "DX004", new ChassisId("f4b52f1f81c0"));
+
+ assertEquals(expected, actual);
+
+ }
+
+
+ @Test
+ public void testLinkAbstractionToString() throws IOException {
+ final JuniperUtils.LinkAbstraction x = new JuniperUtils.LinkAbstraction("foo", 1, 2, null, null);
+ assertThat("Null attributes excluded", x.toString(), allOf(
+ containsString("LinkAbstraction"),
+ containsString("localPortName=foo"),
+ not(containsString("remotePortDescription"))));
+
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/drivers/juniper/src/test/resources/Junos_get-chassis-mac-addresses_response_15.1.xml b/drivers/juniper/src/test/resources/Junos_get-chassis-mac-addresses_response_15.1.xml
new file mode 100644
index 0000000..8c6c8ff
--- /dev/null
+++ b/drivers/juniper/src/test/resources/Junos_get-chassis-mac-addresses_response_15.1.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1R5/junos" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
+ <output>
+ MAC address information:
+ Public base address 84:18:88:99:7c:00
+ Public count 1984
+ Private base address 84:18:88:99:83:c0
+ Private count 64
+ </output>
+</rpc-reply>
\ No newline at end of file
diff --git a/drivers/juniper/src/test/resources/Junos_get-chassis-mac-addresses_response_19.2.xml b/drivers/juniper/src/test/resources/Junos_get-chassis-mac-addresses_response_19.2.xml
new file mode 100644
index 0000000..1cf0c4d
--- /dev/null
+++ b/drivers/juniper/src/test/resources/Junos_get-chassis-mac-addresses_response_19.2.xml
@@ -0,0 +1,10 @@
+<rpc-reply xmlns:junos="http://xml.juniper.net/junos/19.2I0/junos" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
+ <chassis-mac-addresses>
+ <mac-address-information>
+ <public-base-address>f4:b5:2f:1f:81:00</public-base-address>
+ <public-count>192</public-count>
+ <private-base-address>f4:b5:2f:1f:81:c0</private-base-address>
+ <private-count>1088</private-count>
+ </mac-address-information>
+ </chassis-mac-addresses>
+</rpc-reply>
\ No newline at end of file
diff --git a/drivers/juniper/src/test/resources/Junos_get-system-information_response_15.1.xml b/drivers/juniper/src/test/resources/Junos_get-system-information_response_15.1.xml
new file mode 100644
index 0000000..26ba181
--- /dev/null
+++ b/drivers/juniper/src/test/resources/Junos_get-system-information_response_15.1.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1R5/junos" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
+ <system-information>
+ <hardware-model>mx240</hardware-model>
+ <os-name>junos</os-name>
+ <os-version>15.1R5.5</os-version>
+ <serial-number>JN11AC665AFC</serial-number>
+ <host-name>Mx35</host-name>
+ </system-information>
+</rpc-reply>
+
diff --git a/drivers/juniper/src/test/resources/Junos_get-system-information_response_19.2.xml b/drivers/juniper/src/test/resources/Junos_get-system-information_response_19.2.xml
new file mode 100644
index 0000000..99e8a5d
--- /dev/null
+++ b/drivers/juniper/src/test/resources/Junos_get-system-information_response_19.2.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<rpc-reply xmlns:junos="http://xml.juniper.net/junos/19.2I0/junos" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
+ <system-information>
+ <hardware-model>acx6360-or</hardware-model>
+ <os-name>junos</os-name>
+ <os-version>19.2I-20190228_dev_common.0.2316</os-version>
+ <serial-number>DX004</serial-number>
+ <host-name>capella39</host-name>
+ </system-information>
+</rpc-reply>
\ No newline at end of file