From 7941ee5bbbaf472ef62d485342297a0198a46bfb Mon Sep 17 00:00:00 2001 From: Eric MacDonald Date: Fri, 25 Jan 2019 14:47:47 -0500 Subject: [PATCH] Add new Link Monitor (lmond) daemon to Mtce This update introduces a new Link Monitor daemon to the Mtce flock of daemons and disable rmon's interface monitoring. This new daemon parses the platform.conf file and using the interface names assigned to each monitored network (mgmt, infra and oam) queries the kernel for their physical, bonded and vlan interface names and then registers to listen for netlink events. All link/interface state change (netlink) events that correspond to any of the interfaces or links assiciated with the monitored networks are tracked by this new daemon. This new daemon then also implements an http listener for localhost initiated GET requests targeted to /mtce/lmond on port 2122 and responds with a json link_info string that contains a summary of monitored networks, links and their current Up/Down status. lmond behavioral summary: 1. learn interface/port model, 2. load initial link status for learned links, 3. listen for link status change events 4. provide link status info to http GET Query requests. Another update to stx-integ implements the collectd interface plugin that periodically issues the Link Status GET requests for the purponse of alarming port and interface Down conditions, clearing alarms on Up state changes, and storing sample data that represents the percentage of active links for each monitored network. Test Plan: PASS: Verify lmond process startup PASS: Verify lmond logging and log rotation PASS: Verify lmond process monitoring by pmon PASS: Verify lmond interface learning on process startup PASS: Verify lmond port learning on process startup PASS: Verify lmond handling of vlan and bond interface types PASS: Verify lmond http link info GET Query handling PASS: Verify lmond has no memory leak during normal and eventfull operation Change-Id: I58915644e60f31e3a12c3b451399c4f76ec2ea37 Story: 2002823 Task: 28635 Depends-On: Signed-off-by: Eric MacDonald --- centos_iso_image.inc | 1 + mtce-common/src/common/httpUtil.cpp | 156 +++++ mtce-common/src/common/httpUtil.h | 15 + mtce-common/src/common/logMacros.h | 7 +- mtce-common/src/common/nodeUtil.cpp | 38 +- mtce-common/src/common/nodeUtil.h | 2 +- mtce-common/src/daemon/daemon_config.cpp | 2 + mtce/centos/build_srpm.data | 2 +- mtce/centos/mtce.spec | 67 +- mtce/src/Makefile | 2 + mtce/src/lmon/Makefile | 35 ++ mtce/src/lmon/lmon.h | 119 ++++ mtce/src/lmon/lmonHdlr.cpp | 769 +++++++++++++++++++++++ mtce/src/lmon/lmonInit.cpp | 145 +++++ mtce/src/lmon/lmonUtil.cpp | 415 ++++++++++++ mtce/src/lmon/scripts/lmon | 83 +++ mtce/src/lmon/scripts/lmon.logrotate | 16 + mtce/src/lmon/scripts/lmon.pmon.conf | 16 + mtce/src/lmon/scripts/lmon.service | 17 + mtce/src/lmon/scripts/lmond.conf | 19 + mtce/src/rmon/rmonHdlr.cpp | 2 +- 21 files changed, 1886 insertions(+), 42 deletions(-) create mode 100755 mtce/src/lmon/Makefile create mode 100644 mtce/src/lmon/lmon.h create mode 100644 mtce/src/lmon/lmonHdlr.cpp create mode 100644 mtce/src/lmon/lmonInit.cpp create mode 100644 mtce/src/lmon/lmonUtil.cpp create mode 100644 mtce/src/lmon/scripts/lmon create mode 100644 mtce/src/lmon/scripts/lmon.logrotate create mode 100644 mtce/src/lmon/scripts/lmon.pmon.conf create mode 100644 mtce/src/lmon/scripts/lmon.service create mode 100644 mtce/src/lmon/scripts/lmond.conf diff --git a/centos_iso_image.inc b/centos_iso_image.inc index d607d55b..018e0631 100644 --- a/centos_iso_image.inc +++ b/centos_iso_image.inc @@ -8,6 +8,7 @@ mtce-pmon mtce-rmon mtce-hwmon mtce-hostw +mtce-lmon # mtce-compute mtce-compute diff --git a/mtce-common/src/common/httpUtil.cpp b/mtce-common/src/common/httpUtil.cpp index 534125c1..d263971c 100644 --- a/mtce-common/src/common/httpUtil.cpp +++ b/mtce-common/src/common/httpUtil.cpp @@ -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 ); + } +} + diff --git a/mtce-common/src/common/httpUtil.h b/mtce-common/src/common/httpUtil.h index f108e2b3..d846d29c 100644 --- a/mtce-common/src/common/httpUtil.h +++ b/mtce-common/src/common/httpUtil.h @@ -12,6 +12,7 @@ #include /* for ... http libevent client */ #include #include +#include /* 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__ */ diff --git a/mtce-common/src/common/logMacros.h b/mtce-common/src/common/logMacros.h index 55a72496..f8720c97 100644 --- a/mtce-common/src/common/logMacros.h +++ b/mtce-common/src/common/logMacros.h @@ -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/ */ - char* sysinv_mtc_inv_label ; /**< =/v1/hosts/ */ int sysinv_api_port ; /**< =6385 */ char* sysinv_api_bind_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 */ diff --git a/mtce-common/src/common/nodeUtil.cpp b/mtce-common/src/common/nodeUtil.cpp index 1b282e8c..9aa30dc9 100755 --- a/mtce-common/src/common/nodeUtil.cpp +++ b/mtce-common/src/common/nodeUtil.cpp @@ -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] ; diff --git a/mtce-common/src/common/nodeUtil.h b/mtce-common/src/common/nodeUtil.h index 2c46100f..712a7251 100755 --- a/mtce-common/src/common/nodeUtil.h +++ b/mtce-common/src/common/nodeUtil.h @@ -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); diff --git a/mtce-common/src/daemon/daemon_config.cpp b/mtce-common/src/daemon/daemon_config.cpp index e92c6771..e11212c1 100644 --- a/mtce-common/src/daemon/daemon_config.cpp +++ b/mtce-common/src/daemon/daemon_config.cpp @@ -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 );} diff --git a/mtce/centos/build_srpm.data b/mtce/centos/build_srpm.data index 8cf0e480..5b13b5ad 100644 --- a/mtce/centos/build_srpm.data +++ b/mtce/centos/build_srpm.data @@ -1,3 +1,3 @@ SRC_DIR="src" -TIS_PATCH_VER=145 +TIS_PATCH_VER=146 BUILD_IS_SLOW=5 diff --git a/mtce/centos/mtce.spec b/mtce/centos/mtce.spec index b86dd00e..bf79a421 100644 --- a/mtce/centos/mtce.spec +++ b/mtce/centos/mtce.spec @@ -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 ############################### diff --git a/mtce/src/Makefile b/mtce/src/Makefile index e4587181..68db5444 100755 --- a/mtce/src/Makefile +++ b/mtce/src/Makefile @@ -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 ) diff --git a/mtce/src/lmon/Makefile b/mtce/src/lmon/Makefile new file mode 100755 index 00000000..2681097d --- /dev/null +++ b/mtce/src/lmon/Makefile @@ -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 diff --git a/mtce/src/lmon/lmon.h b/mtce/src/lmon/lmon.h new file mode 100644 index 00000000..4721f0e8 --- /dev/null +++ b/mtce/src/lmon/lmon.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2019 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include /* 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 ); diff --git a/mtce/src/lmon/lmonHdlr.cpp b/mtce/src/lmon/lmonHdlr.cpp new file mode 100644 index 00000000..9dec02e7 --- /dev/null +++ b/mtce/src/lmon/lmonHdlr.cpp @@ -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 /* 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 links_gone_down ; + list links_gone_up ; + list::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 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(); +} + + + + diff --git a/mtce/src/lmon/lmonInit.cpp b/mtce/src/lmon/lmonInit.cpp new file mode 100644 index 00000000..cdb771b2 --- /dev/null +++ b/mtce/src/lmon/lmonInit.cpp @@ -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); +} diff --git a/mtce/src/lmon/lmonUtil.cpp b/mtce/src/lmon/lmonUtil.cpp new file mode 100644 index 00000000..ea3509c8 --- /dev/null +++ b/mtce/src/lmon/lmonUtil.cpp @@ -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 /* for ... ifstream */ +#include /* for ... stringstream */ +#include /* for ... if_indextoname , IF_NAMESIZE */ +#include /* 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); +} + + + diff --git a/mtce/src/lmon/scripts/lmon b/mtce/src/lmon/scripts/lmon new file mode 100644 index 00000000..e55dac51 --- /dev/null +++ b/mtce/src/lmon/scripts/lmon @@ -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 diff --git a/mtce/src/lmon/scripts/lmon.logrotate b/mtce/src/lmon/scripts/lmon.logrotate new file mode 100644 index 00000000..b59fa9ff --- /dev/null +++ b/mtce/src/lmon/scripts/lmon.logrotate @@ -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 +} diff --git a/mtce/src/lmon/scripts/lmon.pmon.conf b/mtce/src/lmon/scripts/lmon.pmon.conf new file mode 100644 index 00000000..a62e9b52 --- /dev/null +++ b/mtce/src/lmon/scripts/lmon.pmon.conf @@ -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 diff --git a/mtce/src/lmon/scripts/lmon.service b/mtce/src/lmon/scripts/lmon.service new file mode 100644 index 00000000..84b14d46 --- /dev/null +++ b/mtce/src/lmon/scripts/lmon.service @@ -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 diff --git a/mtce/src/lmon/scripts/lmond.conf b/mtce/src/lmon/scripts/lmond.conf new file mode 100644 index 00000000..a99609ac --- /dev/null +++ b/mtce/src/lmon/scripts/lmond.conf @@ -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://: + +[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 diff --git a/mtce/src/rmon/rmonHdlr.cpp b/mtce/src/rmon/rmonHdlr.cpp index e4ae793f..42669567 100644 --- a/mtce/src/rmon/rmonHdlr.cpp +++ b/mtce/src/rmon/rmonHdlr.cpp @@ -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);