metal/mtce/src/lmon/lmonUtil.cpp

468 lines
14 KiB
C++

/*
* 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 cluster-host) to a physical port.
* See interface_type enum in lmon.h
*
*****************************************************************************/
int lmon_interfaces_init ( interface_ctrl_type * ptr, string physical_interface )
{
char line_buf[MAX_CHARS_ON_LINE];
/* 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;
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;
}
}
/* 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 ) )
{
snprintf(line_buf, sizeof(line_buf), "%s", line.c_str());
// 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);
}
void set_the_link_state( int ioctl_socket, interface_ctrl_type * ptr ){
/* set the link state for all the primary physical interfaces */
if ( lmon_get_link_state ( ioctl_socket,
ptr->interface_one,
ptr->interface_one_link_up ) )
{
ptr->interface_one_event_time = lmon_fm_timestamp();
ptr->interface_one_link_up = false ;
wlog ("%s interface state query failed ; defaulting to Down\n",
ptr->interface_one) ;
}
else
{
ptr->interface_one_event_time = lmon_fm_timestamp();
ilog ("%s is %s\n",
ptr->interface_one,
ptr->interface_one_link_up ?
"Up" : "Down" );
if ( ptr->lagged == true )
{
/* set the link state for all the lagged physical interfaces */
if ( lmon_get_link_state ( ioctl_socket,
ptr->interface_two,
ptr->interface_two_link_up ) )
{
ptr->interface_two_event_time = lmon_fm_timestamp();
ptr->interface_two_link_up = false ;
wlog ("%s lag interface state query failed ; defaulting to Down\n",
ptr->interface_two) ;
}
else
{
ptr->interface_two_event_time = lmon_fm_timestamp();
ilog ("%s is %s (lag)\n",
ptr->interface_two,
ptr->interface_two_link_up ?
"Up" : "Down" );
}
}
}
}
int read_the_lmon_config( string iface_fullname, string& physical_interface){
FILE * file_ptr;
file_ptr = fopen (LMON_DIR , "r");
if (file_ptr)
{
ifstream fin( LMON_DIR );
string line;
while ( getline( fin, line ))
{
/* does this line contain it ? */
if ( line.find(iface_fullname) != string::npos )
{
stringstream ss( line );
// Config file Format like
// ....
// management_interface=ens7
// cluster_host_interface=ens7
// ...
getline( ss, physical_interface, '=' ); // get string before "="
getline( ss, physical_interface, '=' ); // get string after "="
plog ("%s is the %s primary network interface",
physical_interface.c_str(),
iface_fullname.c_str());
fclose(file_ptr);
return (PASS);
}
}
fclose(file_ptr);
}
return (FAIL);
}
string get_interface_fullname(const char * iface_name){
string iface_fullname = "";
if ( strcmp(iface_name, MGMT_INTERFACE_NAME) == 0 )
iface_fullname = MGMT_INTERFACE_FULLNAME;
else if ( strcmp(iface_name, CLUSTER_HOST_INTERFACE_NAME) == 0 )
iface_fullname = CLUSTER_HOST_INTERFACE_FULLNAME;
else if ( strcmp(iface_name, OAM_INTERFACE_NAME) == 0 )
iface_fullname = OAM_INTERFACE_FULLNAME;
else if ( strcmp(iface_name, DATA_NETWORK_INTERFACE_NAME) == 0 )
iface_fullname = DATA_NETWORK_INTERFACE_FULLNAME;
return iface_fullname;
}