SNMPv3 protocol support for onos.
Implement RFC-rfc3414 standard.
Change-Id: Ibe8d10aaaf569274b922a7500ed237a9813c0428
diff --git a/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDevice.java b/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDevice.java
index 587e2b1..14f954a 100644
--- a/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDevice.java
+++ b/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDevice.java
@@ -107,4 +107,11 @@
* @return DeviceId
*/
DeviceId deviceId();
+
+ /**
+ * Return the SNMP protocol version.
+ *
+ * @return SNMP protocol version
+ */
+ int getVersion();
}
diff --git a/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDeviceConfig.java b/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDeviceConfig.java
index 47446ea..8776b3d 100644
--- a/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDeviceConfig.java
+++ b/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpDeviceConfig.java
@@ -21,6 +21,7 @@
import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.Config;
+import org.snmp4j.mp.SnmpConstants;
/**
* Configuration to push devices to the SNMP provider.
@@ -36,6 +37,15 @@
private static final String NOTIFICATION_PORT = "notificationPort";
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
+ public static final String VERSION = "version";
+ public static final String SECURITY_NAME = "securityName";
+ public static final String SECURITY_LEVEL = "securityLevel";
+ public static final String AUTH_PROTOCOL = "authProtocol";
+ public static final String AUTH_PASSWORD = "authPassword";
+ public static final String PRIVACY_PROTOCOL = "privacyProtocol";
+ public static final String PRIVACY_PASSWORD = "privacyPassword";
+ public static final String CONTEXT_NAME = "contextName";
+
@Override
public boolean isValid() {
@@ -107,6 +117,77 @@
return get(PASSWORD, "");
}
+ /**
+ * Gets the version of the SNMP device.
+ *
+ * @return snmp version
+ */
+ public int version() {
+ return get(VERSION, SnmpConstants.version2c);
+ }
+
+ /**
+ * Gets the securityName of the SNMPv3 device.
+ *
+ * @return securityName
+ */
+ public String securityName() {
+ return get(SECURITY_NAME, "");
+ }
+
+ /**
+ * Gets the securityLevel of the SNMPv3 device.
+ *
+ * @return securityLevel
+ */
+ public String securityLevel() {
+ return get(SECURITY_LEVEL, "");
+ }
+
+ /**
+ * Gets the authProtocol of the SNMPv3 device.
+ *
+ * @return authProtocol
+ */
+ public String authProtocol() {
+ return get(AUTH_PROTOCOL, "");
+ }
+
+ /**
+ * Gets the authPassword of the SNMPv3 device.
+ *
+ * @return authPassword
+ */
+ public String authPassword() {
+ return get(AUTH_PASSWORD, "");
+ }
+
+ /**
+ * Gets the privacyProtocol of the SNMPv3 device.
+ *
+ * @return privacyProtocol
+ */
+ public String privacyProtocol() {
+ return get(PRIVACY_PROTOCOL, "");
+ }
+
+ /**
+ * Gets the privacyPassword of the SNMPv3 device.
+ *
+ * @return privacyPassword
+ */
+ public String privacyPassword() {
+ return get(PRIVACY_PASSWORD, "");
+ }
+
+ /**
+ * Gets the context name of the SNMPv3 device.
+ *
+ * @return context name
+ */
+ public String contextName() {
+ return get(CONTEXT_NAME, "");
+ }
private Pair<String, Integer> extractIpPort() {
String info = subject.uri().getSchemeSpecificPart();
diff --git a/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpException.java b/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpException.java
new file mode 100644
index 0000000..ad22916
--- /dev/null
+++ b/protocols/snmp/api/src/main/java/org/onosproject/snmp/SnmpException.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-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.snmp;
+
+/**
+ * Custom Exception for SNMP.
+ */
+public class SnmpException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Default constructor to create a new snmp exception.
+ */
+ public SnmpException() {
+ super();
+ }
+
+ /**
+ * Constructor to create exception from message and cause.
+ *
+ * @param text the detail of exception in string
+ * @param variables underlying cause of exception variables
+ */
+ public SnmpException(String text, String... variables) {
+ super(format(text, variables));
+ }
+
+ private static String format(String text, String... variables) {
+ return String.format(text, (Object[]) variables);
+ }
+
+ /**
+ * Constructor to create exception from message and cause.
+ *
+ * @param cause underlying cause of the error
+ * @param text the detail of exception in string
+ * @param variables underlying cause of exception variables
+ */
+ public SnmpException(Throwable cause, String text, String... variables) {
+ super(format(text, variables), cause);
+
+ }
+}
\ No newline at end of file
diff --git a/protocols/snmp/api/src/main/java/org/onosproject/snmp/Snmpv3Configuration.java b/protocols/snmp/api/src/main/java/org/onosproject/snmp/Snmpv3Configuration.java
new file mode 100644
index 0000000..4fdafa0
--- /dev/null
+++ b/protocols/snmp/api/src/main/java/org/onosproject/snmp/Snmpv3Configuration.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021-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.snmp;
+
+import com.btisystems.pronx.ems.core.snmp.ISnmpConfiguration;
+import org.onlab.packet.IpAddress;
+import org.snmp4j.security.SecurityLevel;
+import org.snmp4j.smi.OID;
+import org.snmp4j.util.PDUFactory;
+
+import java.io.Serializable;
+
+/**
+ * Abstraction of SNMPv3 configuration.
+ */
+public interface Snmpv3Configuration extends Serializable, ISnmpConfiguration {
+
+ /**
+ * Returns the ip address.
+ *
+ * @return ip address
+ */
+ IpAddress getAddress();
+
+ /**
+ * Returns the snmpv3 security name of the device.
+ * the SNMPv3 username.
+ *
+ * @return security name
+ */
+ String getSecurityName();
+
+ /**
+ * Returns the snmpv3 security level of the device.
+ * the security level is noAuthNoPriv or authNoPriv or authPriv
+ *
+ * @return security level
+ */
+ SecurityLevel getSecurityLevel();
+
+ /**
+ * Returns the snmpv3 authentication protocol of the device.
+ * the authentication method (either MD5 or SHA)
+ *
+ * @return authentication protocol
+ */
+ OID getAuthenticationProtocol();
+
+ /**
+ * Returns the snmpv3 authentication password of the device.
+ * the authentication password must be at least eight characters long
+ *
+ * @return authentication password
+ */
+ String getAuthenticationPassword();
+
+ /**
+ * Returns the snmpv3 privacy protocol of the device.
+ * the privacy method (either AES or DES)
+ *
+ * @return privacy protocol
+ */
+ OID getPrivacyProtocol();
+
+ /**
+ * Returns the snmpv3 privacy password of the device.
+ * the privacy password must be at least eight characters long
+ *
+ * @return privacy password
+ */
+ String getPrivacyPassword();
+
+ /**
+ * Returns the snmpv3 authoritative engine id of the device.
+ *
+ * @return authoritative engine id
+ */
+ byte[] getAuthoritativeEngineId();
+
+ /**
+ * Returns the snmpv3 context name of the device.
+ * An SNMP context name or "context" in short,
+ * is a collection of management information accessible by an SNMP entity.
+ * An item of management information may exist in more than one context.
+ * An SNMP entity potentially has access to many contexts. In other words,
+ * if a management information has been defined under certain context by an SNMPv3 entity,
+ * then any management application can access that information by giving that context name.
+ * The "context name" is an octet string, which has at least one management information
+ *
+ * @return snmpv3 context name
+ */
+ String getContextName();
+
+ /**
+ * Create snmp session PDU factory.
+ *
+ * @return session PDU factory
+ */
+ PDUFactory createPduFactory();
+
+ /**
+ * Remove Snmp user security model when close connection to device.
+ */
+ void removeUsm();
+
+}
diff --git a/protocols/snmp/api/src/main/java/org/onosproject/snmp/Snmpv3Device.java b/protocols/snmp/api/src/main/java/org/onosproject/snmp/Snmpv3Device.java
new file mode 100644
index 0000000..7e48c51
--- /dev/null
+++ b/protocols/snmp/api/src/main/java/org/onosproject/snmp/Snmpv3Device.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021-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.snmp;
+
+
+/**
+ * Abstraction a Snmpv3 Device.
+ */
+public interface Snmpv3Device extends SnmpDevice {
+
+ /**
+ * Retrieves the security name of SNMPv3 device.
+ *
+ * @return security name
+ */
+ String getSecurityName();
+
+ /**
+ * Retrieves the security level of SNMPv3 device.
+ *
+ * @return security level
+ */
+ String getSecurityLevel();
+
+ /**
+ * Retrieves the authentication protocol of SNMPv3 device.
+ *
+ * @return authentication protocol
+ */
+ String getAuthProtocol();
+
+ /**
+ * Retrieves the authentication password of SNMPv3 device.
+ *
+ * @return authentication password
+ */
+ String getAuthPassword();
+
+ /**
+ * Retrieves the privacy protocol of SNMPv3 device.
+ *
+ * @return privacy protocol
+ */
+ String getPrivProtocol();
+
+ /**
+ * Retrieves the privacy password of SNMPv3 device.
+ *
+ * @return privacy password
+ */
+ String getPrivPassword();
+
+ /**
+ * Retrieves the context name of SNMPv3 device.
+ *
+ * @return context name
+ */
+ String getContextName();
+
+}
diff --git a/protocols/snmp/ctl/BUILD b/protocols/snmp/ctl/BUILD
index 2e5c6ef..6b4550e 100644
--- a/protocols/snmp/ctl/BUILD
+++ b/protocols/snmp/ctl/BUILD
@@ -1,4 +1,4 @@
-COMPILE_DEPS = CORE_DEPS + [
+COMPILE_DEPS = CORE_DEPS + JACKSON + [
"@org_apache_servicemix_bundles_snmp4j//jar",
"@snmp_core//jar",
"@mibs_net_snmp//jar",
diff --git a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java
index d5664e6..d84ef09 100644
--- a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java
+++ b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java
@@ -23,24 +23,28 @@
import com.btisystems.pronx.ems.core.snmp.SnmpSessionFactory;
import com.btisystems.pronx.ems.core.snmp.V2cSnmpConfiguration;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
import org.onosproject.alarm.Alarm;
import org.onosproject.alarm.AlarmId;
import org.onosproject.alarm.DefaultAlarm;
import org.onosproject.net.DeviceId;
import org.onosproject.snmp.SnmpController;
import org.onosproject.snmp.SnmpDevice;
+import org.onosproject.snmp.SnmpException;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.snmp4j.mp.SnmpConstants;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -52,15 +56,18 @@
private final Logger log = LoggerFactory
.getLogger(getClass());
- protected ISnmpSessionFactory sessionFactory;
+ protected Map<Integer, ISnmpSessionFactory> factoryMap;
protected final Map<DeviceId, ISnmpSession> sessionMap = new HashMap<>();
protected final Map<DeviceId, SnmpDevice> snmpDeviceMap = new ConcurrentHashMap<>();
@Activate
public void activate(ComponentContext context) {
- sessionFactory = new SnmpSessionFactory(
- new DefaultSnmpConfigurationFactory(new V2cSnmpConfiguration()));
+ factoryMap = Maps.newHashMap();
+ factoryMap.put(SnmpConstants.version2c, new SnmpSessionFactory(
+ new DefaultSnmpConfigurationFactory(new V2cSnmpConfiguration())));
+ factoryMap.put(SnmpConstants.version3, new SnmpSessionFactory(
+ new DefaultSnmpConfigurationFactory(new V3SnmpConfiguration())));
log.info("Started");
}
@@ -76,6 +83,11 @@
public ISnmpSession getSession(DeviceId deviceId) throws IOException {
if (!sessionMap.containsKey(deviceId)) {
SnmpDevice device = snmpDeviceMap.get(deviceId);
+ ISnmpSessionFactory sessionFactory = factoryMap.get(device.getVersion());
+ if (Objects.isNull(sessionFactory)) {
+ log.error("Invalid session factory", deviceId);
+ throw new SnmpException("Invalid session factory");
+ }
String ipAddress = null;
int port = -1;
if (device != null) {
@@ -93,8 +105,26 @@
}
Preconditions.checkNotNull(ipAddress, "ip address is empty, cannot start session");
Preconditions.checkArgument(port != -1, "port is incorrect, cannot start session");
-
- ISnmpConfiguration config = new V2cSnmpConfiguration();
+ ISnmpConfiguration config;
+ if (device.getVersion() == SnmpConstants.version2c) {
+ config = new V2cSnmpConfiguration();
+ config.setCommunity(device.getCommunity());
+ } else if (device.getVersion() == SnmpConstants.version3) {
+ DefaultSnmpv3Device v3Device = (DefaultSnmpv3Device) device;
+ config = V3SnmpConfiguration.builder()
+ .setAddress(ipAddress)
+ .setSecurityName(v3Device.getSecurityName())
+ .setSecurityLevel(v3Device.getSecurityLevel())
+ .setAuthenticationProtocol(v3Device.getAuthProtocol())
+ .setAuthenticationPassword(v3Device.getAuthPassword())
+ .setPrivacyProtocol(v3Device.getPrivProtocol())
+ .setPrivacyPassword(v3Device.getPrivPassword())
+ .setContextName(v3Device.getContextName())
+ .build();
+ } else {
+ throw new SnmpException(
+ String.format("Invalid snmp version %d", device.getVersion()));
+ }
config.setPort(port);
sessionMap.put(deviceId, sessionFactory.createSession(config, ipAddress));
}
diff --git a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpDevice.java b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpDevice.java
index 5104cb8..30972a0 100644
--- a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpDevice.java
+++ b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpDevice.java
@@ -21,6 +21,7 @@
import org.slf4j.Logger;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
+import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
@@ -52,6 +53,7 @@
private boolean reachable = false;
private final String protocol;
private final String notificationProtocol;
+ private final int version;
private Snmp session;
@@ -65,6 +67,7 @@
this.username = username;
this.community = community;
this.deviceId = createDeviceId();
+ this.version = SnmpConstants.version2c;
initializeSession();
}
@@ -78,6 +81,7 @@
this.username = snmpDeviceConfig.username();
this.community = snmpDeviceConfig.password();
this.deviceId = createDeviceId();
+ this.version = snmpDeviceConfig.version();
initializeSession();
}
@@ -146,6 +150,11 @@
}
@Override
+ public int getVersion() {
+ return version;
+ }
+
+ @Override
public DeviceId deviceId() {
return deviceId;
}
diff --git a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpv3Device.java b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpv3Device.java
new file mode 100644
index 0000000..81cc8d1
--- /dev/null
+++ b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpv3Device.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2021-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.snmp.ctl;
+
+import com.google.common.base.MoreObjects;
+import org.apache.commons.lang.StringUtils;
+import org.onosproject.snmp.Snmpv3Device;
+import org.onosproject.snmp.SnmpDeviceConfig;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * This is a logical representation of actual SNMPv3 device.
+ * carrying all the necessary information to connect and execute
+ * SNMPv3 operations.
+ */
+public class DefaultSnmpv3Device extends DefaultSnmpDevice implements Snmpv3Device {
+
+ private final String securityLevel;
+
+ private final String securityName;
+
+ private final String authProtocol;
+
+ private final String authPassword;
+
+ private final String privProtocol;
+
+ private final String privPassword;
+
+ private final String contextName;
+
+ /**
+ * Create a new DefaultSnmpv3Device.
+ *
+ * @param config snmp device config
+ */
+ public DefaultSnmpv3Device(SnmpDeviceConfig config) {
+ super(config);
+ checkState(!StringUtils.isEmpty(config.securityLevel()),
+ "SNMPv3 security level cannot be null or empty");
+ checkState(!StringUtils.isEmpty(config.securityName()),
+ "SNMPv3 security name cannot be null or empty");
+ this.securityLevel = config.securityLevel();
+ this.securityName = config.securityName();
+ this.authProtocol = config.authProtocol();
+ this.authPassword = config.authPassword();
+ this.privProtocol = config.privacyProtocol();
+ this.privPassword = config.privacyPassword();
+ this.contextName = config.contextName();
+ }
+
+ /**
+ * Retrieves the security name of SNMPv3 device.
+ *
+ * @return security name
+ */
+ @Override
+ public String getSecurityName() {
+ return securityName;
+ }
+
+ /**
+ * Retrieves the security level of SNMPv3 device.
+ *
+ * @return security level
+ */
+ @Override
+ public String getSecurityLevel() {
+ return securityLevel;
+ }
+
+ /**
+ * Retrieves the authentication protocol of SNMPv3 device.
+ *
+ * @return authentication protocol
+ */
+ @Override
+ public String getAuthProtocol() {
+ return authProtocol;
+ }
+
+ /**
+ * Retrieves the authentication password of SNMPv3 device.
+ *
+ * @return authentication password
+ */
+ @Override
+ public String getAuthPassword() {
+ return authPassword;
+ }
+
+ /**
+ * Retrieves the privacy protocol of SNMPv3 device.
+ *
+ * @return privacy protocol
+ */
+ @Override
+ public String getPrivProtocol() {
+ return privProtocol;
+ }
+
+ /**
+ * Retrieves the privacy password of SNMPv3 device.
+ *
+ * @return privacy password
+ */
+ @Override
+ public String getPrivPassword() {
+ return privPassword;
+ }
+
+ /**
+ * Retrieves the context name of SNMPv3 device.
+ *
+ * @return context name
+ */
+ @Override
+ public String getContextName() {
+ return contextName;
+ }
+
+ /**
+ * Convert the Snmpv3 device to string.
+ */
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("hostName", getSnmpHost())
+ .add("securityLevel", securityLevel)
+ .add("securityName", securityName)
+ .add("authProtocol", authProtocol)
+ .add("authPassword", authPassword)
+ .add("privProtocol", privProtocol)
+ .add("privPassword", privPassword)
+ .add("contextName", contextName)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ DefaultSnmpv3Device otherv3Device = (DefaultSnmpv3Device) obj;
+ return Objects.equals(securityLevel, otherv3Device.securityLevel) &&
+ Objects.equals(securityName, otherv3Device.securityName) &&
+ Objects.equals(getSnmpHost(), otherv3Device.getSnmpHost());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(securityLevel, securityName, getSnmpHost());
+ }
+}
diff --git a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/V3SnmpConfiguration.java b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/V3SnmpConfiguration.java
new file mode 100644
index 0000000..640668b
--- /dev/null
+++ b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/V3SnmpConfiguration.java
@@ -0,0 +1,658 @@
+/*
+ * Copyright 2021-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.snmp.ctl;
+
+import com.google.common.base.MoreObjects;
+import org.apache.commons.lang.StringUtils;
+import com.btisystems.pronx.ems.core.snmp.SnmpConfiguration;
+import org.onosproject.snmp.SnmpException;
+import org.onosproject.snmp.Snmpv3Configuration;
+import org.slf4j.Logger;
+import org.onlab.packet.IpAddress;
+
+import org.snmp4j.MessageDispatcher;
+import org.snmp4j.MessageDispatcherImpl;
+import org.snmp4j.PDU;
+import org.snmp4j.Snmp;
+import org.snmp4j.Target;
+import org.snmp4j.TransportMapping;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.smi.Address;
+import org.snmp4j.smi.OctetString;
+import org.snmp4j.util.MultiThreadedMessageDispatcher;
+import org.snmp4j.util.ThreadPool;
+import org.snmp4j.UserTarget;
+import org.snmp4j.ScopedPDU;
+import org.snmp4j.mp.MPv3;
+
+import org.snmp4j.security.PrivDES;
+import org.snmp4j.security.AuthMD5;
+import org.snmp4j.security.SecurityLevel;
+import org.snmp4j.security.SecurityModels;
+import org.snmp4j.security.SecurityProtocols;
+import org.snmp4j.security.USM;
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.security.PrivAES128;
+import org.snmp4j.security.PrivAES256;
+import org.snmp4j.security.Priv3DES;
+import org.snmp4j.security.PrivAES192;
+import org.snmp4j.security.AuthSHA;
+import org.snmp4j.security.nonstandard.PrivAES192With3DESKeyExtension;
+import org.snmp4j.security.nonstandard.PrivAES256With3DESKeyExtension;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.UdpAddress;
+import org.snmp4j.util.DefaultPDUFactory;
+import org.snmp4j.util.PDUFactory;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the SNMPv3 configuration.
+ */
+public class V3SnmpConfiguration extends SnmpConfiguration implements Snmpv3Configuration {
+
+ private IpAddress address;
+
+ private String securityName;
+
+ private SecurityLevel securityLevel;
+
+ private OID authProtocol;
+
+ private String authPassword;
+
+ private OID privacyProtocol;
+
+ private String privacyPassword;
+
+ private String contextName;
+
+ private byte[] authoritativeEngineId;
+
+ private static Snmp snmp;
+
+ private static final USM USM_USER;
+
+ private static final int ENGINE_BOOT = 0;
+
+ private static final int PASS_CODE_LENGTH = 8;
+
+ private static final int DISCOVERY_TIMEOUT = 5000;
+
+ private static final String SLASH = "/";
+
+ private static final byte[] LOCALENGINEID = MPv3.createLocalEngineID();
+
+ private final Logger log = getLogger(V3SnmpConfiguration.class);
+
+ static {
+ SecurityProtocols securityProtocols = SecurityProtocols.getInstance();
+ securityProtocols.addPrivacyProtocol(new PrivAES128());
+ securityProtocols.addPrivacyProtocol(new
+ PrivAES192With3DESKeyExtension());
+ securityProtocols.addPrivacyProtocol(new
+ PrivAES256With3DESKeyExtension());
+ securityProtocols.addPrivacyProtocol(new PrivDES());
+ securityProtocols.addPrivacyProtocol(new Priv3DES());
+
+ USM_USER = new USM(SecurityProtocols.getInstance(),
+ new OctetString(LOCALENGINEID), ENGINE_BOOT);
+ USM_USER.setEngineDiscoveryEnabled(true);
+ SecurityModels.getInstance().addSecurityModel(USM_USER);
+ }
+
+ public V3SnmpConfiguration() {
+ this.setVersion(SnmpConstants.version3);
+ }
+
+ private V3SnmpConfiguration(Builder builder) {
+ this();
+ this.address = builder.address;
+ this.securityName = builder.securityName;
+ this.securityLevel = builder.securityLevel;
+ this.authProtocol = builder.authProtocol;
+ this.authPassword = builder.authPassword;
+ this.privacyProtocol = builder.privacyProtocol;
+ this.privacyPassword = builder.privacyPassword;
+ this.contextName = builder.contextName;
+ }
+
+ @Override
+ public Target createTarget(Address address) {
+ setUsm();
+ UserTarget target = new UserTarget();
+ target.setSecurityLevel(this.getSecurityLevel().getSnmpValue());
+ target.setSecurityName(new OctetString(this.getSecurityName()));
+ target.setVersion(this.getVersion());
+ target.setAddress(address);
+ target.setRetries(this.getRetries());
+ target.setTimeout(this.getTimeout());
+ target.setAuthoritativeEngineID(this.getAuthoritativeEngineId());
+ return target;
+ }
+
+ /**
+ * Create snmp session PDU factory.
+ *
+ * @return session PDU factory
+ */
+ @Override
+ public PDUFactory createPduFactory() {
+ DefaultPDUFactory pduFactory = new DefaultPDUFactory(PDU.GETBULK);
+ if (!StringUtils.isEmpty(this.getContextName())) {
+ pduFactory.setContextName(new OctetString(this.getContextName()));
+ }
+ return pduFactory;
+ }
+
+ @Override
+ public PDU createPDU(int type) {
+ ScopedPDU pdu = new ScopedPDU();
+ pdu.setType(type);
+ if (!StringUtils.isEmpty(this.getContextName())) {
+ pdu.setContextName(new OctetString(this.getContextName()));
+ }
+ switch (type) {
+ case PDU.GETBULK:
+ pdu.setMaxRepetitions(this.getMaxRepetitions());
+ pdu.setNonRepeaters(this.getNonRepeaters());
+ break;
+ default:
+ log.debug("Not setting up non-default configuration for PDU type {}.", type);
+ }
+
+ return pdu;
+ }
+
+ /**
+ * Create snmp session to the device.
+ *
+ * @return snmp session object
+ */
+ @Override
+ public Snmp createSnmpSession(TransportMapping transportMapping) throws IOException {
+ synchronized (USM_USER) {
+ if (Objects.isNull(snmp)) {
+ ThreadPool threadPool = ThreadPool.create("SnmpDispatcherPool", getDispatcherPoolSize());
+ MessageDispatcher mtDispatcher = new MultiThreadedMessageDispatcher(
+ threadPool, new MessageDispatcherImpl());
+
+ // Add message processing models
+ mtDispatcher.addMessageProcessingModel(new MPv3());
+
+ snmp = new Snmp(mtDispatcher, transportMapping);
+
+ snmp.listen();
+ }
+ }
+
+ return snmp;
+ }
+
+ /**
+ * Set User Security Model to the snmpv3 session.
+ * SNMPv3 is a security model in which an authentication
+ * strategy is set up for a user in which the user resides.
+ * Security level is the permitted level of security within a security model.
+ * A combination of a security model and a security level determines
+ * which security mechanism is used when handling an SNMP packet.
+ */
+ private void setUsm() {
+
+ OctetString securityName = new OctetString(this.getSecurityName());
+ OctetString authPassphrase = StringUtils.isEmpty(this.getAuthenticationPassword()) ?
+ null : new OctetString(this.getAuthenticationPassword());
+ OctetString privPassphrase = StringUtils.isEmpty(this.getPrivacyPassword()) ?
+ null : new OctetString(this.getPrivacyPassword());
+
+
+ discoverAuthoritativeEngineId();
+
+ if (USM_USER.hasUser(new OctetString(this.getAuthoritativeEngineId()), securityName)) {
+ return;
+ }
+
+ USM_USER.addUser(securityName,
+ new UsmUser(securityName,
+ this.getAuthenticationProtocol(),
+ authPassphrase,
+ this.getPrivacyProtocol(),
+ privPassphrase));
+
+ }
+
+ /**
+ * Remove Snmp user security model when close connection to device.
+ */
+ @Override
+ public void removeUsm() {
+ OctetString securityName = new OctetString(this.getSecurityName());
+ OctetString engineId = new OctetString(this.getAuthoritativeEngineId());
+ if (USM_USER.hasUser(engineId, securityName)) {
+ USM_USER.removeAllUsers(securityName, engineId);
+ }
+
+ }
+
+ /**
+ * Discover snmp agent authoritative engineId.
+ * The Engine ID is used by SNMPv3 entities to uniquely identify them.
+ * An SNMP agent is considered an authoritative SNMP engine.
+ * This means that the agent responds to incoming messages (Get, GetNext, GetBulk, Set)
+ * and sends trap messages to a manager.
+ * The agent's local information is encapsulated in fields in the message.
+ * <p>
+ * Each SNMP agent maintains local information that is used in SNMPv3 message exchanges.
+ * The default SNMP Engine ID is comprised of the enterprise number and the default MAC address.
+ * This engine ID must be unique for the administrative domain,
+ * so that no two devices in a network have the same engine ID.
+ */
+ private void discoverAuthoritativeEngineId() {
+ this.authoritativeEngineId = Optional.ofNullable(snmp.discoverAuthoritativeEngineID(
+ getTransportAddress(), DISCOVERY_TIMEOUT))
+ .orElseThrow(() -> new SnmpException(String.format("Snmp agent %s is not configured with" +
+ " Snmpv3 user or not reachable",
+ getAddress().toString())));
+ }
+
+ /**
+ * Returns the security level of SNMPv3 device.
+ *
+ * @return security level
+ */
+ @Override
+ public SecurityLevel getSecurityLevel() {
+ return this.securityLevel;
+ }
+
+ /**
+ * Returns the ip address.
+ *
+ * @return ip address
+ */
+ @Override
+ public IpAddress getAddress() {
+ return this.address;
+ }
+
+ /**
+ * Returns the security name of SNMPv3 device.
+ *
+ * @return security name
+ */
+ @Override
+ public String getSecurityName() {
+ return this.securityName;
+ }
+
+ /**
+ * Returns the authentication password of SNMPv3 device.
+ *
+ * @return authentication password
+ */
+ @Override
+ public String getAuthenticationPassword() {
+ return this.authPassword;
+ }
+
+ /**
+ * Returns the authentication protocol of SNMPv3 device.
+ *
+ * @return authentication protocol
+ */
+ @Override
+ public OID getAuthenticationProtocol() {
+ return this.authProtocol;
+ }
+
+ /**
+ * Returns the snmpv3 privacy password of the device.
+ *
+ * @return privacy password
+ */
+ @Override
+ public String getPrivacyPassword() {
+ return this.privacyPassword;
+ }
+
+ /**
+ * Returns the snmpv3 privacy protocol of the device.
+ *
+ * @return privacy protocol
+ */
+ @Override
+ public OID getPrivacyProtocol() {
+ return this.privacyProtocol;
+ }
+
+ /**
+ * Returns the snmpv3 context name of the device.
+ *
+ * @return snmpv3 context name
+ */
+ @Override
+ public String getContextName() {
+ return this.contextName;
+ }
+
+ /**
+ * Returns the snmpv3 authoritative engine id of the device.
+ *
+ * @return authoritative engine id
+ */
+ @Override
+ public byte[] getAuthoritativeEngineId() {
+ return this.authoritativeEngineId;
+ }
+
+
+ private Address getTransportAddress() {
+ return new UdpAddress(getAddress().toString() + SLASH + getPort());
+ }
+
+ /**
+ * Creates a new v3snmp configuration builder.
+ *
+ * @return new v3snmp configuration builder
+ */
+ public static V3SnmpConfiguration.Builder builder() {
+ return new V3SnmpConfiguration.Builder();
+ }
+
+ /**
+ * Convert the Snmpv3 configuration to string.
+ */
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("address", address)
+ .add("securityName", securityName)
+ .add("securityLevel", securityLevel)
+ .add("authProtocol", authProtocol)
+ .add("authPassword", authPassword)
+ .add("privacyProtocol", privacyProtocol)
+ .add("privacyPassword", privacyPassword)
+ .add("contextName", contextName)
+ .add("authoritativeEngineId", Arrays.toString(authoritativeEngineId))
+ .toString();
+ }
+
+ /**
+ * Facility for gradually building snmpv3 configuration.
+ */
+ public static final class Builder {
+
+ private IpAddress address;
+
+ private String securityName;
+
+ private SecurityLevel securityLevel;
+
+ private OID authProtocol;
+
+ private String authPassword;
+
+ private OID privacyProtocol;
+
+ private String privacyPassword;
+
+ private String contextName;
+
+
+ // Private construction is forbidden.
+ private Builder() {
+ }
+
+ /**
+ * Set ip address of the device.
+ *
+ * @param address ip address
+ * @return This builder
+ */
+ public Builder setAddress(String address) {
+ this.address = IpAddress.valueOf(address);
+ return this;
+ }
+
+ /**
+ * Set the security level of the SNMPv3 device.
+ *
+ * @param securityLevel securityLevel of the SNMPv3 device
+ * @return This builder
+ */
+ public Builder setSecurityLevel(String securityLevel) {
+ this.securityLevel = getSecurityLevel(securityLevel);
+ return this;
+ }
+
+ /**
+ * Set the security name of the SNMPv3 device.
+ *
+ * @param securityName securityName of the SNMPv3 device.
+ * @return This builder
+ */
+ public Builder setSecurityName(String securityName) {
+ this.securityName = securityName;
+ return this;
+ }
+
+ /**
+ * Set the authentication password of the SNMPv3 device.
+ *
+ * @param authPassword authPassword of the SNMPv3 device
+ * @return This builder
+ */
+ public Builder setAuthenticationPassword(String authPassword) {
+ this.authPassword = StringUtils.isEmpty(authPassword) ? null : authPassword;
+ return this;
+ }
+
+ /**
+ * Set the authentication protocol of the SNMPv3 device.
+ *
+ * @param authProtocol authProtocol of the SNMPv3 device
+ * @return This builder
+ */
+ public Builder setAuthenticationProtocol(String authProtocol) {
+ this.authProtocol = getAuthProtocol(authProtocol);
+ return this;
+ }
+
+ /**
+ * Set the privacy password of the SNMPv3 device.
+ *
+ * @param privacyPassword privacy protocol of the SNMPv3 device
+ * @return This builder
+ */
+ public Builder setPrivacyPassword(String privacyPassword) {
+ this.privacyPassword = StringUtils.isEmpty(privacyPassword) ? null : privacyPassword;
+ return this;
+ }
+
+ /**
+ * Set the privacy protocol of the SNMPv3 device.
+ *
+ * @param privacyProtocol privacyProtocol of the SNMPv3 device
+ * @return This builder
+ */
+ public Builder setPrivacyProtocol(String privacyProtocol) {
+ this.privacyProtocol = getPrivProtocol(privacyProtocol);
+ return this;
+ }
+
+ /**
+ * Set the context name of the SNMPv3 device.
+ *
+ * @param contextName context name of the SNMPv3 device
+ * @return This builder
+ */
+ public Builder setContextName(String contextName) {
+ this.contextName = contextName;
+ return this;
+ }
+
+ /**
+ * Convert privacy protocol string to privacy protocol object identifier.
+ *
+ * @param priv privacy protocol string
+ * @return privacy protocol object identifier
+ */
+ private OID getPrivProtocol(String priv) {
+
+ switch (priv) {
+
+ case "DES":
+ return PrivDES.ID;
+
+ case "AES":
+ case "AES128":
+ return PrivAES128.ID;
+
+ case "AES192":
+ return PrivAES192.ID;
+
+ case "AES256":
+ return PrivAES256.ID;
+
+ case "3DES":
+ case "DESEDE":
+ return Priv3DES.ID;
+
+ default:
+ throw new SnmpException("Invalid privacy protocol");
+
+ }
+ }
+
+ /**
+ * Convert authentication string to authentication protocol object identifier.
+ *
+ * @param auth privacy protocol string
+ * @return authentication protocol object identifier
+ */
+ private OID getAuthProtocol(String auth) {
+
+ switch (auth) {
+
+ case "MD5":
+ return AuthMD5.ID;
+
+ case "SHA":
+ return AuthSHA.ID;
+
+ default:
+ throw new SnmpException("Invalid Authentication protocol");
+
+ }
+ }
+
+ /**
+ * Convert security level string to security level number.
+ *
+ * @param securityLevel snmpv3 security level string
+ * @return snmpv3 security level
+ */
+ private SecurityLevel getSecurityLevel(String securityLevel) {
+
+ switch (securityLevel) {
+
+ case "noAuthNoPriv":
+ return SecurityLevel.noAuthNoPriv;
+
+ case "authNoPriv":
+ return SecurityLevel.authNoPriv;
+
+ case "authPriv":
+ return SecurityLevel.authPriv;
+
+ default:
+ throw new SnmpException("Invalid Security level");
+ }
+ }
+
+ /**
+ * Validate snmpv3 configuration.
+ */
+ private void validateUsmConfiguration() {
+
+ validateSecurityName();
+
+ switch (securityLevel.getSnmpValue()) {
+
+ case SecurityLevel.AUTH_PRIV:
+ validateAuth();
+ validatePriv();
+ return;
+
+ case SecurityLevel.AUTH_NOPRIV:
+ validateAuth();
+ return;
+
+ case SecurityLevel.NOAUTH_NOPRIV:
+ return;
+
+ default:
+ throw new SnmpException("Invalid security level");
+
+ }
+ }
+
+ /**
+ * Validate snmpv3 authentication protocol and password.
+ */
+ private void validateAuth() {
+ checkNotNull(authProtocol, "Authentication protocol must be provided");
+ checkNotNull(authPassword, "Authentication password must be provided");
+ checkState(authPassword.length() >= PASS_CODE_LENGTH,
+ "Invalid authentication password");
+ }
+
+ private void validatePriv() {
+ checkNotNull(privacyProtocol, "Privacy protocol must be provided");
+ checkNotNull(privacyPassword, "Privacy password must be provided");
+ checkState(privacyPassword.length() >= PASS_CODE_LENGTH,
+ "Invalid privacy password");
+ }
+
+ /**
+ * Validate snmpv3 privacy protocol and password.
+ */
+ private void validateSecurityName() {
+ checkNotNull(securityName, "Security name must be provided");
+ checkState(!privacyPassword.isEmpty(), "Invalid security name");
+ }
+
+ /**
+ * Create snmpv3 configuration instance.
+ *
+ * @return v3snmp configuration object
+ */
+ public V3SnmpConfiguration build() {
+ validateUsmConfiguration();
+ return new V3SnmpConfiguration(this);
+ }
+
+ }
+
+}
diff --git a/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java
index 41b4123..db7a877 100644
--- a/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java
+++ b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java
@@ -20,6 +20,7 @@
import com.btisystems.pronx.ems.core.snmp.ISnmpConfigurationFactory;
import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
import com.btisystems.pronx.ems.core.snmp.ISnmpSessionFactory;
+import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.alarm.Alarm;
@@ -52,13 +53,15 @@
@Before
public void setUp() {
- snmpController.sessionFactory = mockSnmpSessionFactory;
+ snmpController.factoryMap = Maps.newHashMap();
+ snmpController.factoryMap.put(1, mockSnmpSessionFactory);
}
@Test
public void testActivate() {
snmpController.activate(null);
- assertNotNull("Incorrect sessionFactory", snmpController.sessionFactory);
+ assertTrue("Snmp session factory map should contain atleast one factory object",
+ snmpController.factoryMap.size() > 0);
}
@Test
diff --git a/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpv3DeviceTest.java b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpv3DeviceTest.java
new file mode 100644
index 0000000..d663b5a
--- /dev/null
+++ b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpv3DeviceTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2021-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.snmp.ctl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.snmp.SnmpDeviceConfig;
+
+import java.io.InputStream;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test class for DefaultSnmpv3Device.
+ */
+public class DefaultSnmpv3DeviceTest {
+
+ private final SnmpDeviceConfig config = new SnmpDeviceConfig();
+ private final InputStream jsonStream = DefaultSnmpv3DeviceTest.class
+ .getResourceAsStream("/device.json");
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ private static final String KEY = "snmp";
+ private final String snmpHost = "1.1.1.1";
+ private final int snmpPort = 1;
+ private final String username = "test";
+ private final String community = "test";
+ private final DeviceId deviceId = DeviceId.deviceId("snmp:1.1.1.1:1");
+ private final String defaultProtocol = "udp";
+ private final String securityLevel = "authPriv";
+ private final String securityName = "sdnonos";
+ private final String authProtocol = "SHA";
+ private final String authPassword = "sdn@1234";
+ private final String privProtocol = "AES";
+ private final String privPassword = "sdn@1234";
+ private final String contextName = "sdn-context";
+
+ private DefaultSnmpv3Device defaultSnmpv3Device;
+
+
+ @Before
+ public void setUp() throws Exception {
+ JsonNode jsonNode = mapper.readTree(jsonStream);
+ ConfigApplyDelegate delegate = new DefaultSnmpv3DeviceTest.MockDelegate();
+ config.init(deviceId, KEY, jsonNode, mapper, delegate);
+ defaultSnmpv3Device = new DefaultSnmpv3Device(config);
+ }
+
+ /**
+ * Tests fetching snmp host.
+ */
+ @Test
+ public void testGetSnmpHost() {
+ assertEquals(snmpHost, defaultSnmpv3Device.getSnmpHost());
+ }
+
+ /**
+ * Tests fetching snmp port.
+ */
+ @Test
+ public void testGetSnmpPort() {
+ assertEquals(snmpPort, defaultSnmpv3Device.getSnmpPort());
+ }
+
+ /**
+ * Tests fetching username.
+ */
+ @Test
+ public void testGetUsername() {
+ assertEquals(username, defaultSnmpv3Device.getUsername());
+ }
+
+ /**
+ * Tests fetching community string.
+ */
+ @Test
+ public void testGetCommunity() {
+ assertEquals(community, defaultSnmpv3Device.getCommunity());
+ }
+
+ /**
+ * Tests fetching protocol.
+ */
+ @Test
+ public void testGetProtocol() {
+ assertEquals(defaultProtocol, defaultSnmpv3Device.getProtocol());
+ }
+
+ /**
+ * Tests fetching security name.
+ */
+ @Test
+ public void testGetSecurityName() {
+ assertEquals(securityName, defaultSnmpv3Device.getSecurityName());
+ }
+
+ /**
+ * Tests fetching security level.
+ */
+ @Test
+ public void testGetSecurityLevel() {
+ assertEquals(securityLevel, defaultSnmpv3Device.getSecurityLevel());
+ }
+
+ /**
+ * Tests fetching authentication protocol.
+ */
+ @Test
+ public void testGetAuthProtocol() {
+ assertEquals(authProtocol, defaultSnmpv3Device.getAuthProtocol());
+ }
+
+ /**
+ * Tests fetching authentication password.
+ */
+ @Test
+ public void testGetAuthPassword() {
+ assertEquals(authPassword, defaultSnmpv3Device.getAuthPassword());
+ }
+
+ /**
+ * Tests fetching privacy protocol.
+ */
+ @Test
+ public void testGetPrivProtocol() {
+ assertEquals(privProtocol, defaultSnmpv3Device.getPrivProtocol());
+ }
+
+ /**
+ * Tests fetching privacy password.
+ */
+ @Test
+ public void testGetPrivPassword() {
+ assertEquals(privPassword, defaultSnmpv3Device.getPrivPassword());
+ }
+
+ /**
+ * Tests fetching context name.
+ */
+ @Test
+ public void testGetContextName() {
+ assertEquals(contextName, defaultSnmpv3Device.getContextName());
+ }
+
+ private class MockDelegate implements ConfigApplyDelegate {
+ @Override
+ public void onApply(Config config) {
+
+ }
+ }
+
+}
diff --git a/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/V3SnmpConfigurationTest.java b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/V3SnmpConfigurationTest.java
new file mode 100644
index 0000000..5ea4dc4
--- /dev/null
+++ b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/V3SnmpConfigurationTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2021-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.snmp.ctl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.snmp.SnmpDeviceConfig;
+import org.onosproject.snmp.SnmpException;
+import org.snmp4j.TransportMapping;
+import org.snmp4j.security.AuthSHA;
+import org.snmp4j.security.PrivAES128;
+import org.snmp4j.security.SecurityLevel;
+import org.snmp4j.smi.Address;
+import org.snmp4j.smi.GenericAddress;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test class for V3SnmpConfiguration.
+ */
+public class V3SnmpConfigurationTest {
+
+ private final SnmpDeviceConfig config = new SnmpDeviceConfig();
+ private final InputStream jsonStream = DefaultSnmpv3DeviceTest.class
+ .getResourceAsStream("/device.json");
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ private static final String KEY = "snmp";
+ private final String snmpHost = "1.1.1.1";
+ private final int snmpPort = 1;
+ private final String username = "test";
+ private final String community = "test";
+ private final DeviceId deviceId = DeviceId.deviceId("snmp:1.1.1.1:1");
+ private final String defaultProtocol = "udp";
+ private final String securityName = "sdnonos";
+ private final String authProtocol = "SHA";
+ private final String authPassword = "sdn@1234";
+ private final String privPassword = "sdn@1234";
+ private final String contextName = "sdn-context";
+
+ private static final String SLASH = "/";
+
+ private DefaultSnmpv3Device defaultSnmpv3Device;
+ private V3SnmpConfiguration v3SnmpConfiguration;
+
+ @Before
+ public void setUp() throws Exception {
+ JsonNode jsonNode = mapper.readTree(jsonStream);
+ ConfigApplyDelegate delegate = new MockDelegate();
+ config.init(deviceId, KEY, jsonNode, mapper, delegate);
+ defaultSnmpv3Device = new DefaultSnmpv3Device(config);
+
+ v3SnmpConfiguration = V3SnmpConfiguration.builder()
+ .setAddress(defaultSnmpv3Device.getSnmpHost())
+ .setSecurityName(defaultSnmpv3Device.getSecurityName())
+ .setSecurityLevel(defaultSnmpv3Device.getSecurityLevel())
+ .setAuthenticationProtocol(defaultSnmpv3Device.getAuthProtocol())
+ .setAuthenticationPassword(defaultSnmpv3Device.getAuthPassword())
+ .setPrivacyProtocol(defaultSnmpv3Device.getPrivProtocol())
+ .setPrivacyPassword(defaultSnmpv3Device.getPrivPassword())
+ .setContextName(defaultSnmpv3Device.getContextName())
+ .build();
+
+ v3SnmpConfiguration.setPort(defaultSnmpv3Device.getSnmpPort());
+ }
+
+ /**
+ * Test snmp create target exception case.
+ *
+ * @throws IOException
+ */
+ @Test(expected = SnmpException.class)
+ public void testCreateTargetException() throws IOException {
+ Address targetAddress = GenericAddress.parse(
+ defaultSnmpv3Device.getProtocol() +
+ ":" + defaultSnmpv3Device.getSnmpHost() +
+ "/" + defaultSnmpv3Device.getSnmpPort());
+
+ TransportMapping transport = new DefaultUdpTransportMapping();
+ v3SnmpConfiguration.createSnmpSession(transport);
+ v3SnmpConfiguration.createTarget(targetAddress);
+
+ }
+
+ /**
+ * Test fetching security level.
+ */
+ @Test
+ public void testGetSecurityLevel() {
+ assertEquals(SecurityLevel.AUTH_PRIV, v3SnmpConfiguration.getSecurityLevel().getSnmpValue());
+ }
+
+ /**
+ * Test fetching snmp host address.
+ */
+ @Test
+ public void testGetAddress() {
+ assertEquals(snmpHost, v3SnmpConfiguration.getAddress().toString());
+ }
+
+ /**
+ * Test fetching security name.
+ */
+ @Test
+ public void testGetSecurityName() {
+ assertEquals(securityName, v3SnmpConfiguration.getSecurityName());
+ }
+
+ /**
+ * Test fetching authentication password.
+ */
+ @Test
+ public void testGetAuthenticationPassword() {
+ assertEquals(authPassword, v3SnmpConfiguration.getAuthenticationPassword());
+ }
+
+ /**
+ * Test fetching authentication protocol.
+ */
+ @Test
+ public void testGetAuthenticationProtocol() {
+ assertEquals(AuthSHA.ID, v3SnmpConfiguration.getAuthenticationProtocol());
+ }
+
+ /**
+ * Test fetching privacy password.
+ */
+ @Test
+ public void testGetPrivacyPassword() {
+ assertEquals(privPassword, v3SnmpConfiguration.getPrivacyPassword());
+ }
+
+ /**
+ * Test fetching privacy protocol.
+ */
+ @Test
+ public void testGetPrivacyProtocol() {
+ assertEquals(PrivAES128.ID, v3SnmpConfiguration.getPrivacyProtocol());
+ }
+
+ /**
+ * Test fetching context name.
+ */
+ @Test
+ public void testGetContextName() {
+ assertEquals(contextName, v3SnmpConfiguration.getContextName());
+ }
+
+ private class MockDelegate implements ConfigApplyDelegate {
+ @Override
+ public void onApply(Config config) {
+
+ }
+ }
+
+}
diff --git a/protocols/snmp/ctl/src/test/resources/device.json b/protocols/snmp/ctl/src/test/resources/device.json
new file mode 100644
index 0000000..0902b47
--- /dev/null
+++ b/protocols/snmp/ctl/src/test/resources/device.json
@@ -0,0 +1,15 @@
+{
+ "ip": "1.1.1.1",
+ "port": 1,
+ "username": "test",
+ "password": "test",
+ "version": 3,
+ "communityString": "sdnonos",
+ "securityLevel": "authPriv",
+ "securityName": "sdnonos",
+ "authProtocol": "SHA",
+ "authPassword": "sdn@1234",
+ "privacyProtocol": "AES",
+ "privacyPassword": "sdn@1234",
+ "contextName": "sdn-context"
+}
diff --git a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java b/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
index ddd81c7..6a06a98 100644
--- a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
+++ b/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
@@ -15,6 +15,8 @@
*/
package org.onosproject.provider.snmp.device.impl;
+import org.onosproject.snmp.SnmpException;
+import org.onosproject.snmp.ctl.DefaultSnmpv3Device;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
@@ -52,6 +54,7 @@
import org.onosproject.snmp.ctl.DefaultSnmpDevice;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
+import org.snmp4j.mp.SnmpConstants;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -166,7 +169,14 @@
deviceSubjects.forEach(deviceId -> {
SnmpDeviceConfig config =
netCfgService.getConfig(deviceId, SnmpDeviceConfig.class);
- buildDevice(new DefaultSnmpDevice(config));
+ if (config.version() == SnmpConstants.version2c) {
+ buildDevice(new DefaultSnmpDevice(config));
+ } else if (config.version() == SnmpConstants.version3) {
+ buildDevice(new DefaultSnmpv3Device(config));
+ } else {
+ throw new SnmpException(
+ String.format("Invalid snmp version %d", config.version()));
+ }
});
}