Merge "Add new Link Monitor (lmond) daemon to Mtce"

This commit is contained in:
Zuul 2019-02-04 17:07:02 +00:00 committed by Gerrit Code Review
commit 6e7bbf6e35
21 changed files with 1886 additions and 42 deletions

View File

@ -8,6 +8,7 @@ mtce-pmon
mtce-rmon
mtce-hwmon
mtce-hostw
mtce-lmon
# mtce-compute
mtce-compute

View File

@ -27,6 +27,33 @@ static char rest_api_filename[MAX_FILENAME_LEN];
static char rest_api_log_str [MAX_API_LOG_LEN];
static libEvent nullEvent ;
#define HTTP_GET_STR "GET"
#define HTTP_PUT_STR "PUT"
#define HTTP_PATCH_STR "PATCH"
#define HTTP_POST_STR "POST"
#define HTTP_DELETE_STR "DELETE"
#define HTTP_UNKNOWN_STR "UNKNOWN"
/* convert http event type to its string name */
const char * getHttpCmdType_str ( evhttp_cmd_type type )
{
switch (type)
{
case EVHTTP_REQ_GET: return(HTTP_GET_STR);
case EVHTTP_REQ_PUT: return(HTTP_PUT_STR);
case EVHTTP_REQ_PATCH: return(HTTP_PATCH_STR);
case EVHTTP_REQ_POST: return(HTTP_POST_STR);
case EVHTTP_REQ_DELETE: return(HTTP_DELETE_STR);
case EVHTTP_REQ_HEAD:
case EVHTTP_REQ_OPTIONS:
case EVHTTP_REQ_TRACE:
case EVHTTP_REQ_CONNECT:
default:
break ;
}
return(HTTP_UNKNOWN_STR);
}
/* ***********************************************************************
*
* Name : httpUtil_event_init
@ -1057,3 +1084,132 @@ void httpUtil_log_event ( libEvent * event_ptr )
send_log_message ( mtclogd_ptr, event_ptr->hostname.data(), &rest_api_filename[0], &rest_api_log_str[0] );
}
/*****************************************************************
*
* Name : httpUtil_bind
*
* Description : Setup the HTTP server socket
*
*****************************************************************/
int httpUtil_bind ( libEvent & event )
{
int one = 1;
event.fd = socket(AF_INET, SOCK_STREAM, 0);
if (event.fd < 0)
{
elog ("failed to create http server socket (%d:%m)\n", errno );
return FAIL_SOCKET_CREATE ;
}
/* make socket reusable */
if ( 0 > setsockopt(event.fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int)))
{
elog ("failed to set http server socket to reusable (%d:%m)\n", errno );
return FAIL_SOCKET_OPTION ;
}
memset(&event.addr, 0, sizeof(struct sockaddr_in));
event.addr.sin_family = AF_INET;
/* ERIK: INADDR_ANY; TODO: Refine this if we can */
event.addr.sin_addr.s_addr = inet_addr(LOOPBACK_IP);
// event.addr.sin_addr.s_addr = INADDR_ANY;
event.addr.sin_port = htons(event.port);
/* bind port */
if ( 0 > bind ( event.fd, (struct sockaddr*)&event.addr, sizeof(struct sockaddr_in)))
{
elog ("failed to bind to http server port %d (%d:%m)\n", event.port, errno );
return FAIL_SOCKET_BIND ;
}
/* Listen for events */
if ( 0 > listen(event.fd, 10 ))
{
elog ("failed to listen to http server socket (%d:%m)\n", errno );
return FAIL_SOCKET_LISTEN;
}
/* make non-blocking */
int flags = fcntl ( event.fd, F_GETFL, 0) ;
if ( flags < 0 || fcntl(event.fd, F_SETFL, flags | O_NONBLOCK) < 0)
{
elog ("failed to set http server socket to non-blocking (%d:%m)\n", errno );
return FAIL_SOCKET_OPTION;
}
return PASS;
}
/* Setup the http server */
int httpUtil_setup ( libEvent & event,
int supported_methods,
void(*hdlr)(struct evhttp_request *, void *) )
{
int rc = PASS ;
if ( ( rc = httpUtil_bind ( event )) != PASS )
{
return rc ;
}
else if (event.fd < 0)
{
wlog ("failed to get http server socket file descriptor\n");
return RETRY ;
}
event.base = event_base_new();
if (event.base == NULL)
{
elog ("failed to get http server event base\n");
return -1;
}
event.httpd = evhttp_new(event.base);
if (event.httpd == NULL)
{
elog ("failed to get httpd server handle\n");
return -1;
}
/* api is a void return */
evhttp_set_allowed_methods (event.httpd, supported_methods );
rc = evhttp_accept_socket(event.httpd, event.fd);
if ( rc == -1)
{
elog ("failed to accept on http server socket\n");
return -1;
}
/* api is a void return */
evhttp_set_gencb(event.httpd, hdlr, NULL);
ilog ("Listening On: 'http server' socket %s:%d\n",
inet_ntoa(event.addr.sin_addr), event.port );
return PASS ;
}
void httpUtil_fini ( libEvent & event )
{
if ( event.fd )
{
if ( event.base )
{
event_base_free( event.base);
}
close ( event.fd );
event.fd = 0 ;
}
}
void httpUtil_look ( libEvent & event )
{
/* Look for Events */
if ( event.base )
{
// rc = event_base_loopexit( mtce_event.base, NULL ) ; // EVLOOP_NONBLOCK );
event_base_loop(event.base, EVLOOP_NONBLOCK );
}
}

View File

@ -12,6 +12,7 @@
#include <evhttp.h> /* for ... http libevent client */
#include <time.h>
#include <list>
#include <fcntl.h> /* for ... F_GETFL */
using namespace std;
@ -22,6 +23,7 @@ using namespace std;
#define MTC_HTTP_BAD_REQUEST 400
#define MTC_HTTP_UNAUTHORIZED 401
#define MTC_HTTP_FORBIDDEN 403
#define MTC_HTTP_METHOD_NOT_ALLOWED 405
#define MTC_HTTP_CONFLICT 409
#define MTC_HTTP_LENGTH_REQUIRED 411
#define MTC_HTTP_NORESPONSE 444
@ -194,6 +196,10 @@ struct libEvent
struct evbuffer *buf ; /**< HTTP output buffer ptr */
struct evbuffer_ptr evp ; /**< HTTP output buffer ptr */
int fd ;
struct sockaddr_in addr ;
struct evhttp *httpd ;
string log_prefix ; /**< log prefix for this event */
/** Service Specific Request Info */
@ -339,5 +345,14 @@ void httpUtil_event_info ( libEvent & event );
const char * getHttpCmdType_str ( evhttp_cmd_type type );
/* HTTP Server setup utilities */
int httpUtil_bind ( libEvent & event );
int httpUtil_setup ( libEvent & event,
int supported_methods,
void(*hdlr)(struct evhttp_request *, void *));
/* Cleanup */
void httpUtil_fini ( libEvent & event );
void httpUtil_look ( libEvent & event );
#endif /* __INCLUDE_HTTPUTIL_H__ */

View File

@ -55,6 +55,7 @@ typedef struct
int mtc_agent_port ; /**< mtcAgent receive port (from Client) */
int mtc_client_port ; /**< mtcClient receive port (from Agent) */
char* uri_path ; /**< /mtce/lmon ... for link monitor */
int keystone_port ; /**< Keystone REST API port number */
char* keystone_prefix_path ; /**< Keystone REST API prefix path */
char* keystone_auth_host ; /**< =auth_host=192.168.204.2 */
@ -67,7 +68,6 @@ typedef struct
char* keystone_user_domain; /**< = Default */
char* keystone_project_domain; /**< = Default */
char* keyring_directory ; /**< =/opt/platform/.keyring/<release> */
char* sysinv_mtc_inv_label ; /**< =/v1/hosts/ */
int sysinv_api_port ; /**< =6385 */
char* sysinv_api_bind_ip ; /**< =<local floating IP> */
@ -114,8 +114,9 @@ typedef struct
int event_port ; /**< daemon specific event tx port */
int cmd_port ; /**< daemon specific command rx port */
int sensor_port ; /**< sensor read value port */
int sm_server_port ; /**< port mtce uses to receive data from SM */
int sm_client_port ; /**< port mtce uses to send SM data */
int sm_server_port ; /**< port mtce uses to receive data from SM */
int sm_client_port ; /**< port mtce uses to send SM data */
int lmon_query_port ;
int start_delay ; /**< startup delay, added for pmon */
int api_retries ; /**< api retries before failure */
int hostwd_failure_threshold ; /**< allowed # of missed pmon/hostwd messages */

View File

@ -1489,33 +1489,6 @@ string get_event_str ( int event_code )
}
}
#define HTTP_GET_STR "GET"
#define HTTP_PUT_STR "PUT"
#define HTTP_PATCH_STR "PATCH"
#define HTTP_POST_STR "POST"
#define HTTP_DELETE_STR "DELETE"
#define HTTP_UNKNOWN_STR "UNKNOWN"
/* Private: convert http event type to its string name */
const char * getHttpCmdType_str ( evhttp_cmd_type type )
{
switch (type)
{
case EVHTTP_REQ_GET: return(HTTP_GET_STR);
case EVHTTP_REQ_PUT: return(HTTP_PUT_STR);
case EVHTTP_REQ_PATCH: return(HTTP_PATCH_STR);
case EVHTTP_REQ_POST: return(HTTP_POST_STR);
case EVHTTP_REQ_DELETE: return(HTTP_DELETE_STR);
case EVHTTP_REQ_HEAD:
case EVHTTP_REQ_OPTIONS:
case EVHTTP_REQ_TRACE:
case EVHTTP_REQ_CONNECT:
default:
break ;
}
return(HTTP_UNKNOWN_STR);
}
#define MAX_NUM_LEN 64
string itos ( int val )
{
@ -1527,6 +1500,17 @@ string itos ( int val )
return (temp);
}
#define MAX_NUM_LEN 64
string lltos (long long unsigned int val )
{
char int_str[MAX_NUM_LEN] ;
string temp ;
memset ( &int_str[0], 0, MAX_NUM_LEN );
snprintf ( &int_str[0], MAX_NUM_LEN, "%llu" , val );
temp = int_str ;
return (temp);
}
string ftos ( float val, int resolution )
{
char float_str[MAX_NUM_LEN] ;

View File

@ -99,9 +99,9 @@ int get_link_state ( int ioctl_socket , const char * iface_ptr, bool * run
int open_ioctl_socket ( void );
string get_event_str ( int event_code );
const char * getHttpCmdType_str ( evhttp_cmd_type type );
string itos ( int val );
string lltos (long long unsigned int val );
string ftos ( float val, int resolution );
unsigned short checksum(void *b, int len);

View File

@ -34,6 +34,7 @@ void daemon_config_default ( daemon_config_type* config_ptr )
config_ptr->mon_process_5 = strdup("none");
config_ptr->mon_process_6 = strdup("none");
config_ptr->mon_process_7 = strdup("none");
config_ptr->uri_path = strdup("");
config_ptr->keystone_prefix_path = strdup("");
config_ptr->keystone_identity_uri = strdup("");
config_ptr->keystone_auth_uri = strdup("");
@ -295,6 +296,7 @@ void daemon_dump_cfg ( void )
/* mtcAgent & hwmond */
if ( ptr->sysinv_api_port ) { ilog ("sysinv_api_port = %d\n", ptr->sysinv_api_port );}
if ( ptr->uri_path ) { ilog ("uri_path = %s\n", ptr->uri_path );}
if ( ptr->keystone_prefix_path ) { ilog ("keystone_prefix_path = %s\n", ptr->keystone_prefix_path );}
if ( ptr->keystone_auth_host ) { ilog ("keystone_auth_host = %s\n", ptr->keystone_auth_host );}
if ( ptr->keystone_identity_uri ) { ilog ("keystone_identity_uri = %s\n", ptr->keystone_identity_uri );}

View File

@ -1,3 +1,3 @@
SRC_DIR="src"
TIS_PATCH_VER=145
TIS_PATCH_VER=146
BUILD_IS_SLOW=5

View File

@ -178,7 +178,7 @@ Provides: librmonapi.so.1()(64bit)
Titanium Cloud Host Maintenance Resource Monitor Service (rmond) adds
threshold based monitoring with predictive severity level alarming for
out of tolerance utilization of critical resourses such as memory, cpu
file system, interface state, etc.
file system, etc.
%package -n mtce-hwmon
Summary: Titanuim Server Maintenance Hardware Monitor Package
@ -266,6 +266,39 @@ of spec operating conditions that can reduce outage time through automated
notification and recovery thereby improving overall platform availability
for the customer.
%package -n mtce-lmon
Summary: Titanuim Server Maintenance Link Monitor Package
Group: base
BuildRequires: cppcheck
Requires: util-linux
Requires: /bin/bash
Requires: /bin/systemctl
Requires: dpkg
Requires: time
Requires: libstdc++.so.6(CXXABI_1.3)(64bit)
Requires: libfmcommon.so.1()(64bit)
Requires: libc.so.6(GLIBC_2.7)(64bit)
Requires: libc.so.6(GLIBC_2.2.5)(64bit)
Requires: libstdc++.so.6(GLIBCXX_3.4.11)(64bit)
Requires: /bin/sh
Requires: libc.so.6(GLIBC_2.3)(64bit)
Requires: libc.so.6(GLIBC_2.14)(64bit)
Requires: librt.so.1(GLIBC_2.3.3)(64bit)
Requires: libgcc_s.so.1(GCC_3.0)(64bit)
Requires: librt.so.1(GLIBC_2.2.5)(64bit)
Requires: libm.so.6()(64bit)
Requires: rtld(GNU_HASH)
Requires: libstdc++.so.6()(64bit)
Requires: libc.so.6(GLIBC_2.4)(64bit)
Requires: libc.so.6()(64bit)
Requires: libgcc_s.so.1()(64bit)
Requires: libstdc++.so.6(GLIBCXX_3.4)(64bit)
Requires: libstdc++.so.6(GLIBCXX_3.4.15)(64bit)
%description -n mtce-lmon
Titanium Cloud Maintenance Link Monitor service (lmond) provides
netlink monitoring for provisioned oam, mgmt and infra interfaces.
%define local_dir /usr/local
%define local_bindir %{local_dir}/bin
%define local_sbindir %{local_dir}/sbin
@ -321,6 +354,7 @@ install -m 644 -p -D %{_buildsubdir}/scripts/mtc.conf %{buildroot}%{_sysconfdir}
install -m 644 -p -D %{_buildsubdir}/fsmon/scripts/fsmond.conf %{buildroot}%{_sysconfdir}/mtc/fsmond.conf
install -m 644 -p -D %{_buildsubdir}/hwmon/scripts/hwmond.conf %{buildroot}%{_sysconfdir}/mtc/hwmond.conf
install -m 644 -p -D %{_buildsubdir}/pmon/scripts/pmond.conf %{buildroot}%{_sysconfdir}/mtc/pmond.conf
install -m 644 -p -D %{_buildsubdir}/lmon/scripts/lmond.conf %{buildroot}%{_sysconfdir}/mtc/lmond.conf
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/rmond.conf %{buildroot}%{_sysconfdir}/mtc/rmond.conf
install -m 644 -p -D %{_buildsubdir}/hostw/scripts/hostwd.conf %{buildroot}%{_sysconfdir}/mtc/hostwd.conf
@ -335,6 +369,7 @@ install -m 755 -p -D %{_buildsubdir}/maintenance/mtcClient %{buildroot}/%{local_
install -m 755 -p -D %{_buildsubdir}/heartbeat/hbsAgent %{buildroot}/%{local_bindir}/hbsAgent
install -m 755 -p -D %{_buildsubdir}/heartbeat/hbsClient %{buildroot}/%{local_bindir}/hbsClient
install -m 755 -p -D %{_buildsubdir}/pmon/pmond %{buildroot}/%{local_bindir}/pmond
install -m 755 -p -D %{_buildsubdir}/lmon/lmond %{buildroot}/%{local_bindir}/lmond
install -m 755 -p -D %{_buildsubdir}/hostw/hostwd %{buildroot}/%{local_bindir}/hostwd
install -m 755 -p -D %{_buildsubdir}/rmon/rmond %{buildroot}/%{local_bindir}/rmond
install -m 755 -p -D %{_buildsubdir}/fsmon/fsmond %{buildroot}/%{local_bindir}/fsmond
@ -355,6 +390,7 @@ install -m 755 -p -D %{_buildsubdir}/hwmon/scripts/lsb/hwmon %{buildroot}%{_sysc
install -m 755 -p -D %{_buildsubdir}/fsmon/scripts/fsmon %{buildroot}%{_sysconfdir}/init.d/fsmon
install -m 755 -p -D %{_buildsubdir}/scripts/mtclog %{buildroot}%{_sysconfdir}/init.d/mtclog
install -m 755 -p -D %{_buildsubdir}/pmon/scripts/pmon %{buildroot}%{_sysconfdir}/init.d/pmon
install -m 755 -p -D %{_buildsubdir}/lmon/scripts/lmon %{buildroot}%{_sysconfdir}/init.d/lmon
install -m 755 -p -D %{_buildsubdir}/rmon/scripts/rmon %{buildroot}%{_sysconfdir}/init.d/rmon
install -m 755 -p -D %{_buildsubdir}/hostw/scripts/hostw %{buildroot}%{_sysconfdir}/init.d/hostw
install -m 755 -p -D %{_buildsubdir}/alarm/scripts/mtcalarm.init %{buildroot}%{_sysconfdir}/init.d/mtcalarm
@ -377,6 +413,7 @@ install -m 644 -p -D %{_buildsubdir}/scripts/mtclog.service %{buildroot}%{_unitd
install -m 644 -p -D %{_buildsubdir}/scripts/goenabled.service %{buildroot}%{_unitdir}/goenabled.service
install -m 644 -p -D %{_buildsubdir}/scripts/runservices.service %{buildroot}%{_unitdir}/runservices.service
install -m 644 -p -D %{_buildsubdir}/alarm/scripts/mtcalarm.service %{buildroot}%{_unitdir}/mtcalarm.service
install -m 644 -p -D %{_buildsubdir}/lmon/scripts/lmon.service %{buildroot}%{_unitdir}/lmon.service
# go enabled stuff
install -m 755 -d %{buildroot}%{local_etc_goenabledd}
@ -407,18 +444,15 @@ install -m 644 -p -D %{_buildsubdir}/rmon/scripts/rmon.conf %{buildroot}%{local_
install -m 644 -p -D %{_buildsubdir}/fsmon/scripts/fsmon.conf %{buildroot}%{local_etc_pmond}/fsmon.conf
install -m 644 -p -D %{_buildsubdir}/scripts/mtclogd.conf %{buildroot}%{local_etc_pmond}/mtclogd.conf
install -m 644 -p -D %{_buildsubdir}/alarm/scripts/mtcalarm.pmon.conf %{buildroot}%{local_etc_pmond}/mtcalarm.conf
install -m 644 -p -D %{_buildsubdir}/lmon/scripts/lmon.pmon.conf %{buildroot}%{local_etc_pmond}/lmon.conf
# resource monitor config files
install -m 755 -d %{buildroot}%{local_etc_rmond}
install -m 755 -d %{buildroot}%{_sysconfdir}/rmonapi.d
install -m 755 -d %{buildroot}%{_sysconfdir}/rmonfiles.d
install -m 755 -d %{buildroot}%{_sysconfdir}/rmon_interfaces.d
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/remotelogging_resource.conf %{buildroot}%{local_etc_rmond}/remotelogging_resource.conf
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/cinder_virtual_resource.conf %{buildroot}%{local_etc_rmond}/cinder_virtual_resource.conf
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/nova_virtual_resource.conf %{buildroot}%{local_etc_rmond}/nova_virtual_resource.conf
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/oam_resource.conf %{buildroot}%{_sysconfdir}/rmon_interfaces.d/oam_resource.conf
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/management_resource.conf %{buildroot}%{_sysconfdir}/rmon_interfaces.d/management_resource.conf
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/infrastructure_resource.conf %{buildroot}%{_sysconfdir}/rmon_interfaces.d/infrastructure_resource.conf
install -m 755 -p -D %{_buildsubdir}/rmon/scripts/rmon_reload_on_cpe.sh %{buildroot}%{local_etc_goenabledd}/rmon_reload_on_cpe.sh
# log rotation
@ -426,6 +460,7 @@ install -m 755 -d %{buildroot}%{_sysconfdir}/logrotate.d
install -m 644 -p -D %{_buildsubdir}/scripts/mtce.logrotate %{buildroot}%{local_etc_logrotated}/mtce.logrotate
install -m 644 -p -D %{_buildsubdir}/hostw/scripts/hostw.logrotate %{buildroot}%{local_etc_logrotated}/hostw.logrotate
install -m 644 -p -D %{_buildsubdir}/pmon/scripts/pmon.logrotate %{buildroot}%{local_etc_logrotated}/pmon.logrotate
install -m 644 -p -D %{_buildsubdir}/lmon/scripts/lmon.logrotate %{buildroot}%{local_etc_logrotated}/lmon.logrotate
install -m 644 -p -D %{_buildsubdir}/rmon/scripts/rmon.logrotate %{buildroot}%{local_etc_logrotated}/rmon.logrotate
install -m 644 -p -D %{_buildsubdir}/fsmon/scripts/fsmon.logrotate %{buildroot}%{local_etc_logrotated}/fsmon.logrotate
install -m 644 -p -D %{_buildsubdir}/hwmon/scripts/hwmon.logrotate %{buildroot}%{local_etc_logrotated}/hwmon.logrotate
@ -466,6 +501,9 @@ install -m 755 -d %{buildroot}/var/run
%post -n mtce-rmon
/bin/systemctl enable rmon.service
%post -n mtce-lmon
/bin/systemctl enable lmon.service
###############################
# Maintenance RPM Files
###############################
@ -583,10 +621,6 @@ install -m 755 -d %{buildroot}/var/run
%{local_etc_rmond}/cinder_virtual_resource.conf
%{local_etc_rmond}/nova_virtual_resource.conf
%{_sysconfdir}/rmon_interfaces.d/management_resource.conf
%{_sysconfdir}/rmon_interfaces.d/oam_resource.conf
%{_sysconfdir}/rmon_interfaces.d/infrastructure_resource.conf
%{_libdir}/librmonapi.so.1.0
%{_libdir}/librmonapi.so.1
%{_libdir}/librmonapi.so
@ -628,6 +662,21 @@ install -m 755 -d %{buildroot}/var/run
%{_sysconfdir}/init.d/hostw
%{local_bindir}/hostwd
###############################
# Link Monitor RPM Files
###############################
%files -n mtce-lmon
%defattr(-,root,root,-)
# Config files - Non-Modifiable
%{_sysconfdir}/mtc/lmond.conf
%{_unitdir}/lmon.service
%{local_etc_logrotated}/lmon.logrotate
%{local_etc_pmond}/lmon.conf
%{local_bindir}/lmond
%{_sysconfdir}/init.d/lmon
###############################
# Maintenance Software Development RPM
###############################

View File

@ -16,6 +16,7 @@ build:
(cd maintenance ; make build VER=$(VER) VER_MJR=$(VER_MJR))
(cd hwmon ; make build VER=$(VER) VER_MJR=$(VER_MJR))
(cd mtclog ; make build VER=$(VER) VER_MJR=$(VER_MJR))
(cd lmon ; make build VER=$(VER) VER_MJR=$(VER_MJR))
(cd pmon ; make build VER=$(VER) VER_MJR=$(VER_MJR))
(cd fsmon ; make build VER=$(VER) VER_MJR=$(VER_MJR))
(cd rmon ; make build VER=$(VER) VER_MJR=$(VER_MJR))
@ -30,6 +31,7 @@ clean:
@( cd alarm ; make clean )
@( cd mtclog ; make clean )
@( cd hwmon ; make clean )
@( cd lmon ; make clean )
@( cd pmon ; make clean )
@( cd fsmon ; make clean )
@( cd heartbeat ; make clean )

35
mtce/src/lmon/Makefile Executable file
View File

@ -0,0 +1,35 @@
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
SHELL = /bin/bash
SRCS = lmonInit.cpp lmonUtil.cpp lmonHdlr.cpp
OBJS = $(SRCS:.cpp=.o)
LDLIBS = -lstdc++ -ldaemon -lcommon -ljson-c -lcrypto -lrt -levent
LDPATH = -L../../../mtce-common/src/daemon -L../../../mtce-common/src/common
INCLUDES = -I. -I/usr/include/mtce-daemon -I/usr/include/mtce-common
CCFLAGS = -g -O2 -Wall -Wextra -Werror
STATIC_ANALYSIS_TOOL = cppcheck
STATIC_ANALYSIS_TOOL_EXISTS = $(shell [[ -e `which $(STATIC_ANALYSIS_TOOL)` ]] && echo 1 || echo 0)
all: clean static_analysis build
.cpp.o:
$(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o $@
static_analysis:
ifeq ($(STATIC_ANALYSIS_TOOL_EXISTS), 1)
$(STATIC_ANALYSIS_TOOL) --language=c++ --enable=warning -U__AREA__ *.cpp *.h
else
echo "Warning: '$(STATIC_ANALYSIS_TOOL)' static analysis tool not installed ; bypassing ..."
endif
build: clean static_analysis $(OBJS)
$(CXX) $(CCFLAGS) $(OBJS) $(LDPATH) $(LDLIBS) -o lmond
clean:
@rm -v -f $(OBJ) lmond *.o *.a

119
mtce/src/lmon/lmon.h Normal file
View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include <net/if.h> /* for ... IF_NAMESIZE */
using namespace std;
#include "daemon_ini.h" /* for ... ini_parse */
#include "daemon_common.h" /* for ... daemon common definitions and types */
#include "nodeBase.h" /* for ... maintenance base definitions */
#include "nodeTimers.h" /* for ... mtcTimer_init/start/stop utilities */
#include "nodeUtil.h" /* for ... common utils like open_ioctl_socket */
#include "httpUtil.h" /* for ... httputil_setup */
#include "nlEvent.h" /* for ... open_netlink_socket */
#include "fmAPI.h" /* for ... FMTimeT */
#ifdef __AREA__
#undef __AREA__
#endif
#define __AREA__ "mon"
#define INTERFACES_DIR ((const char *)"/sys/class/net/")
#define PLATFORM_DIR ((const char *)"/etc/platform/platform.conf")
#define INTERFACES_MAX (3) /* maximum number of interfaces to monitor */
enum interface_type { ethernet = 0, vlan = 1, bond = 2 };
string iface_type ( interface_type type_enum );
/* daemon only supports the GET request */
#define HTTP_SUPPORTED_METHODS (EVHTTP_REQ_GET)
typedef struct
{
int ioctl_socket ;
int netlink_socket ;
libEvent http_event ;
msgSock_type mtclogd ;
int dos_log_throttle ;
struct mtc_timer audit_timer ;
char my_hostname[MAX_HOST_NAME_SIZE+1];
char my_address [MAX_CHARS_IN_IP_ADDR+1];
} lmon_ctrl_type ;
typedef struct
{
const char * name ; /* pointer to well known primary interface name */
/* primary interface names */
#define MGMT_INTERFACE_NAME ((const char *)"mgmt")
#define INFRA_INTERFACE_NAME ((const char *)"infra")
#define OAM_INTERFACE_NAME ((const char *)"oam")
/* name labels used in platform.conf */
#define MGMT_INTERFACE_FULLNAME ((const char *)"management_interface")
#define INFRA_INTERFACE_FULLNAME ((const char *)"infrastructure_interface")
#define OAM_INTERFACE_FULLNAME ((const char *)"oam_interface")
/* true if the interface is configured.
* i.e. the name label shown above is found in platform.conf */
bool used ;
interface_type type_enum ;
/* true if the link is up ; false otherwise */
bool interface_one_link_up ;
bool interface_two_link_up ;
FMTimeT interface_one_event_time ;
FMTimeT interface_two_event_time ;
/* Config Items */
const char * severity ; /* MINOR, MAJOR or CRITICAL for each resource */
unsigned int debounce ; /* Period to wait before clearing alarms */
unsigned int num_tries ; /* Number of times a resource has to be in
failed or cleared state before sending alarm */
/* Dynamic Data */
char interface_one[IF_NAMESIZE] ; /* primary interface */
char interface_two[IF_NAMESIZE] ; /* second interface if lagged */
char bond[IF_NAMESIZE] ; /* bonded interface name */
bool lagged ; /* Lagged interface=true or not=false */
// unsigned int debounce_cnt ; /* running monitor debounce count */
// unsigned int minorlog_cnt ; /* track minor log count for thresholding */
// unsigned int count ; /* track the number of times the condition has been occured */
// bool failed ; /* track if the resource needs to be serviced by the resource handler */
// int resource_value ; /* 1 if the interface is up and 0 if it is down */
// int resource_value_lagged ; /* 1 if the interface is up and 0 if it is down for lagged interfaces */
// int sev ; /* The severity of the failed resource */
// rmonStage_enum stage ; /* The stage the resource is in within the resource handler fsm */
// char alarm_id[FM_MAX_BUFFER_LENGTH] ; /* Used by FM API, type of alarm being raised */
// char alarm_id_port[FM_MAX_BUFFER_LENGTH] ; /* Used by FM API, type of alarm being raised for the ports */
// char errorMsg[ERR_SIZE];
// rmon_api_socket_type msg;
// bool link_up_and_running; /* whether the interface is up or down initially */
// bool alarm_raised;
// int failed_send; /* The number of times the rmon api failed to send a message */
} interface_ctrl_type ;
/* lmonHdlr.cpp */
void daemon_exit ( void );
void lmon_learn_interfaces ( int ioctl_sock );
/* lmonUtils.cpp */
FMTimeT lmon_fm_timestamp ( void );
int lmon_interfaces_init ( interface_ctrl_type * ptr );
int lmon_get_link_state ( int ioctl_socket,
char iface[IF_NAMESIZE],
bool & link_up );

769
mtce/src/lmon/lmonHdlr.cpp Normal file
View File

@ -0,0 +1,769 @@
/*
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
/**
* @file
* Starling-X Maintenance Link Monitor Service Header
*/
#include "lmon.h"
#include <linux/rtnetlink.h> /* for ... RTMGRP_LINK */
#include "nodeMacro.h" /* for ... CREATE_REUSABLE_INET_UDP_TX_SOCKET */
#define HTTP_SERVER_NAME ((const char *)"link status query")
static lmon_ctrl_type lmon_ctrl ;
static interface_ctrl_type interfaces[INTERFACES_MAX];
static const char * iface_list[INTERFACES_MAX] = { MGMT_INTERFACE_NAME,
INFRA_INTERFACE_NAME,
OAM_INTERFACE_NAME };
/* httpUtil needs a mtclog socket pointer */
msgSock_type * get_mtclogd_sockPtr ( void )
{
return (&lmon_ctrl.mtclogd);
}
/* dump state before exiting */
void daemon_exit ( void )
{
daemon_files_fini ();
daemon_dump_info ();
exit (0);
}
/* daemon timer handler */
void lmonTimer_handler ( int sig, siginfo_t *si, void *uc)
{
UNUSED(sig); UNUSED(uc);
timer_t * tid_ptr = (void**)si->si_value.sival_ptr ;
if ( !(*tid_ptr) )
return ;
else if (( *tid_ptr == lmon_ctrl.audit_timer.tid ) )
lmon_ctrl.audit_timer.ring = true ;
else
mtcTimer_stop_tid_int_safe ( tid_ptr );
}
/*****************************************************************************
*
* Name : lmonHdlr_http_handler
*
* Description: Handle HTTP Link Status Query requests.
*
* Method : GET
*
******************************************************************************/
#define DOS_LOG_THROTTLE_THLD (10000)
void lmonHdlr_http_handler (struct evhttp_request *req, void *arg)
{
int http_status_code = HTTP_NOTFOUND ;
UNUSED(arg);
if ( ! req )
return;
/* Get sender must be localhost */
const char * host_ptr = evhttp_request_get_host (req);
if (( host_ptr == NULL ) ||
(( strncmp ( host_ptr , "localhost" , 10 ) != 0 ) &&
( strncmp ( host_ptr , LOOPBACK_IP , 10 ) != 0 )))
{
wlog_throttled ( lmon_ctrl.dos_log_throttle,
DOS_LOG_THROTTLE_THLD,
"Message received from unknown host (%s)\n",
host_ptr?host_ptr:"(null)" );
return ;
}
const char * uri_ptr = evhttp_request_get_uri (req);
if ( uri_ptr == NULL )
{
wlog_throttled ( lmon_ctrl.dos_log_throttle,
DOS_LOG_THROTTLE_THLD,
"null uri");
return ;
}
string uri_path = daemon_get_cfg_ptr()->uri_path ;
if (strncmp(uri_ptr, uri_path.data(), uri_path.length()))
{
wlog_throttled ( lmon_ctrl.dos_log_throttle,
DOS_LOG_THROTTLE_THLD,
"http request not for this service: %s",
uri_ptr);
return ;
}
/* Extract the operation */
evhttp_cmd_type http_cmd = evhttp_request_get_command (req);
jlog ("'%s' %s\n", uri_ptr, getHttpCmdType_str(http_cmd));
switch ( http_cmd )
{
case EVHTTP_REQ_GET:
{
http_status_code = HTTP_OK ;
break ;
}
default:
{
ilog_throttled ( lmon_ctrl.dos_log_throttle,
DOS_LOG_THROTTLE_THLD,
"unsupported %s request (%d)",
getHttpCmdType_str(http_cmd),
http_cmd);
http_status_code = MTC_HTTP_METHOD_NOT_ALLOWED ;
}
}
/*
* Link status query response format - success path
*
* Lagged case has an array of 2 links
*
{ "status" : "pass",
"link_info": [
{ "network":"mgmt",
"type":"vlan",
"links": [
{ "name":"enp0s8.1", "state":"Up/Down", "time":5674323454567 },
{ "name":"enp0s8.2", "state":"Up/Down", "time":5674323454567 }]
},
{ "network":"infra",
"type":"bond",
"bond":"bond0",
"links": [
{ "name":"enp0s9f1", "state":"Up/Down", "time":5674323454567 },
{ "name":"enp0s9f0", "state":"Up/Down", "time":5674323454567 }]
},
{ "network":"oam",
"type":"ethernet",
"links": [
{ "name":"enp0s3", "state":"Up/Down", "time":5674323454567 }]
}]
}
*
*lmonHdlr.cpp
*
*/
// #define WANT_TYPE_STR
// #define WANT_BOND_STR
if (( http_status_code == HTTP_OK ) || ( http_status_code == MTC_HTTP_ACCEPTED ))
{
/* build response string */
string response = "{ \"status\":\"pass\",\"link_info\":[" ;
/* loop over the interfaces and build a response string for each
* of those that are used */
for ( int i = 0 ; i < INTERFACES_MAX ; i++ )
{
if ((interfaces[i].used == true) && (interfaces[i].name[0] != '\0'))
{
if ( i > 0 )
response.append (",");
response.append ("{\"network\":\"");
response.append (interfaces[i].name);
response.append ("\"");
#ifdef WANT_TYPE_STR
string type_str = "ethernet" ;
if ( interfaces[i].type_enum == bond )
type_str = "bond" ;
else if ( interfaces[i].type_enum == vlan )
type_str = "vlan" ;
response.append (",\"type\":\"" + type_str + "\"");
#endif
#ifdef WANT_BOND_STR
if ( interfaces[i].type_enum == bond )
{
response.append (",\"bond\":\"");
response.append (interfaces[i].bond);
response.append ("\"");
}
#endif
response.append (",\"links\":[");
{
response.append ("{\"name\":\"");
response.append (interfaces[i].interface_one);
response.append ("\",\"state\":\"");
response.append (interfaces[i].interface_one_link_up?"Up":"Down");
response.append ("\",\"time\":\"" + lltos(interfaces[i].interface_one_event_time) + "\"}");
}
if (( interfaces[i].lagged ) &&
( interfaces[i].interface_two[0] != '\0'))
{
response.append (",{\"name\":\"");
response.append (interfaces[i].interface_two);
response.append ("\",\"state\":\"");
response.append (interfaces[i].interface_two_link_up?"Up":"Down");
response.append ("\",\"time\":\"" + lltos(interfaces[i].interface_two_event_time) + "\"}");
}
response.append ("]}");
}
}
response.append ("]}");
struct evbuffer * resp_buf = evbuffer_new();
jlog ("Resp: %s\n", response.c_str());
evbuffer_add_printf (resp_buf, "%s\n", response.data());
evhttp_send_reply (req, http_status_code, "OK", resp_buf );
evbuffer_free ( resp_buf );
}
else if ( http_status_code == MTC_HTTP_METHOD_NOT_ALLOWED )
{
/* build response string */
string response = "{" ;
response.append (" \"status\" : \"fail ; method not allowed\"");
response.append ("}");
struct evbuffer * resp_buf = evbuffer_new();
jlog ("Event Response: %s\n", response.c_str());
evbuffer_add_printf (resp_buf, "%s\n", response.data());
/* Add the 'Allow' header */
int rc = evhttp_add_header( req->output_headers, "Allow", "GET" );
if ( rc ) { ilog ("failed to add 'Allow' header (%d %d:%m", rc, errno);}
evhttp_send_reply (req, http_status_code, "NOT ALLOWED", resp_buf );
evbuffer_free ( resp_buf );
}
else
{
/* build response string */
string response = "{" ;
response.append (" \"status\" : \"fail ; bad request\"");
response.append ("}");
elog ("HTTP Event error:%d ; cmd:%s uri:%s response:%s\n",
http_status_code,
getHttpCmdType_str(http_cmd),
uri_ptr,
response.c_str());
evhttp_send_error (req, http_status_code, response.data() );
}
}
/*****************************************************************************
*
* Name : lmon_socket_init
*
* Purpose : Initialize all the sockets for this process.
*
* Sockets include ...
*
* 1. local kernel ioctl socket ; link attribute query
*
*****************************************************************************/
int lmon_socket_init ( lmon_ctrl_type * ctrl_ptr )
{
int rc = PASS ;
if ( ctrl_ptr )
{
httpUtil_event_init ( &lmon_ctrl.http_event,
&lmon_ctrl.my_hostname[0],
HTTP_SERVER_NAME,
lmon_ctrl.my_address,
daemon_get_cfg_ptr()->lmon_query_port );
if (( ctrl_ptr->ioctl_socket = open_ioctl_socket()) <= 0 )
{
/* errno/strerror logged by open utility if failure is detected */
elog ("failed to create ioctl socket\n");
rc = FAIL_SOCKET_CREATE ;
}
/* Note that address changes should not generate netlink events.
* Therefore these options are not set
* RTMGRP_IPV4_IFADDR
* RTMGRP_IPV6_IFADDR
*/
else if (( ctrl_ptr->netlink_socket = open_netlink_socket ( RTMGRP_LINK )) <= 0 )
{
/* errno/strerr logged by open utility if failure is detected */
elog ("failed to create netlink listener socket\n");
rc = FAIL_SOCKET_CREATE ;
}
else if ( httpUtil_setup ( ctrl_ptr->http_event,
HTTP_SUPPORTED_METHODS,
&lmonHdlr_http_handler ) != PASS )
{
/* errno/strerr logged by open utility if failure is detected */
elog ("failed to setup http server\n");
rc = FAIL_SOCKET_CREATE ;
}
else
{
ctrl_ptr->mtclogd.port = daemon_get_cfg_ptr()->daemon_log_port ;
CREATE_REUSABLE_INET_UDP_TX_SOCKET ( LOOPBACK_IP,
ctrl_ptr->mtclogd.port,
ctrl_ptr->mtclogd.sock,
ctrl_ptr->mtclogd.addr,
ctrl_ptr->mtclogd.port,
ctrl_ptr->mtclogd.len,
"mtc logger message",
rc );
if ( rc )
{
elog ("failed to setup mtce logger port %d\n", ctrl_ptr->mtclogd.port );
rc = PASS ;
}
}
}
else
{
rc = FAIL_NULL_POINTER ;
}
return (rc);
}
/*****************************************************************************
*
* Name : lmon_learn_interfaces
*
* Purpose : realize the interfaces to monitor in terms of
*
* - interface type ; ethernet, bonded or vlan
* - initial up/down state
*
*****************************************************************************/
void lmon_learn_interfaces ( int ioctl_socket )
{
/* initialize interface monitoring */
for ( int iface = 0 ; iface < INTERFACES_MAX ; iface++ )
{
interfaces[iface].name = iface_list[iface];
lmon_interfaces_init ( &interfaces[iface] );
if ( interfaces[iface].used == false )
continue ;
/* set the link state for all the primary physical interfaces */
if ( lmon_get_link_state ( ioctl_socket,
interfaces[iface].interface_one,
interfaces[iface].interface_one_link_up ) )
{
interfaces[iface].interface_one_event_time = lmon_fm_timestamp();
interfaces[iface].interface_one_link_up = false ;
wlog ("%s interface state query failed ; defaulting to Down\n",
interfaces[iface].interface_one) ;
}
else
{
interfaces[iface].interface_one_event_time = lmon_fm_timestamp();
ilog ("%s is %s\n",
interfaces[iface].interface_one,
interfaces[iface].interface_one_link_up ?
"Up" : "Down" );
if ( interfaces[iface].lagged == true )
{
/* set the link state for all the lagged physical interfaces */
if ( lmon_get_link_state ( ioctl_socket,
interfaces[iface].interface_two,
interfaces[iface].interface_two_link_up ) )
{
interfaces[iface].interface_two_event_time = lmon_fm_timestamp();
interfaces[iface].interface_two_link_up = false ;
wlog ("%s lag interface state query failed ; defaulting to Down\n",
interfaces[iface].interface_two) ;
}
else
{
interfaces[iface].interface_two_event_time = lmon_fm_timestamp();
ilog ("%s is %s (lag)\n",
interfaces[iface].interface_two,
interfaces[iface].interface_two_link_up ?
"Up" : "Down" );
}
}
}
}
}
/*****************************************************************************
*
* Name : service_interface_events
*
* Purpose : Service state changes for monitored link
*
* Description: netlink event driven state change handler.
*
*****************************************************************************/
int service_interface_events ( void )
{
list<string> links_gone_down ;
list<string> links_gone_up ;
list<string>::iterator iter_ptr ;
links_gone_down.clear();
links_gone_up.clear();
int events = get_netlink_events ( lmon_ctrl.netlink_socket,
links_gone_down,
links_gone_up );
if ( events <= 0 )
{
dlog1 ("called but get_netlink_events reported no events");
return RETRY ;
}
for ( int i = 0 ; i < INTERFACES_MAX ; i++ )
{
if ( interfaces[i].used == true )
{
bool running = false ;
/* handle links that went down */
if ( ! links_gone_down.empty() )
{
bool found = false ;
dlog ("netlink Down events: %ld", links_gone_down.size());
/* Look at the down list */
for ( iter_ptr = links_gone_down.begin();
iter_ptr != links_gone_down.end() ;
iter_ptr++ )
{
if ( strcmp ( interfaces[i].interface_one, iter_ptr->c_str()) == 0 )
{
found = true ;
interfaces[i].interface_one_event_time = lmon_fm_timestamp();
dlog ("%s is Down ; netlink event\n",
interfaces[i].interface_one );
if ( get_link_state ( lmon_ctrl.ioctl_socket,
iter_ptr->c_str(),
&running ) == PASS )
{
if ( interfaces[i].interface_one_link_up == true )
{
wlog ("%s is Down ; (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
else
{
dlog ("%s is Down ; (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
interfaces[i].interface_one_link_up = running ? true:false;
}
else
{
wlog ("%s is Down ; oper query failed\n",
iter_ptr->c_str());
interfaces[i].interface_one_link_up = false ;
}
}
else if (interfaces[i].lagged == true)
{
if ( strcmp ( interfaces[i].interface_two, iter_ptr->c_str()) == 0 )
{
found = true ;
interfaces[i].interface_two_event_time = lmon_fm_timestamp();
dlog ("%s is Down\n", interfaces[i].interface_two);
if ( get_link_state ( lmon_ctrl.ioctl_socket,
iter_ptr->c_str(),
&running ) == PASS )
{
if ( interfaces[i].interface_two_link_up == true )
{
wlog ("%s is Down (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
else
{
dlog ("%s is Down (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
interfaces[i].interface_two_link_up = running ? true:false;
}
else
{
wlog ("%s is Down ; oper query failed\n",
iter_ptr->c_str() );
interfaces[i].interface_two_link_up = false ;
}
}
if ( strcmp ( interfaces[i].bond, iter_ptr->c_str()) == 0 )
{
found = true ;
wlog ("%s is Down (bond)\n", interfaces[i].bond);
}
}
}
if ( ! found )
{
dlog ("netlink Down event on unmonitored link:%s", iter_ptr->c_str());
}
}
/* handle links that came up */
if ( !links_gone_up.empty() )
{
bool found = false ;
dlog ("netlink Up events: %ld", links_gone_up.size());
/* Look at the down list */
for ( iter_ptr = links_gone_up.begin();
iter_ptr != links_gone_up.end() ;
iter_ptr++ )
{
if ( strcmp ( interfaces[i].interface_one, iter_ptr->c_str()) == 0 )
{
found = true ;
interfaces[i].interface_one_event_time = lmon_fm_timestamp();
dlog ("%s is Up\n", interfaces[i].interface_one );
if ( get_link_state ( lmon_ctrl.ioctl_socket,
iter_ptr->c_str(),
&running ) == PASS )
{
if ( interfaces[i].interface_one_link_up == false )
{
ilog ("%s is Up (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
else
{
dlog ("%s is Up (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
interfaces[i].interface_one_link_up = running ? true:false;
}
else
{
wlog ("%s is Down ; oper query failed\n", iter_ptr->c_str() );
interfaces[i].interface_one_link_up = false ;
}
}
else if (interfaces[i].lagged == true)
{
if ( strcmp ( interfaces[i].interface_two, iter_ptr->c_str()) == 0 )
{
found = true ;
interfaces[i].interface_two_event_time = lmon_fm_timestamp();
dlog ("%s is Up\n", interfaces[i].interface_two );
if ( get_link_state ( lmon_ctrl.ioctl_socket,
iter_ptr->c_str(),
&running ) == PASS )
{
if ( interfaces[i].interface_two_link_up == false )
{
ilog ("%s is Up (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
else
{
dlog ("%s is Up (%s)\n",
iter_ptr->c_str(),
running ? "Up" : "Down" );
}
interfaces[i].interface_two_link_up = running ? true:false;
}
else
{
wlog ("%s is Down ; oper query failed\n", iter_ptr->c_str() );
interfaces[i].interface_two_link_up = false ;
}
}
if ( strcmp ( interfaces[i].bond, iter_ptr->c_str()) == 0 )
{
found = true ;
wlog ("%s is Up (bond)\n", interfaces[i].bond);
}
}
}
if ( ! found )
{
dlog ("netlink Up event on unmonitored link:%s", iter_ptr->c_str());
}
}
}
}
return (PASS);
}
/**************************************************************************
*
* Name : lmon_query_all_links
*
* Purpose : self correct for netlink event misses by running this
* as a periodic audit at a 1 minute cadence.
*
**************************************************************************/
void lmon_query_all_links( void )
{
dlog1 ("audit timer fired");
for ( int i = 0 ; i < INTERFACES_MAX ; i++ )
{
if ( interfaces[i].used )
{
bool link_up = false ;
string log_msg = "link state mismatch detected by audit";
if ( lmon_get_link_state ( lmon_ctrl.ioctl_socket,
interfaces[i].interface_one,
link_up) == PASS )
{
if ( link_up != interfaces[i].interface_one_link_up )
{
wlog ("%s %s ; is:%s was:%s ; corrected",
interfaces[i].interface_one,
log_msg.c_str(),
link_up?"Up":"Down",
interfaces[i].interface_one_link_up?"Up":"Down" );
interfaces[i].interface_one_event_time = lmon_fm_timestamp();
interfaces[i].interface_one_link_up = link_up ;
}
}
if ( interfaces[i].lagged )
{
if ( lmon_get_link_state ( lmon_ctrl.ioctl_socket,
interfaces[i].interface_two,
link_up) == PASS )
{
if ( link_up != interfaces[i].interface_two_link_up )
{
wlog ("%s %s ; is:%s was:%s ; corrected",
interfaces[i].interface_two,
log_msg.c_str(),
link_up?"Up":"Down",
interfaces[i].interface_two_link_up?"Up":"Down" );
interfaces[i].interface_two_event_time = lmon_fm_timestamp();
interfaces[i].interface_two_link_up = link_up ;
}
}
}
}
}
}
/*****************************************************************************
*
* Name : daemon_service_run
*
* Purpose : track interface profile link status.
*
* Assumptions: Event driven with self-correcting audit.
*
* General Behavior:
*
* Init:
*
* 1. learn interface/port model
* 2. setup http server
*
* Select:
*
* 3. load initial link status for learned links
* 4. listen for link status change events
* 5. provide link status info to http GET Query requests.
*
* Audit:
*
* 6. run 1 minute periodic self correcting audit.
*
*/
void daemon_service_run ( void )
{
fd_set readfds;
struct timeval waitd;
std::list<int> socks;
lmon_ctrl.ioctl_socket = 0 ;
lmon_ctrl.netlink_socket = 0 ;
memset (&lmon_ctrl.mtclogd, 0, sizeof(lmon_ctrl.mtclogd));
memset (&interfaces, 0, sizeof(interface_ctrl_type));
get_hostname (&lmon_ctrl.my_hostname[0], MAX_HOST_NAME_SIZE );
mtcTimer_init ( lmon_ctrl.audit_timer, lmon_ctrl.my_hostname, "audit");
string my_address = lmon_ctrl.my_address ;
get_iface_address ( daemon_mgmnt_iface().data(), my_address, true );
/* Setup the messaging sockets */
if (( lmon_socket_init ( &lmon_ctrl )) != PASS )
{
elog ("socket initialization failed ; exiting ...\n");
daemon_exit ();
}
else if ( 0 >= lmon_ctrl.netlink_socket )
{
elog ("failed to get ioctl socket descriptor (%d) ; exiting ...\n",
lmon_ctrl.netlink_socket );
daemon_exit ();
}
lmon_learn_interfaces ( lmon_ctrl.ioctl_socket );
int audit_secs = daemon_get_cfg_ptr()->audit_period ;
ilog ("started %d second link state self correcting audit", audit_secs );
mtcTimer_start ( lmon_ctrl.audit_timer, lmonTimer_handler, audit_secs );
socks.clear();
socks.push_front (lmon_ctrl.netlink_socket);
socks.sort();
ilog ("waiting on netlink events ...");
for (;;)
{
/* Accomodate for hup reconfig */
FD_ZERO(&readfds);
FD_SET(lmon_ctrl.netlink_socket, &readfds);
waitd.tv_sec = 0;
waitd.tv_usec = SOCKET_WAIT ;
/* This is used as a delay up to select timeout ; SOCKET_WAIT */
select( socks.back()+1, &readfds, NULL, NULL, &waitd);
if (FD_ISSET(lmon_ctrl.netlink_socket, &readfds))
{
dlog ("netlink socket fired\n");
service_interface_events ();
}
if ( lmon_ctrl.audit_timer.ring == true )
{
lmon_ctrl.audit_timer.ring = false ;
lmon_query_all_links();
}
httpUtil_look ( lmon_ctrl.http_event );
daemon_signal_hdlr();
}
daemon_exit();
}

145
mtce/src/lmon/lmonInit.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
/**
* @file
* Starling-X Maintenance Link Monitor Initialization
*/
#include "lmon.h"
/** Daemon Configuration Structure - Allocation and get pointer
* @see daemon_common.h for daemon_config_type struct format. */
static daemon_config_type lmon_config ;
daemon_config_type * daemon_get_cfg_ptr () { return &lmon_config ; }
/* read config label values */
static int lmon_config_handler ( void * user,
const char * section,
const char * name,
const char * value)
{
daemon_config_type* config_ptr = (daemon_config_type*)user;
if (MATCH("client", "audit_period"))
{
config_ptr->audit_period = atoi(value);
ilog ("Audit Period: %d (secs)", config_ptr->audit_period );
}
else if (MATCH("client", "lmon_query_port"))
{
config_ptr->lmon_query_port = atoi(value);
ilog ("Status Query: %d (port)", config_ptr->lmon_query_port );
}
else if (MATCH("client", "daemon_log_port"))
{
config_ptr->daemon_log_port = atoi(value);
ilog ("Daemon Log : %d (port)", config_ptr->daemon_log_port );
}
else if (MATCH("client", "uri_path"))
{
config_ptr->uri_path = strdup(value);
}
return (PASS);
}
/*****************************************************************************
*
* Name : daemon_configure
*
* Purpose : Read process config file settings into the daemon configuration
*
* Configuration File */
#define CONFIG_FILE ((const char *)"/etc/mtc/lmond.conf")
/*****************************************************************************/
int daemon_configure ( void )
{
int rc = PASS ;
/* read config out of /etc/mtc/lmond.conf */
if (ini_parse( CONFIG_FILE, lmon_config_handler, &lmon_config) < 0)
{
elog("Can't load '%s'\n", CONFIG_FILE );
rc = FAIL_INI_CONFIG ;
}
else
{
get_debug_options ( CONFIG_FILE, &lmon_config );
}
return (rc);
}
/*****************************************************************************
*
* Name : daemon_init
*
* Purpose : Daemon Initialization
*
*****************************************************************************/
int daemon_init ( string iface, string nodetype_str )
{
int rc = PASS ;
UNUSED(iface);
UNUSED(nodetype_str);
if ( daemon_files_init ( ) != PASS )
{
elog ("Pid, log or other files could not be opened\n");
return ( FAIL_FILES_INIT ) ;
}
/* Bind signal handlers */
if ( daemon_signal_init () != PASS )
{
elog ("daemon_signal_init failed\n");
return ( FAIL_SIGNAL_INIT );
}
daemon_wait_for_file ( CONFIG_COMPLETE_FILE, 0);
daemon_wait_for_file ( PLATFORM_DIR, 0);
daemon_wait_for_file ( GOENABLED_MAIN_READY, 0);
/* Configure the daemon */
if ( (rc = daemon_configure ( )) != PASS )
{
elog ("Daemon service configuration failed (rc:%i)\n", rc );
rc = FAIL_DAEMON_CONFIG ;
}
return (rc);
}
void daemon_dump_info ( void )
{
}
void daemon_sigchld_hdlr ( void )
{
; /* dlog("Received SIGCHLD ... no action\n"); */
}
const char MY_DATA [100] = { "eieio\n" } ;
const char * daemon_stream_info ( void )
{
return (&MY_DATA[0]);
}
/** Teat Head Entry */
int daemon_run_testhead ( void )
{
// ilog ("Empty test head.\n");
return (PASS);
}

415
mtce/src/lmon/lmonUtil.cpp Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
/**
* @file
* Starling-X Maintenance Link Monitor Utility
*/
#include "lmon.h"
#include <fstream> /* for ... ifstream */
#include <sstream> /* for ... stringstream */
#include <net/if.h> /* for ... if_indextoname , IF_NAMESIZE */
#include <sys/ioctl.h> /* for ... SIOCGIFFLAGS */
#include "nlEvent.h" /* for ... get_netlink_events */
#ifdef __AREA__
#undef __AREA__
#endif
#define __AREA__ "mon"
/*****************************************************************************
*
* Name : iface_type
*
* Purpose : convert interface type enum to representative string.
*
* Returns : 0:ethernet returns "ethernet"
* 1:vlan returns "vlan"
* 2:bond returns "bond"
* ? returns "unknown" ... error case
*
****************************************************************************/
string iface_type ( interface_type type_enum )
{
switch(type_enum)
{
case ethernet: return "ethernet";
case vlan: return "vlan" ;
case bond: return "bond" ;
default: return "unknown" ;
}
}
/*****************************************************************************
*
* Name : get_iflink_interface
*
* Purpose : Gets the ifname of the linked parent interface
*
* Returns : Returns a string containing the ifname.
*
****************************************************************************/
string get_iflink_interface (string & ifname )
{
string ret = "";
/* build the full file path */
string iflink_file = INTERFACES_DIR + ifname + "/iflink";
/* declare a file stream based on the full file path */
ifstream iflink_file_stream ( iflink_file.c_str() );
/* open the file stream */
if (iflink_file_stream.is_open())
{
int iflink = -1;
string iflink_line;
char * dummy_ptr ;
char iface_buffer [IF_NAMESIZE] = "";
memset (&iface_buffer[0], 0, IF_NAMESIZE);
while ( getline (iflink_file_stream, iflink_line) )
{
iflink = strtol(iflink_line.c_str(), &dummy_ptr, 10);
}
iflink_file_stream.close();
/*
* load iface_buffer with the name of the network interface
* corresponding to iflink.
*/
if_indextoname (iflink, iface_buffer);
if (iface_buffer[0] != '\0')
{
ret = iface_buffer;
}
else
{
slog ("no ifname from linked parent interface\n");
}
}
return ret;
}
/*****************************************************************************
*
* Name : lmon_fm_timestamp
*
* Purpose : Get a microsecond timestamp of the current time.
*
* Description: Used to record the time of link state changes.
*
* The value is included in link state query responses.
*
* Uses : FMTimeT from fmAPI.h
*
****************************************************************************/
FMTimeT lmon_fm_timestamp ( void )
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ( ts.tv_sec*1000000 + ts.tv_nsec/1000 );
}
/*****************************************************************************
*
* Name : lmon_get_link_state
*
* Purpose : Query the link up/down state of the specified interface.
*
* Updates : Sets the callers boolean pointer to ...
*
* true if interface is up
* false if interface is doewn
*
* Returns : PASS on query success.
* FAIL_OPERATION if the query was not successful.
*
****************************************************************************/
static int get_link_state_throttle = 0 ;
#define GET_LINK_STATE__LOG_THROTTLE (100)
int lmon_get_link_state ( int ioctl_socket,
char iface[IF_NAMESIZE],
bool & link_up )
{
int rc = FAIL_OPERATION ;
link_up = false ; /* default to link down */
if (iface[0] == '\0')
{
slog ("supplied interface name is invalid ; null\n");
return ( rc ) ;
}
/* Declare and load interface data for ioctl query */
struct ifreq if_data;
memset( &if_data, 0, sizeof(if_data) );
snprintf( if_data.ifr_name, IF_NAMESIZE, "%s", iface );
/* read the interface up/down state */
if( 0 <= ioctl( ioctl_socket, SIOCGIFFLAGS, &if_data ) )
{
if( if_data.ifr_flags & IFF_RUNNING )
link_up = true;
/* reset log flood gate counter */
get_link_state_throttle = 0 ;
rc = PASS ;
}
else
{
wlog_throttled (get_link_state_throttle,
GET_LINK_STATE__LOG_THROTTLE,
"failed to get %s (%s) interface state (%d:%s)\n",
iface,
if_data.ifr_name,
errno,
strerror(errno));
}
return ( rc );
}
/*****************************************************************************
*
* Name : lmon_interfaces_init
*
* Purpose : Map an interface (mgmt, oam or infra) to a physical port.
* See interface_type enum in lmon.h
*
*****************************************************************************/
int lmon_interfaces_init ( interface_ctrl_type * ptr )
{
FILE * file_ptr;
char line_buf[MAX_CHARS_ON_LINE];
string str;
string physical_interface = "";
/* iface enum to pltform.conf iface name */
if ( strcmp(ptr->name, MGMT_INTERFACE_NAME) == 0 )
str = MGMT_INTERFACE_FULLNAME;
else if ( strcmp(ptr->name, INFRA_INTERFACE_NAME) == 0 )
str = INFRA_INTERFACE_FULLNAME;
else if ( strcmp(ptr->name, OAM_INTERFACE_NAME) == 0 )
str = OAM_INTERFACE_FULLNAME;
else
{
slog ("%s is an unsupported iface\n", ptr->name );
return (FAIL_BAD_PARM);
}
/* open platform.conf and find the line containing this interface name. */
file_ptr = fopen (PLATFORM_DIR , "r");
if (file_ptr)
{
ifstream fin( PLATFORM_DIR );
string line;
while ( getline( fin, line ))
{
/* does this line contain it ? */
if ( line.find(str) != string::npos )
{
stringstream ss( line );
getline( ss, physical_interface, '=' ); // string before
getline( ss, physical_interface, '=' ); // string after
plog ("%s is the %s primary network interface",
physical_interface.c_str(),
ptr->name);
/* determine the interface type */
string uevent_interface_file =
INTERFACES_DIR + physical_interface + "/uevent";
ifstream finUevent( uevent_interface_file.data() );
if (!finUevent)
{
elog ("Cannot find '%s' ; unable to monitor '%s' interface\n",
uevent_interface_file.c_str(), ptr->name );
ptr->used = false;
fclose(file_ptr);
return FAIL_OPERATION ;
}
else
{
string line;
ptr->type_enum = ethernet;
while( getline( finUevent, line ) )
{
if ( line.find ("DEVTYPE") == 0 )
{
if ( line.find ("=vlan") != string::npos )
ptr->type_enum = vlan;
else if ( line.find ("=bond") != string::npos )
ptr->type_enum = bond;
break;
}
}
}
switch (ptr->type_enum)
{
case ethernet:
{
memcpy(ptr->interface_one,
physical_interface.c_str(),
physical_interface.size());
ilog("%s is a %s ethernet interface\n",
ptr->interface_one, ptr->name );
break;
}
case bond:
{
memcpy(ptr->bond,
physical_interface.c_str(),
physical_interface.size());
ilog("%s is a bonded %s network interface\n",
ptr->bond, ptr->name);
break;
}
case vlan:
{
/****************************************************
*
* If it is a VLAN interface, we need to determine its
* parent interface, which may be a single ethernet
* link or a bonded interface.
*
****************************************************/
string parent = get_iflink_interface(physical_interface);
if (!parent.empty())
{
string physical_interface_save = physical_interface ;
physical_interface = parent;
string uevent_parent_file =
INTERFACES_DIR + parent + "/uevent";
ifstream finUevent2( uevent_parent_file.c_str() );
string line;
bool bond_configured = false;
while( getline( finUevent2, line ) )
{
// if this uevent does not have a DEVTYPE
// then its a ethernet interface. If this
// does have a DEVTYPE then check explicity
// for bond. Since we don't allow vlan over
// vlan, for all other DEVTYPEs, assume
// this is a ethernet interface.
if ( (line.find ("DEVTYPE") == 0) &&
(line.find ("=bond") != string::npos) ) {
ilog("%s is a vlan off the %s network whose parent is %s\n",
physical_interface_save.c_str(),
ptr->name,
parent.c_str());
bond_configured = true;
break;
}
}
if (!bond_configured)
{
ilog("%s is a vlan off the %s network whose parent is %s\n",
physical_interface.c_str(),
ptr->name,
parent.c_str());
memcpy(ptr->interface_one,
parent.c_str(),
parent.size());
}
}
else
{
ilog("%s is a vlan %s network\n",
physical_interface.c_str(), ptr->name);
}
break;
}
} // end of switch
break;
}
}
fclose(file_ptr);
}
/* Lagged interface */
if ((ptr->interface_one[0] == '\0') && (!physical_interface.empty()))
{
string lagged_interface_file =
INTERFACES_DIR + physical_interface + "/bonding/slaves";
ifstream finTwo( lagged_interface_file.c_str() );
if (!finTwo)
{
elog ("Cannot find bond interface file (%s) to "
"resolve slave interfaces\n", lagged_interface_file.c_str());
ptr->used = false ;
return (FAIL_OPERATION);
}
else
{
string line;
while ( getline( finTwo, line ) )
{
strncpy(line_buf, line.c_str(), MAX_CHARS_ON_LINE);
// the slave interfaces are listed as enXYYY enXYYY...
// starting with the primary. Read all other slaves
// as interface_two
sscanf(line_buf, "%19s %19s", ptr->interface_one, ptr->interface_two);
ilog("%s and %s are %s network aggregated interfaces\n",
ptr->interface_one,
ptr->interface_two,
ptr->name);
break;
}
}
}
if ( ptr->interface_one[0] == '\0' )
{
ptr->used = false;
}
else
{
ptr->used = true;
if ( ptr->interface_two[0] == '\0' )
{
/* this is not a lagged interface */
ptr->lagged = false;
}
else
{
/* this is a lagged interface */
ptr->lagged = true;
}
}
return (PASS);
}

View File

@ -0,0 +1,83 @@
#! /bin/sh
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
#
# chkconfig: 2345 95 95
#
### BEGIN INIT INFO
# Provides: lmon
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Link Monitor daemon
### END INIT INFO
. /etc/init.d/functions
DAEMON_NAME="lmond"
DAEMON="/usr/local/bin/${DAEMON_NAME}"
IFACE=""
if [ ! -e "$DAEMON" ] ; then
logger "$DAEMON is missing"
exit 1
fi
RETVAL=0
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
export PATH
case "$1" in
start)
echo -n "Starting $DAEMON_NAME: "
# Prevent multiple starts
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
echo "OK"
exit $RETVAL
fi
start-stop-daemon --start -b -x ${DAEMON} --
RETVAL=$?
if [ $RETVAL -eq 0 ] ; then
echo "OK"
else
echo "FAIL"
fi
;;
stop)
echo -n "Stopping ${DAEMON_NAME}: "
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
killproc ${DAEMON_NAME}
fi
echo "OK"
;;
restart)
$0 stop
$0 start
;;
status)
pid=`pidof ${DAEMON_NAME}`
RETVAL=$?
if [ ${RETVAL} -eq 0 ] ; then
echo "${DAEMON_NAME} is running"
else
echo "${DAEMON_NAME} is NOT running"
fi
;;
condrestart)
[ -f /var/lock/subsys/${DAEMON_NAME} ] && $0 restart
;;
*)
echo "usage: $0 { start | stop | status | restart | condrestart | status }"
;;
esac
exit $RETVAL

View File

@ -0,0 +1,16 @@
#daily
nodateext
/var/log/lmond.log
{
nodateext
size 10M
start 1
missingok
rotate 20
compress
sharedscripts
postrotate
systemctl reload syslog-ng > /dev/null 2>&1 || true
endscript
}

View File

@ -0,0 +1,16 @@
[process]
process = lmond
service = lmon
pidfile = /var/run/lmond.pid
style = lsb ; ocf or lsb
severity = major ; minor, major, critical
restarts = 3 ; restart retries before error assertion
interval = 5 ; number of seconds to wait between restarts
debounce = 20 ; number of seconds that a process needs to remain
; running before degrade is removed and retry count
; is cleared.
startuptime = 5 ; Seconds to wait after process start before starting the debounce monitor
mode = passive ; Monitoring mode: passive (default) or active
; passive: process death monitoring (default: always)
; active : heartbeat monitoring, i.e. request / response messaging
; ignore : do not monitor or stop monitoring

View File

@ -0,0 +1,17 @@
[Unit]
Description=Starling-X Maintenance Link Monitor
After=config.service
After=syslog-ng.service
Before=pmon.service
[Service]
Type=forking
ExecStart=/etc/rc.d/init.d/lmon start
ExecStop=/etc/rc.d/init.d/lmon stop
ExecReload=/etc/rc.d/init.d/lmon reload
PIDFile=/var/run/lmond.pid
KillMode=process
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,19 @@
; Link Monitor Configuration File
[client] ; Client configuration
audit_period = 60 ; seconds between process audits
lmon_query_port = 2122 ; port that responds to link query requests
daemon_log_port = 2121 ; daemon logger port
uri_path = /mtce/lmon ; maintenance service path http://<ip>:<port><uri_path>
[defaults]
[timeouts]
[features]
[debug] ; SIGHUP to reload
debug_timer = 0 ; enable(1) or disable(0) timer logs (tlog)
debug_json = 0 ; enable(1) or disable(0) message logs (jlog)
debug_state = 0 ; enable(1) or disable(0) state change logs (clog)
debug_level = 0 ; decimal mask 0..15 (8,4,2,1)
debug_all = 0 ; set all debug labels to the specified value

View File

@ -663,7 +663,7 @@ int rmon_hdlr_init ( rmon_ctrl_type * ctrl_ptr )
_thinmeta_config_load();
_config_files_load ();
_inter_config_load ();
// _inter_config_load ();
/* init Thin Metadata Monitoring after config reload - including timers */
thinmeta_init(thinmeta_resource_config, thinmetatimer, ctrl_ptr->thinmeta_resources);