ha/service-mgmt/sm-common-1.0.0/src/sm_eru_db.c

619 lines
22 KiB
C

//
// Copyright (c) 2014-2017 Wind River Systems, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
#include "sm_eru_db.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <sched.h>
#include <pthread.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include "sm_limits.h"
#include "sm_types.h"
#include "sm_debug.h"
#define SM_ERU_DB_FILENAME "/var/lib/sm/sm.eru.v1"
#define SM_ERU_DB_MMAP_INITIALIZED 0xA5A5A5A5
#define SM_ERU_DB_MAX_RECORDS 4194304
#define SM_ERU_DB_HEADER_SIZE 8
typedef struct
{
bool initialized;
bool read_only;
int fd;
FILE* fp;
off_t file_size;
} SmEruDBFileInfoT;
typedef struct
{
int write_index;
bool wrapped;
} SmEruDatabaseHeaderT;
static SmEruDBFileInfoT _file_info;
static SmEruDatabaseHeaderT _file_header;
static uint32_t _1MB_data_block[1048576/sizeof(uint32_t)];
// ****************************************************************************
// Event Recorder Unit Database - Read Lock
// ========================================
static SmErrorT sm_eru_db_read_lock( void )
{
struct flock lock;
int result;
memset( &lock, 0, sizeof(lock) );
lock.l_type = F_RDLCK;
int retry_i;
for( retry_i=0; 10 > retry_i; ++retry_i )
{
result = fcntl( _file_info.fd, F_SETLK, &lock );
if( 0 == result )
{
return( SM_OKAY );
}
usleep( 50000 ); // 50 milliseconds.
}
return( SM_FAILED );
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Write Lock
// =========================================
static SmErrorT sm_eru_db_write_lock( void )
{
struct flock lock;
int result;
memset( &lock, 0, sizeof(lock) );
lock.l_type = F_WRLCK;
int retry_i;
for( retry_i=0; 10 > retry_i; ++retry_i )
{
result = fcntl( _file_info.fd, F_SETLK, &lock );
if( 0 == result )
{
return( SM_OKAY );
}
usleep( 50000 ); // 50 milliseconds.
}
return( SM_FAILED );
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Unlock
// =====================================
static void sm_eru_db_unlock( void )
{
struct flock lock;
int result;
memset( &lock, 0, sizeof(lock) );
lock.l_type = F_UNLCK;
int retry_i;
for( retry_i=0; 10 > retry_i; ++retry_i )
{
result = fcntl( _file_info.fd, F_SETLK, &lock );
if( 0 == result )
{
return;
}
usleep( 50000 ); // 50 milliseconds.
}
abort();
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Total
// ====================================
int sm_eru_db_total( void )
{
if( !_file_info.initialized )
{
DPRINTFE( "Database is not initialized." );
return( 0 );
}
if( _file_header.wrapped )
{
return( SM_ERU_DB_MAX_RECORDS );
}
return( _file_header.write_index );
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Get Write Index
// ==============================================
int sm_eru_db_get_write_index( void )
{
if( !_file_info.initialized )
{
DPRINTFE( "Database is not initialized." );
return( -1 );
}
return( _file_header.write_index );
}
// ****************************************************************************
// Event Recorder Unit Database - Flush the database
// =================================================
void sm_eru_db_sync( void )
{
if( _file_info.fp != NULL )
{
fflush( _file_info.fp );
fsync(fileno(_file_info.fp));
}
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Read
// ===================================
SmErrorT sm_eru_db_read( int read_index, SmEruDatabaseEntryT* entry )
{
SmErrorT error;
if( !_file_info.initialized )
{
DPRINTFE( "Database is not initialized." );
return( SM_NOT_FOUND );
}
if(( 0 > read_index )&&( SM_ERU_DB_MAX_RECORDS <= read_index ))
{
DPRINTFE( "Database read index (%i) is invalid.", read_index );
return( SM_FAILED );
}
error = sm_eru_db_read_lock();
if( SM_OKAY != error )
{
DPRINTFE( "Failed to get eru database read lock, error=%s.",
sm_error_str(error) );
return( error );
}
fseek(_file_info.fp, (read_index*sizeof(SmEruDatabaseEntryT))+SM_ERU_DB_HEADER_SIZE, SEEK_SET);
fread(entry, 1, sizeof(SmEruDatabaseEntryT), _file_info.fp);
sm_eru_db_unlock();
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Write
// ====================================
SmErrorT sm_eru_db_write( SmEruDatabaseEntryT* entry )
{
SmErrorT error;
if( !_file_info.initialized )
{
DPRINTFE( "Database is not initialized." );
return( SM_FAILED );
}
error = sm_eru_db_write_lock();
if( SM_OKAY != error )
{
DPRINTFE( "Failed to get eru database write lock, error=%s.",
sm_error_str(error) );
return( error );
}
clock_gettime( CLOCK_REALTIME, &(entry->ts_real) );
entry->index = _file_header.write_index;
fseek(_file_info.fp, (_file_header.write_index*sizeof(SmEruDatabaseEntryT))+SM_ERU_DB_HEADER_SIZE, SEEK_SET);
size_t written = fwrite(entry, 1, sizeof(SmEruDatabaseEntryT), _file_info.fp);
if( 0 > written )
{
DPRINTFE( "Failed to write , error=%s.", strerror(errno) );
sm_eru_db_unlock();
return( SM_FAILED );
}
if( written != sizeof(SmEruDatabaseEntryT))
{
DPRINTFE( "Failed to write, %lu bytes should of been written instead of %lu", sizeof(SmEruDatabaseEntryT), written );
sm_eru_db_unlock();
return( SM_FAILED );
}
++(_file_header.write_index);
if( SM_ERU_DB_MAX_RECORDS <= _file_header.write_index )
{
DPRINTFD( "Database wrapped." );
_file_header.wrapped = true;
_file_header.write_index = 0;
}
// The first 8 bytes of the database contains the write index and the wrapped flag
unsigned char buffer[SM_ERU_DB_HEADER_SIZE];
memset( &buffer, 0, SM_ERU_DB_HEADER_SIZE);
memcpy( buffer, &_file_header.write_index, sizeof(int));
memcpy( buffer+sizeof(int), &_file_header.wrapped, sizeof(bool));
fseek(_file_info.fp, 0, SEEK_SET);
fwrite(buffer, 1, SM_ERU_DB_HEADER_SIZE, _file_info.fp);
sm_eru_db_unlock();
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Display
// ======================================
void sm_eru_db_display( SmEruDatabaseEntryT* entry, bool want_raw )
{
char time_str[80];
char date_str[32];
char addr_type_str[32];
struct tm t_real;
unsigned long long user_time;
unsigned long long nice_time;
unsigned long long total_time;
long double user, nice, sys, idle, iowait, irq, soft_irq, steal;
long double guest, guest_nice;
char ip_str[SM_NETWORK_ADDRESS_MAX_CHAR];
SmNodeCpuStatsT* cpu = &(entry->u.cpu_stats);
SmNodeMemStatsT* mem = &(entry->u.mem_stats);
SmNodeDiskStatsT* disk = &(entry->u.disk_stats);
SmNodeNetDevStatsT* net = &(entry->u.net_stats);
SmHwQdiscInfoT* qdisc = &(entry->u.tc_stats);
SmHwInterfaceChangeDataT* if_change = &(entry->u.if_change);
SmHwIpChangeDataT* ip_change = &(entry->u.ip_change);
if( NULL == localtime_r( &(entry->ts_real.tv_sec), &t_real ) )
{
snprintf( time_str, sizeof(time_str), "YYYY:MM:DD HH:MM:SS.xxx" );
} else {
strftime( date_str, sizeof(date_str), "%FT%T", &t_real );
snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str,
entry->ts_real.tv_nsec/1000000 );
}
printf( "%10i. %s " , entry->index, time_str );
switch( entry->type )
{
case SM_ERU_DATABASE_ENTRY_TYPE_CPU_STATS:
user_time = cpu->user_cpu_usage - cpu->guest_cpu_usage;
nice_time = cpu->nice_cpu_usage - cpu->guest_nice_cpu_usage;
total_time = user_time + nice_time + cpu->idle_task_cpu_usage
+ cpu->iowait_cpu_usage + cpu->system_cpu_usage
+ cpu->irq_cpu_usage + cpu->soft_irq_cpu_usage
+ cpu->steal_cpu_usage + cpu->guest_cpu_usage
+ cpu->guest_nice_cpu_usage;
if( 0 != total_time )
{
user = (long double)user_time
/(long double)total_time * 100.0;
nice = (long double)nice_time
/(long double)total_time * 100.0;
sys = (long double)cpu->system_cpu_usage
/(long double)total_time * 100.0;
idle = (long double)cpu->idle_task_cpu_usage
/(long double)total_time * 100.0;
iowait = (long double)cpu->iowait_cpu_usage
/(long double)total_time * 100.0;
irq = (long double)cpu->irq_cpu_usage
/(long double)total_time * 100.0;
soft_irq = (long double)cpu->soft_irq_cpu_usage
/(long double)total_time * 100.0;
steal = (long double)cpu->steal_cpu_usage
/(long double)total_time * 100.0;
guest = (long double)cpu->guest_cpu_usage
/(long double)total_time * 100.0;
guest_nice = (long double)cpu->guest_nice_cpu_usage
/(long double)total_time * 100.0;
printf( "cpu-stats: %s user: %5.1Lf nice: %5.1Lf sys: %5.1Lf"
" idle: %5.1Lf iowait: %5.1Lf irq: %5.1Lf"
" soft-irq: %5.1Lf steal: %5.1Lf guest-cpu: %5.1Lf"
" guest-nice: %5.1Lf total-interrupts: %llu"
" total-context-switches: %llu"
" total-processes: %llu processes_running: %llu"
" processes_blocked: %llu boot_time_in_secs: %llu\n",
cpu->cpu_name, user, nice, sys, idle, iowait, irq,
soft_irq, steal, guest, guest_nice,
cpu->total_interrupts, cpu->total_context_switches,
cpu->total_processes, cpu->processes_running,
cpu->processes_blocked, cpu->boot_time_in_secs );
} else {
want_raw = true;
}
if( want_raw )
{
printf( "cpu-raw-stats: %s user: %llu nice: %llu sys: %llu"
" idle: %llu iowait: %llu irq: %llu soft-irq: %llu"
" steal: %llu guest-cpu: %llu guest-nice: %llu"
" total-interrupts: %llu total-context-switches: %llu"
" total-processes: %llu processes_running: %llu"
" processes_blocked: %llu boot_time_in_secs: %llu\n",
cpu->cpu_name, cpu->user_cpu_usage, cpu->nice_cpu_usage,
cpu->system_cpu_usage, cpu->idle_task_cpu_usage,
cpu->iowait_cpu_usage, cpu->irq_cpu_usage,
cpu->soft_irq_cpu_usage, cpu->steal_cpu_usage,
cpu->guest_cpu_usage, cpu->guest_nice_cpu_usage,
cpu->total_interrupts, cpu->total_context_switches,
cpu->total_processes, cpu->processes_running,
cpu->processes_blocked, cpu->boot_time_in_secs );
}
break;
case SM_ERU_DATABASE_ENTRY_TYPE_MEM_STATS:
printf( "mem-stats: total: %lu free: %lu buffers: %lu"
" cached: %lu swap-cached: %lu swap-total: %lu"
" swap-free: %lu active: %lu inactive: %lu"
" dirty: %lu hugepages-total: %lu"
" hugepages-free: %lu hugepage-size: %lu"
" nfs-uncommited: %lu commited: %lu\n",
mem->total_memory_kB, mem->free_memory_kB,
mem->buffers_kB, mem->cached_kB, mem->swap_cached_kB,
mem->swap_total_kB, mem->swap_free_kB, mem->active_kB,
mem->inactive_kB, mem->dirty_kB, mem->hugepages_total,
mem->hugepages_free, mem->hugepage_size_kB,
mem->nfs_uncommited_kB, mem->commited_memory_kB );
break;
case SM_ERU_DATABASE_ENTRY_TYPE_DISK_STATS:
printf( "disk-stats: %s major: %i minor: %i"
" reads-completed: %lu reads-merged: %lu"
" sectors-read: %lu ms-spent-reading: %lu"
" writes-completed: %lu writes-merged: %lu"
" sectors-written: %lu ms-spent-writing: %lu"
" io-inprogress: %lu ms-spent-io: %lu"
" weighted-ms-spent-io: %lu\n", disk->dev_name,
disk->major_num, disk->minor_num, disk->reads_completed,
disk->reads_merged, disk->sectors_read,
disk->ms_spent_reading, disk->writes_completed,
disk->writes_merged, disk->sectors_written,
disk->ms_spent_writing, disk->io_inprogress,
disk->ms_spent_io, disk->weighted_ms_spent_io );
break;
case SM_ERU_DATABASE_ENTRY_TYPE_NET_STATS:
printf( "net-stats: %s rx-bytes: %llu rx-packets: %llu"
" rx-errors: %llu rx-dropped: %llu rx-fifo-errors: %llu"
" rx-frame-errors: %llu rx-compressed-packets: %llu"
" rx-multicast-frames: %llu tx-bytes: %llu"
" tx-packets: %llu tx-errors: %llu tx-dropped: %llu"
" tx-fifo-errors: %llu tx-collisions: %llu"
" tx-carrier-loss: %llu tx-compressed-packets: %llu\n",
net->dev_name, net->rx_bytes, net->rx_packets,
net->rx_errors, net->rx_dropped, net->rx_fifo_errors,
net->rx_frame_errors, net->rx_compressed_packets,
net->rx_multicast_frames, net->tx_bytes, net->tx_packets,
net->tx_errors, net->tx_dropped, net->tx_fifo_errors,
net->tx_collisions, net->tx_carrier_loss,
net->tx_compressed_packets );
break;
case SM_ERU_DATABASE_ENTRY_TYPE_TC_STATS:
printf( "tc-stats: %s %s %s bytes: %" PRIu64 " packets: %" PRIu64
" qlen: %" PRIu64 " backlog: %" PRIu64 " drops: %" PRIu64
" requeues: %" PRIu64 " overlimits: %" PRIu64 "\n",
qdisc->interface_name, qdisc->queue_type,
qdisc->handle, qdisc->bytes, qdisc->packets,
qdisc->q_length, qdisc->backlog, qdisc->drops,
qdisc->requeues, qdisc->overlimits );
break;
case SM_ERU_DATABASE_ENTRY_TYPE_IF_CHANGE:
printf( "if-change: %s type: %s state: %s\n",
if_change->interface_name,
(SM_HW_INTERFACE_CHANGE_TYPE_ADD == if_change->type)
? "add" : "delete",
sm_interface_state_str(if_change->interface_state) );
break;
case SM_ERU_DATABASE_ENTRY_TYPE_IP_CHANGE:
sm_network_address_str( &(ip_change->address), ip_str );
if( SM_HW_ADDRESS_TYPE_ADDRESS == ip_change->address_type )
{
snprintf( addr_type_str, sizeof(addr_type_str), "address" );
} else if( SM_HW_ADDRESS_TYPE_LOCAL == ip_change->address_type ){
snprintf( addr_type_str, sizeof(addr_type_str), "local" );
} else if( SM_HW_ADDRESS_TYPE_BROADCAST == ip_change->address_type ){
snprintf( addr_type_str, sizeof(addr_type_str), "broadcast" );
} else if( SM_HW_ADDRESS_TYPE_ANYCAST == ip_change->address_type ){
snprintf( addr_type_str, sizeof(addr_type_str), "anycast" );
} else {
snprintf( addr_type_str, sizeof(addr_type_str), "unknown" );
}
printf( "ip-change: %s type: %s address: %s/%i address-type=%s\n",
ip_change->interface_name,
(SM_HW_IP_CHANGE_TYPE_ADD == ip_change->type)
? "add" : "delete", ip_str, ip_change->prefix_len,
addr_type_str );
break;
default:
DPRINTFE( "Unknown entry type (%i).", entry->type );
break;
}
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Initialize
// =========================================
SmErrorT sm_eru_db_initialize( char* filename, bool read_only )
{
char db_filename[512] = "";
struct stat stat_info;
int result;
_file_info.initialized = false;
_file_info.fp = NULL;
_file_header.wrapped = false;
_file_header.write_index = 0;
if( NULL == filename )
{
snprintf( db_filename, sizeof(db_filename), "%s", SM_ERU_DB_FILENAME );
} else {
snprintf( db_filename, sizeof(db_filename), "%s", filename );
}
DPRINTFD( "ERU Database Entry size is %i, total_records=%i.",
(int) sizeof(SmEruDatabaseEntryT), SM_ERU_DB_MAX_RECORDS );
if( read_only )
{
_file_info.fp = fopen (db_filename, "r");
} else {
_file_info.fp = fopen (db_filename, "r+");
if (_file_info.fp == NULL)
{
// File does not exist, open for write with file creation
_file_info.fp = fopen (db_filename, "w+");
}
}
if( _file_info.fp == NULL )
{
DPRINTFE( "Failed to open database file (%s), error=%s.", db_filename,
strerror( errno ) );
return( SM_FAILED );
}
_file_info.fd = fileno(_file_info.fp);
result = fstat( _file_info.fd, &stat_info );
if( 0 > result )
{
DPRINTFE( "Failed to get database file stats, error=%s.",
strerror(errno) );
sm_eru_db_finalize();
return( SM_FAILED );
}
int max_db_size = (sizeof(SmEruDatabaseEntryT) * SM_ERU_DB_MAX_RECORDS ) + SM_ERU_DB_HEADER_SIZE;
if( (int) stat_info.st_size < max_db_size )
{
if( read_only )
{
DPRINTFE( "Database is not sized correctly, expected=%i, "
"actual=%i.", max_db_size, (int) stat_info.st_size );
sm_eru_db_finalize();
return( SM_FAILED );
} else {
int num_blocks;
DPRINTFI( "Initializing database." );
num_blocks = max_db_size / sizeof(_1MB_data_block) + 1;
memset( _1MB_data_block, 0, sizeof(_1MB_data_block) );
int block_i;
for( block_i=0; block_i < num_blocks; ++block_i )
{
write( _file_info.fd, (void*) _1MB_data_block,
sizeof(_1MB_data_block) );
}
result = fstat( _file_info.fd, &stat_info );
if( 0 > result )
{
DPRINTFE( "Failed to get database file statistics, error=%s.",
strerror(errno) );
sm_eru_db_finalize();
return( SM_FAILED );
}
if( (int) stat_info.st_size < (max_db_size) )
{
DPRINTFE( "Failed to create database, size=%d.",
(int) stat_info.st_size );
sm_eru_db_finalize();
return( SM_FAILED );
}
_file_info.file_size = stat_info.st_size;
}
} else {
_file_info.file_size = stat_info.st_size;
}
_file_info.read_only = read_only;
_file_info.initialized = true;
// Read write index and wrapper flag
unsigned char buffer[SM_ERU_DB_HEADER_SIZE];
int bytes_read = fread(buffer, 1, SM_ERU_DB_HEADER_SIZE, _file_info.fp);
if (bytes_read == SM_ERU_DB_HEADER_SIZE)
{
memcpy(&_file_header.write_index, buffer, sizeof(int));
memcpy(&_file_header.wrapped, buffer+sizeof(int), sizeof(bool));
}
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Event Recorder Unit Database - Finalize
// =======================================
SmErrorT sm_eru_db_finalize( void )
{
_file_info.initialized = false;
if( _file_info.fp != NULL )
{
sm_eru_db_sync();
fclose(_file_info.fp);
}
return( SM_OKAY );
}
// ****************************************************************************