Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rsu health monitor #564

Merged
merged 54 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
67b74d6
init
dan-du-car Nov 7, 2023
4b70589
update snmp call
dan-du-car Nov 7, 2023
0ec2806
update RSU status message
dan-du-car Nov 7, 2023
1013355
update
dan-du-car Nov 7, 2023
25cf9fc
add gps parse
dan-du-car Nov 8, 2023
0577b21
update
dan-du-car Nov 8, 2023
d959d97
clean code
dan-du-car Nov 8, 2023
bf91eae
add security level
dan-du-car Nov 8, 2023
c1ad5c9
update snmp
dan-du-car Nov 8, 2023
1e041fd
update priv
dan-du-car Nov 9, 2023
66e15d4
update priv
dan-du-car Nov 9, 2023
f9ecabf
update
dan-du-car Nov 9, 2023
331e390
snmp update
dan-du-car Nov 9, 2023
cf8f392
snmp update
dan-du-car Nov 9, 2023
a04a0ee
snmp update
dan-du-car Nov 9, 2023
bb97d7a
snmp update
dan-du-car Nov 9, 2023
a047264
snmp update
dan-du-car Nov 9, 2023
ee211d7
str to double
dan-du-car Nov 9, 2023
c0bac10
address comments
dan-du-car Nov 9, 2023
1edaf32
update source
dan-du-car Nov 9, 2023
d747a98
address comments and add unit test
dan-du-car Nov 10, 2023
dd94272
address comments and add unit test
dan-du-car Nov 10, 2023
dedf357
update break
dan-du-car Nov 10, 2023
9f565ec
update break
dan-du-car Nov 10, 2023
04de385
update break
dan-du-car Nov 10, 2023
861f198
update break
dan-du-car Nov 10, 2023
d7bdd64
update
dan-du-car Nov 10, 2023
2754ad3
update
dan-du-car Nov 10, 2023
537df66
update
dan-du-car Nov 10, 2023
1569792
update
dan-du-car Nov 10, 2023
aabd56a
update
dan-du-car Nov 10, 2023
5f7858e
address comments
dan-du-car Nov 13, 2023
d468935
address comments
dan-du-car Nov 13, 2023
7a4238a
address comments
dan-du-car Nov 13, 2023
cef89f5
address comments
dan-du-car Nov 13, 2023
74e5b8f
address code smell
dan-du-car Nov 13, 2023
2ea0021
code smell
dan-du-car Nov 13, 2023
b4c46ec
code smell
dan-du-car Nov 13, 2023
40e57d5
code smell
dan-du-car Nov 13, 2023
fd375bb
code smell
dan-du-car Nov 13, 2023
0d35b67
add unit test
dan-du-car Nov 13, 2023
1e1e7a1
code smell
dan-du-car Nov 13, 2023
ad40e04
update code coverage
dan-du-car Nov 13, 2023
f5732e3
code coverage
dan-du-car Nov 13, 2023
30c891c
update code coverage
dan-du-car Nov 13, 2023
a49366e
address comments
dan-du-car Nov 14, 2023
c118f90
update code coverage
dan-du-car Nov 14, 2023
d517517
update code coverage
dan-du-car Nov 14, 2023
a1639de
update code coverage
dan-du-car Nov 14, 2023
6526ac4
updade code coverage
dan-du-car Nov 14, 2023
be3b634
updade code coverage
dan-du-car Nov 14, 2023
f169b5d
updade code coverage
dan-du-car Nov 14, 2023
e904058
updade code coverage
dan-du-car Nov 14, 2023
072ccfa
thread issue
dan-du-car Nov 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .sonarqube/sonar-scanner.properties
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ sonar.modules= PedestrianPlugin, \
MessageReceiverPlugin, \
CARMAStreetsPlugin, \
ERVCloudForwardingPlugin, \
CDASimAdapter
CDASimAdapter, \
RSUHealthMonitorPlugin



Expand All @@ -82,6 +83,7 @@ TimPlugin.sonar.projectBaseDir =src/v2i-hub/TimPlugin
CARMAStreetsPlugin.sonar.projectBaseDir =src/v2i-hub/CARMAStreetsPlugin
ERVCloudForwardingPlugin.sonar.projectBaseDir =src/v2i-hub/ERVCloudForwardingPlugin
CDASimAdapter.sonar.projectBaseDir =src/v2i-hub/CDASimAdapter
RSUHealthMonitorPlugin.sonar.projectBaseDir =src/v2i-hub/RSUHealthMonitorPlugin



Expand Down Expand Up @@ -117,7 +119,8 @@ CARMAStreetsPlugin.sonar.exclusions =test/**
ERVCloudForwardingPlugin.sonar.sources =src
CDASimAdapter.sonar.sources =src
CDASimAdapter.sonar.exclusions =test/**

RSUHealthMonitorPlugin.sonar.sources =src
RSUHealthMonitorPlugin.sonar.exclusions =test/**

# Tests
# Note: For C++ setting this field does not cause test analysis to occur. It only allows the test source code to be evaluated.
Expand Down Expand Up @@ -145,3 +148,4 @@ SpatPlugin.sonar.tests=test
CARMAStreetsPlugin.sonar.tests=test
ERVCloudForwardingPlugin.sonar.tests=test
CDASimAdapter.sonar.tests=test
RSUHealthMonitorPlugin.sonar.tests=test
1 change: 1 addition & 0 deletions src/tmx/Messages/include/MessageTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ static CONSTEXPR const char *MSGSUBTYPE_OUTGOING_STRING = "Outgoing";
static CONSTEXPR const char *MSGSUBTYPE_SHUTDOWN_STRING = "Shutdown";
static CONSTEXPR const char *MSGSUBTYPE_TIMESYNC_STRING = "TimeSync";
static CONSTEXPR const char *MSGSUBTYPE_SENSOR_DETECTED_OBJECT_STRING = "SensorDetectedObject";
static CONSTEXPR const char *MSGSUBTYPE_RSU_STATUS_STRING = "RSUStatus";

} /* End namespace messages */

Expand Down
25 changes: 25 additions & 0 deletions src/tmx/Messages/include/RSUStatusMessage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once


#include <tmx/messages/message.hpp>
#include "MessageTypes.h"


namespace tmx::messages {


class RSUStatusMessage : public tmx::message
{
public:
RSUStatusMessage() {}
paulbourelly999 marked this conversation as resolved.
Show resolved Hide resolved

/// Message type for routing this message through TMX core.
static constexpr const char* MessageType = MSGTYPE_APPLICATION_STRING;

/// Message sub type for routing this message through TMX core.
static constexpr const char* MessageSubType = MSGSUBTYPE_RSU_STATUS_STRING;
};

} /* namespace tmx::messages */


12 changes: 10 additions & 2 deletions src/tmx/TmxUtils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
PROJECT ( tmxutils CXX )
FILE (GLOB_RECURSE HEADERS "src/" "*.h*")
FILE (GLOB_RECURSE SOURCES "src/" "*.c*")

paulbourelly999 marked this conversation as resolved.
Show resolved Hide resolved
find_library(NETSNMPAGENT "netsnmpagent")
find_library(NETSNMPMIBS "netsnmpmibs")
find_library(NETSNMP "netsnmp")

FIND_PACKAGE (carma-clock)
FIND_LIBRARY (UUID_LIBRARY uuid)
Expand All @@ -16,12 +18,18 @@ TARGET_INCLUDE_DIRECTORIES (${PROJECT_NAME} SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<BUILD_INTERFACE:${TMXMESSAGES_INCLUDE_DIR}>
${MYSQL_INCLUDE_DIR}
${NETSNMP_INCLUDE_DIRS}
${MYSQLCPPCONN_INCLUDE_DIR})
TARGET_LINK_LIBRARIES (${PROJECT_NAME} PUBLIC
${TMXAPI_LIBRARIES}
${MYSQL_LIBRARIES}
${MYSQLCPPCONN_LIBRARIES}
${UUID_LIBRARY}
${UUID_LIBRARY}
${NETSNMPAGENT}
${NETSNMPMIBS}
${NETSNMP}
${NETSNMP_LIBRARIES}
rdkafka++
::carma-clock
gmock
Expand Down Expand Up @@ -54,4 +62,4 @@ add_executable(${BINARY} ${TEST_SOURCES})

add_test(NAME ${BINARY} COMMAND ${BINARY})

target_link_libraries(${BINARY} PUBLIC ${PROJECT_NAME} rdkafka++ gmock ${TMXAPI_LIBRARIES} ${ASN_J2735_LIBRARIES} ${UUID_LIBRARY} gtest)
target_link_libraries(${BINARY} PUBLIC ${PROJECT_NAME} rdkafka++ gmock ${TMXAPI_LIBRARIES} ${ASN_J2735_LIBRARIES} ${UUID_LIBRARY} ${NETSNMPAGENT} ${NETSNMPMIBS} ${NETSNMP} ${NETSNMP_LIBRARIES} gtest)
56 changes: 56 additions & 0 deletions src/tmx/TmxUtils/src/RSU_MIB_4_1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once
namespace tmx::utils::rsu41::mib::oid
{
/**
* @brief This header file contains a subset of RSU MIB definition from https://github.com/certificationoperatingcouncil/COC_TestSpecs/blob/master/AppNotes/RSU/RSU-MIB.txt
*/
// Contains the ID given to this RSU.
static constexpr const char *RSU_ID_OID = "1.0.15628.4.1.17.4.0";

// Contains the version of this MIB supported by this RSU, e.g. rsuMIB 4.1 rev201812060000Z
static constexpr const char *RSU_MIB_VERSION = "1.0.15628.4.1.17.1.0";

// Contains the version of firmware running on this RSU.
static constexpr const char *RSU_FIRMWARE_VERSION = "1.0.15628.4.1.17.2.0";

// Contains the name of the manufacturer of this RSU.
static constexpr const char *RSU_MANUFACTURER = "1.0.15628.4.1.17.5.0";

// Contains GPS NMEA GPGGA output string.
static constexpr const char *RSU_GPS_OUTPUT_STRING = "1.0.15628.4.1.8.5.0";

// Immediate Forward Message Index
static constexpr const char *RSU_IFM_INDEX = "1.0.15628.4.1.5.1.1.0";

// Immediate Forward Message PSID.
static constexpr const char *RSU_IFM_PSID = "1.0.15628.4.1.5.1.2.0";

// Immediate Forward Message DSRC Message ID
static constexpr const char *RSU_IFM_DSRC_MSG_ID = "1.0.15628.4.1.5.1.3.0";

// Immediate Forward Message Transmit Mode
static constexpr const char *RSU_IFM_TX_MODE = "1.0.15628.4.1.5.1.4.0";

// DSRC channel set for Immediate Forward Message transmit
static constexpr const char *RSU_IFM_TX_CHANNEL = "1.0.15628.4.1.5.1.5.0";

// Set this bit to enable transmission of the message 0=off, 1=on
static constexpr const char *RSU_IFM_ENABLE = "1.0.15628.4.1.5.1.6.0";

// Create (4) or Destroy (6) row entry
static constexpr const char *RSU_IFM_STATUS = "1.0.15628.4.1.5.1.7.0";

// Specifies the current mode of operation of the RSU and provides capability to transition the device into a new mode, e.g. from the current mode to off, etc
static constexpr const char *RSU_MODE = "1.0.15628.4.1.99.0";

/*
SYNTAX INTEGER {
bothOp (0), --both Continuous and Alternating modes are operational
altOp (1), --Alternating mode is operational,
--Continuous mode is not operational
contOp (2), --Continuous mode is operational,
--Alternating mode is not operational
noneOp (3) --neither Continuous nor Alternating mode is operational
*/
static constexpr const char *RSU_CHAN_STATUS = "1.0.15628.4.1.19.1.0";
}
227 changes: 227 additions & 0 deletions src/tmx/TmxUtils/src/SNMPClient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
#include "SNMPClient.h"

namespace tmx::utils
{

// Client defaults to SNMPv3
snmp_client::snmp_client(const std::string &ip, const int &port, const std::string &community,
const std::string &snmp_user, const std::string &securityLevel, const std::string &authPassPhrase, int snmp_version, int timeout)

: ip_(ip), port_(port), community_(community), snmp_version_(snmp_version), timeout_(timeout)
{

PLOG(logDEBUG1) << "Starting SNMP Client. Target device IP address: " << ip_ << ", Target device SNMP port: " << port_;

// Bring the IP address and port of the target SNMP device in the required form, which is "IPADDRESS:PORT":
std::string ip_port_string = ip_ + ":" + std::to_string(port_);
char *ip_port = &ip_port_string[0];

// Initialize SNMP session parameters
init_snmp("carma_snmp");
snmp_sess_init(&session);
session.peername = ip_port;
session.version = snmp_version_; // SNMP_VERSION_3
session.securityName = (char *)snmp_user.c_str();
session.securityNameLen = snmp_user.length();

// Fallback behavior to setup a community for SNMP V1/V2
if (snmp_version_ != SNMP_VERSION_3)
{
session.community = (unsigned char *)community.c_str();
session.community_len = community_.length();
}

// SNMP authorization/privach config
if (securityLevel == "authPriv")
{
session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
}

else if (securityLevel == "authNoPriv")
{
session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
}

else
session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;

// Passphrase used for both authentication and privacy
auto phrase_len = authPassPhrase.length();
auto phrase = (u_char *)authPassPhrase.c_str();

// Defining and generating auth config with SHA1
session.securityAuthProto = snmp_duplicate_objid(usmHMACSHA1AuthProtocol, USM_AUTH_PROTO_SHA_LEN);
session.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
session.securityAuthKeyLen = USM_AUTH_KU_LEN;
if (session.securityLevel != SNMP_SEC_LEVEL_NOAUTH && generate_Ku(session.securityAuthProto,
session.securityAuthProtoLen,
phrase, phrase_len,
session.securityAuthKey,
&session.securityAuthKeyLen) != SNMPERR_SUCCESS)
{
std::string errMsg = "Error generating Ku from authentication pass phrase. \n";
throw snmp_client_exception(errMsg);
}

// Defining and generating priv config with AES (since using SHA1)
session.securityPrivKeyLen = USM_PRIV_KU_LEN;
session.securityPrivProto =
snmp_duplicate_objid(usmAESPrivProtocol,
OID_LENGTH(usmAESPrivProtocol));
session.securityPrivProtoLen = OID_LENGTH(usmAESPrivProtocol);

if (session.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV && generate_Ku(session.securityAuthProto,
session.securityAuthProtoLen,
phrase, phrase_len,
session.securityPrivKey,
&session.securityPrivKeyLen) != SNMPERR_SUCCESS)
{
std::string errMsg = "Error generating Ku from privacy pass phrase. \n";
throw snmp_client_exception(errMsg);
}

session.timeout = timeout_;

// Opens the snmp session if it exists
ss = snmp_open(&session);

if (ss == nullptr)
{
PLOG(logERROR) << "Failed to establish session with target device";
snmp_sess_perror("snmpget", &session);
throw snmp_client_exception("Failed to establish session with target device");
}
else
{
PLOG(logINFO) << "Established session with device at " << ip_;
}
}

snmp_client::~snmp_client()
{
PLOG(logINFO) << "Closing SNMP session";
snmp_close(ss);
}

// Original implementation used in Carma Streets https://github.com/usdot-fhwa-stol/snmp-client
bool snmp_client::process_snmp_request(const std::string &input_oid, const request_type &request_type, snmp_response_obj &val)
{

/*Structure to hold response from the remote host*/
snmp_pdu *response;

// Create pdu for the data
if (request_type == request_type::GET)
{
PLOG(logDEBUG1) << "Attempting to GET value for: " << input_oid;
pdu = snmp_pdu_create(SNMP_MSG_GET);
}
else if (request_type == request_type::SET)
{
PLOG(logDEBUG1) << "Attempting to SET value for " << input_oid << " to " << val.val_int;
pdu = snmp_pdu_create(SNMP_MSG_SET);
}
else
{
PLOG(logERROR) << "Invalid request type, method accpets only GET and SET";
return false;
}

// Read input OID into an OID variable:
// net-snmp has several methods for creating an OID object
// their documentation suggests using get_node. read_objid seems like a simpler approach
// TO DO: investigate update to get_node
if (!read_objid(input_oid.c_str(), OID, &OID_len))
{
// If oid cannot be created
PLOG(logERROR) << "OID could not be created from input: " << input_oid;
return false;
}
else
{

if (request_type == request_type::GET)
{
// Add OID to pdu for get request
snmp_add_null_var(pdu, OID, OID_len);
}
else if (request_type == request_type::SET)
{
if (val.type == snmp_response_obj::response_type::INTEGER)
{
snmp_add_var(pdu, OID, OID_len, 'i', (std::to_string(val.val_int)).c_str());
}
// Needs to be finalized to support octet string use
else if (val.type == snmp_response_obj::response_type::STRING)
{
PLOG(logERROR) << "Setting string value is currently not supported";
}
}

PLOG(logINFO) << "Created OID for input: " << input_oid;
}
// Send the request
int status = snmp_synch_response(ss, pdu, &response);
PLOG(logINFO) << "Response request status: " << status << " (=" << (status == STAT_SUCCESS ? "SUCCESS" : "FAILED") << ")";

// Check GET response
if (status == STAT_SUCCESS && response && response->errstat == SNMP_ERR_NOERROR && request_type == request_type::GET)
{
for (auto vars = response->variables; vars; vars = vars->next_variable)
{
// Get value of variable depending on ASN.1 type
// Variable could be a integer, string, bitstring, ojbid, counter : defined here https://github.com/net-snmp/net-snmp/blob/master/include/net-snmp/types.h
// get Integer value
if (vars->type == ASN_INTEGER && vars->val.integer)
{
val.type = snmp_response_obj::response_type::INTEGER;
val.val_int = *vars->val.integer;
}
else if (vars->type == ASN_OCTET_STR && vars->val.string)
{
size_t str_len = vars->val_len;
for (size_t i = 0; i < str_len; ++i)
{
val.val_string.push_back(vars->val.string[i]);
}
val.type = snmp_response_obj::response_type::STRING;
}
}
}
else
{
log_error(status, request_type, response);
return false;
}

if (response)
{
snmp_free_pdu(response);
OID_len = MAX_OID_LEN;
}

return true;
}

int snmp_client::get_port() const
{
return port_;
}

void snmp_client::log_error(const int &status, const request_type &request_type, const snmp_pdu *response) const
{

if (status == STAT_SUCCESS)
{
PLOG(logERROR) << "Variable type: " << response->variables->type << ". Error in packet " << static_cast<std::string>(snmp_errstring(static_cast<int>(response->errstat)));
}
else if (status == STAT_TIMEOUT)
{
PLOG(logERROR) << "Timeout, no response from server";
}
else
{
PLOG(logERROR) << "Unknown SNMP Error for " << (request_type == request_type::GET ? "GET" : "SET");
}
}
} // namespace
Loading