2023-02-06 10:34:23 +08:00
# include <string.h>
2023-02-21 21:24:15 +08:00
# include <pthread.h>
# include <assert.h>
# include <unistd.h>
# include <MESA/MESA_prof_load.h>
# include <net/if.h>
# include <sys/ioctl.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netinet/if_ether.h>
# include <net/if_arp.h>
2023-07-13 15:24:50 +08:00
# include <netinet/ip.h>
# include <netinet/ip_icmp.h>
# include <net/if.h>
2023-02-21 21:24:15 +08:00
# include <arpa/inet.h>
# include <errno.h>
2023-07-13 15:24:50 +08:00
# include <linux/netlink.h>
# include <linux/rtnetlink.h>
# include <netinet/ether.h>
2023-02-06 10:34:23 +08:00
2023-02-21 21:24:15 +08:00
# include "log.h"
# include "uthash.h"
# include "bfd.h"
2023-02-28 19:03:35 +08:00
# include "sf_status.h"
2023-07-13 15:24:50 +08:00
# include "utils.h"
2023-02-06 10:34:23 +08:00
# include "health_check.h"
2023-07-13 15:24:50 +08:00
# define BUF_SIZE 4096
# define SEND_MAX 1
# define PACKET_SIZE 64
2023-02-21 21:24:15 +08:00
# define HC_DEV_NAME_LEN 16
# define HC_LOCAL_ADDRESS_LEN 64
2024-07-19 10:02:07 +08:00
# define TIMESPEC_TO_MSEC(ts) ((ts).tv_sec * 1000 + (ts).tv_nsec / 1000000)
2023-02-21 21:24:15 +08:00
2023-02-06 10:34:23 +08:00
struct session_table
{
// handler;
2023-02-21 21:24:15 +08:00
struct session_iterm * root_by_id ;
pthread_rwlock_t rwlock ;
2023-02-06 10:34:23 +08:00
} ;
struct session_iterm
{
2023-03-14 14:15:29 +08:00
uint64_t session_id ; // key
2023-02-06 10:34:23 +08:00
2023-03-14 14:15:29 +08:00
struct health_check policy ; // value1: deep copy
int is_active ; // value2
2024-09-23 16:50:09 +08:00
uuid_t sf_uuid ; // value3
2023-07-13 15:24:50 +08:00
int vsys_id ; // value4
2023-02-21 21:24:15 +08:00
UT_hash_handle hh1 ; /* handle for first hash table */
2023-02-06 10:34:23 +08:00
} ;
2023-03-14 14:15:29 +08:00
struct session_table_addr
{
// handler;
struct node_addr * htable ;
2023-07-13 15:24:50 +08:00
pthread_rwlock_t rwlock ;
2023-03-14 14:15:29 +08:00
} ;
struct node_addr
{
char address [ 64 ] ; // key
2023-10-12 11:59:42 +08:00
uint8_t mac [ ETH_ALEN ] ;
2023-03-14 14:15:29 +08:00
int ref_cnt ; // reference
UT_hash_handle hh ; /* handle for first hash table */
} ;
static uint64_t g_session_id ;
static struct session_table g_handle ;
2023-07-13 15:24:50 +08:00
static struct session_table_addr g_handle_bfd ;
static struct session_table_addr g_handle_none ;
2023-03-14 14:15:29 +08:00
static struct sf_status * g_sf_status = NULL ;
2024-07-19 10:02:07 +08:00
int next_check_wait_ms = 300 ;
2023-03-30 17:44:33 +08:00
int enable = 1 ;
2023-07-13 15:24:50 +08:00
int icmp_cycle_time_s = 10 ;
2023-02-21 21:24:15 +08:00
char path [ BFD_PATHLEN ] ;
char hc_dev_name [ HC_DEV_NAME_LEN ] ;
char local_address [ HC_LOCAL_ADDRESS_LEN ] ;
char gateway_address [ HC_LOCAL_ADDRESS_LEN ] ;
2023-10-12 11:59:42 +08:00
uint8_t default_gw_mac [ ETH_ALEN ] ;
2023-02-21 21:24:15 +08:00
static int get_mac_by_addr ( char * addr , uint8_t * buf ) ;
2023-02-22 20:32:37 +08:00
static int health_check_session_foreach ( ) ;
2023-02-21 21:24:15 +08:00
2023-07-13 15:24:50 +08:00
static int health_check_method_table_set_mac ( struct session_table_addr * table , char * addr , uint8_t * mac )
2023-03-14 14:15:29 +08:00
{
2023-07-13 15:24:50 +08:00
struct node_addr * tmp = NULL ;
pthread_rwlock_wrlock ( & ( table - > rwlock ) ) ;
HASH_FIND_STR ( table - > htable , addr , tmp ) ;
if ( tmp = = NULL ) {
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 1 ;
}
2023-10-12 11:59:42 +08:00
memcpy ( tmp - > mac , mac , ETH_ALEN ) ;
2023-07-13 15:24:50 +08:00
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 0 ;
2023-03-14 14:15:29 +08:00
}
2023-07-13 15:24:50 +08:00
static int health_check_method_table_get_mac ( struct session_table_addr * table , char * addr , uint8_t * out_mac )
2023-03-14 14:15:29 +08:00
{
2023-07-13 15:24:50 +08:00
struct node_addr * tmp = NULL ;
pthread_rwlock_rdlock ( & ( table - > rwlock ) ) ;
HASH_FIND_STR ( table - > htable , addr , tmp ) ;
if ( tmp = = NULL ) {
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 1 ;
}
2023-10-12 11:59:42 +08:00
memcpy ( out_mac , tmp - > mac , ETH_ALEN ) ;
2023-07-13 15:24:50 +08:00
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 0 ;
2023-03-14 14:15:29 +08:00
}
2023-07-13 15:24:50 +08:00
static int health_check_method_table_del ( struct session_table_addr * table , char * addr )
2023-02-21 21:24:15 +08:00
{
2023-07-13 15:24:50 +08:00
struct node_addr * tmp = NULL ;
pthread_rwlock_wrlock ( & ( table - > rwlock ) ) ;
HASH_FIND_STR ( table - > htable , addr , tmp ) ;
if ( tmp = = NULL ) {
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 0 ;
}
if ( - - tmp - > ref_cnt ) {
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 1 ;
}
HASH_DEL ( table - > htable , tmp ) ;
free ( tmp ) ;
tmp = NULL ;
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 0 ;
}
static int health_check_method_table_add ( struct session_table_addr * table , char * addr )
{
struct node_addr * tmp = NULL ;
pthread_rwlock_wrlock ( & ( table - > rwlock ) ) ;
HASH_FIND_STR ( table - > htable , addr , tmp ) ;
if ( tmp ) {
tmp - > ref_cnt + + ;
}
else {
tmp = ( struct node_addr * ) calloc ( 1 , sizeof ( struct node_addr ) ) ;
assert ( tmp ) ;
snprintf ( tmp - > address , sizeof ( tmp - > address ) , addr ) ;
tmp - > ref_cnt + + ;
HASH_ADD_STR ( table - > htable , address , tmp ) ;
}
pthread_rwlock_unlock ( & ( table - > rwlock ) ) ;
return 0 ;
}
2023-11-20 10:31:21 +08:00
# define CHECKSUM_CARRY(x) (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
static inline int checksum ( uint16_t * data , int len )
{
int sum = 0 ;
int nleft = len ;
uint16_t ans = 0 ;
uint16_t * w = data ;
while ( nleft > 1 )
{
sum + = * w + + ;
nleft - = 2 ;
}
if ( nleft = = 1 )
{
* ( char * ) ( & ans ) = * ( char * ) w ;
sum + = ans ;
}
return sum ;
}
2023-07-13 15:24:50 +08:00
static int send_icmp_pkt ( char * addr )
{
int sockfd ;
char packet [ PACKET_SIZE ] = { 0 } ;
struct ifreq ifr ;
struct icmp * icmp = ( struct icmp * ) packet ;
struct sockaddr_in dest_addr ;
sockfd = socket ( AF_INET , SOCK_RAW , IPPROTO_ICMP ) ;
if ( sockfd < 0 )
return 1 ;
dest_addr . sin_family = AF_INET ;
dest_addr . sin_port = 0 ;
if ( inet_pton ( AF_INET , addr , & ( dest_addr . sin_addr ) ) < = 0 ) {
close ( sockfd ) ;
LOG_ERROR ( " unable to send icmp packet, address[%s] invalid! " , addr ) ;
return 1 ;
}
memset ( & ifr , 0 , sizeof ( ifr ) ) ;
snprintf ( ifr . ifr_name , sizeof ( ifr . ifr_name ) , " %s " , hc_dev_name ) ;
if ( setsockopt ( sockfd , SOL_SOCKET , SO_BINDTODEVICE , ( void * ) & ifr , sizeof ( ifr ) ) < 0 ) {
close ( sockfd ) ;
LOG_ERROR ( " unable to send icmp packet, device[%s] bind failed! " , hc_dev_name ) ;
return 1 ;
}
icmp - > icmp_type = ICMP_ECHO ;
icmp - > icmp_code = 0 ;
icmp - > icmp_id = htons ( getpid ( ) ) ;
icmp - > icmp_seq = 0 ;
icmp - > icmp_cksum = 0 ;
int sum = checksum ( ( uint16_t * ) icmp , PACKET_SIZE ) ;
icmp - > icmp_cksum = CHECKSUM_CARRY ( sum ) ;
for ( int i = 0 ; i < SEND_MAX ; i + + ) {
sendto ( sockfd , packet , PACKET_SIZE , 0 , ( struct sockaddr * ) & dest_addr , sizeof ( dest_addr ) ) ;
}
close ( sockfd ) ;
return 0 ;
}
static void * _listen_arp_table ( void * arg )
{
struct sockaddr_nl sa ;
int nl_sock ;
char buf [ BUF_SIZE ] ;
struct in_addr ipaddr ;
uint8_t * mac = NULL ;
char str_addr [ INET_ADDRSTRLEN ] = { 0 } ;
2023-10-12 11:59:42 +08:00
uint8_t init_mac [ ETH_ALEN ] = { 0 } ;
2023-07-13 15:24:50 +08:00
start :
nl_sock = socket ( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
if ( nl_sock < 0 ) {
LOG_ERROR ( " listen_arp_table: unable to create socket! " ) ;
return NULL ;
}
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . nl_family = AF_NETLINK ;
sa . nl_groups = RTMGRP_NEIGH ;
if ( bind ( nl_sock , ( struct sockaddr * ) & sa , sizeof ( sa ) ) ! = 0 ) {
close ( nl_sock ) ;
LOG_ERROR ( " listen_arp_table: unable to bind! " ) ;
return NULL ;
}
while ( 1 ) {
int len = recv ( nl_sock , buf , sizeof ( buf ) , 0 ) ;
if ( len < 0 ) {
close ( nl_sock ) ;
goto start ;
}
struct nlmsghdr * nh ;
for ( nh = ( struct nlmsghdr * ) buf ; NLMSG_OK ( nh , len ) ; nh = NLMSG_NEXT ( nh , len ) ) {
if ( nh - > nlmsg_type = = NLMSG_DONE )
break ;
if ( nh - > nlmsg_type = = NLMSG_ERROR ) {
close ( nl_sock ) ;
goto start ;
}
struct ndmsg * nd = ( struct ndmsg * ) NLMSG_DATA ( nh ) ;
struct rtattr * rth = ( struct rtattr * ) RTM_RTA ( nd ) ;
int rtl = RTM_PAYLOAD ( nh ) ;
memset ( & ipaddr , 0 , sizeof ( ipaddr ) ) ;
mac = NULL ;
for ( ; RTA_OK ( rth , rtl ) ; rth = RTA_NEXT ( rth , rtl ) ) {
if ( rth - > rta_type = = NDA_DST ) {
memcpy ( & ipaddr , RTA_DATA ( rth ) , sizeof ( struct in_addr ) ) ;
} else if ( rth - > rta_type = = NDA_LLADDR ) {
mac = ( uint8_t * ) RTA_DATA ( rth ) ;
}
}
if ( inet_ntop ( AF_INET , & ipaddr , str_addr , INET_ADDRSTRLEN ) ! = NULL ) {
if ( mac = = NULL ) {
health_check_method_table_set_mac ( & g_handle_bfd , str_addr , init_mac ) ;
health_check_method_table_set_mac ( & g_handle_none , str_addr , init_mac ) ;
}
else {
health_check_method_table_set_mac ( & g_handle_bfd , str_addr , mac ) ;
health_check_method_table_set_mac ( & g_handle_none , str_addr , mac ) ;
}
}
}
}
close ( nl_sock ) ;
return 0 ;
}
static int listen_arp_table ( )
{
pthread_t pid ;
pthread_create ( & pid , NULL , _listen_arp_table , NULL ) ;
pthread_detach ( pid ) ;
return pid ;
}
static void * _send_icmp_cycle ( void * arg )
{
struct node_addr * node = NULL ;
struct node_addr * tmp = NULL ;
while ( 1 ) {
pthread_rwlock_rdlock ( & g_handle_none . rwlock ) ;
HASH_ITER ( hh , g_handle_none . htable , node , tmp ) {
send_icmp_pkt ( node - > address ) ;
}
pthread_rwlock_unlock ( & g_handle_none . rwlock ) ;
sleep ( icmp_cycle_time_s ) ;
}
}
static int send_icmp_cycle ( )
{
pthread_t pid ;
pthread_create ( & pid , NULL , _send_icmp_cycle , NULL ) ;
pthread_detach ( pid ) ;
return pid ;
2023-02-21 21:24:15 +08:00
}
2024-07-19 10:02:07 +08:00
void health_check_session_init ( const char * profile , struct kafka * kfk )
2023-02-06 10:34:23 +08:00
{
2023-10-20 18:38:40 +08:00
char default_gw_mac_str [ 32 ] = { 0 } ;
2023-02-06 10:34:23 +08:00
memset ( & g_handle , 0 , sizeof ( g_handle ) ) ;
2023-02-21 21:24:15 +08:00
pthread_rwlock_init ( & g_handle . rwlock , NULL ) ;
2023-07-13 15:24:50 +08:00
memset ( & g_handle_bfd , 0 , sizeof ( g_handle_bfd ) ) ;
pthread_rwlock_init ( & g_handle_bfd . rwlock , NULL ) ;
memset ( & g_handle_none , 0 , sizeof ( g_handle_none ) ) ;
pthread_rwlock_init ( & g_handle_none . rwlock , NULL ) ;
2023-03-30 17:44:33 +08:00
MESA_load_profile_int_def ( profile , " bfdd " , " enable " , & enable , 1 ) ;
2023-07-13 15:24:50 +08:00
MESA_load_profile_int_def ( profile , " bfdd " , " icmp_cycle_time_s " , & icmp_cycle_time_s , 10 ) ;
2023-02-21 21:24:15 +08:00
MESA_load_profile_string_def ( profile , " bfdd " , " path " , path , sizeof ( path ) , " /var/run/frr/bfdd.vty " ) ;
MESA_load_profile_string_def ( profile , " bfdd " , " device " , hc_dev_name , sizeof ( hc_dev_name ) , " eth0 " ) ;
MESA_load_profile_string_def ( profile , " bfdd " , " local_address " , local_address , sizeof ( local_address ) , " 127.0.0.1 " ) ;
2023-12-25 11:04:58 +08:00
MESA_load_profile_string_nodef ( profile , " bfdd " , " gateway " , gateway_address , sizeof ( gateway_address ) ) ;
2023-10-20 18:38:40 +08:00
MESA_load_profile_string_def ( profile , " bfdd " , " default_gw_mac " , default_gw_mac_str , sizeof ( default_gw_mac_str ) , " aa:aa:aa:aa:aa:aa " ) ;
2023-02-21 21:24:15 +08:00
2023-03-30 17:44:33 +08:00
if ( enable = = 0 )
{
2023-10-20 18:38:40 +08:00
str_to_mac ( default_gw_mac_str , default_gw_mac ) ;
2023-03-30 17:44:33 +08:00
return ;
}
2024-07-19 10:02:07 +08:00
g_sf_status = sf_status_create ( profile , kfk ) ;
2023-12-25 11:04:58 +08:00
if ( strlen ( gateway_address ) > 0 ) {
health_check_method_table_add ( & g_handle_none , gateway_address ) ;
}
2023-02-21 21:24:15 +08:00
health_check_session_foreach ( ) ;
2023-07-13 15:24:50 +08:00
listen_arp_table ( ) ;
send_icmp_cycle ( ) ;
2023-02-21 21:24:15 +08:00
}
2023-02-06 10:34:23 +08:00
2023-02-27 14:30:37 +08:00
static int health_check_session_recover_cfg ( struct bfd_vtysh_client * client )
{
int ret = 0 ;
struct session_iterm * tmp = NULL ;
struct session_iterm * node = NULL ;
HASH_ITER ( hh1 , g_handle . root_by_id , node , tmp ) {
if ( node - > policy . method ! = HEALTH_CHECK_METHOD_BFD )
continue ;
ret = bfd_vtysh_add_dev ( client , node - > policy . address , node - > policy . retires , node - > policy . interval_ms ) ;
if ( ret ! = 0 )
return - 1 ;
}
return 0 ;
}
2023-02-21 21:24:15 +08:00
static void health_check_session_init_bfd_client ( struct bfd_vtysh_client * client )
{
memset ( client , 0 , sizeof ( * client ) ) ;
snprintf ( client - > path , sizeof ( client - > path ) , path ) ;
client - > pre_config = bfd_vtysh_pre_config ;
2023-02-06 10:34:23 +08:00
}
2023-02-27 14:30:37 +08:00
static void health_check_session_recover_bfd ( struct bfd_vtysh_client * client )
{
memset ( client , 0 , sizeof ( * client ) ) ;
snprintf ( client - > path , sizeof ( client - > path ) , path ) ;
client - > pre_config = bfd_vtysh_pre_config ;
client - > recover_config = health_check_session_recover_cfg ;
}
2023-07-13 15:24:50 +08:00
static int bfd_rule_add ( const struct health_check * policy )
2023-03-14 14:15:29 +08:00
{
2023-07-13 15:24:50 +08:00
int ret = 0 ;
struct bfd_vtysh_client client ;
2023-03-14 14:15:29 +08:00
2023-07-13 15:24:50 +08:00
health_check_session_init_bfd_client ( & client ) ;
bfd_vtysh_connect ( & client ) ;
ret = bfd_vtysh_add_dev ( & client , policy - > address , policy - > retires , policy - > interval_ms ) ;
if ( ret ! = 0 )
LOG_ERROR ( " bfd vtysh add dev address [%s] failed! " , policy - > address ) ;
bfd_vtysh_close ( & client ) ;
return ret ;
2023-03-14 14:15:29 +08:00
}
2023-07-13 15:24:50 +08:00
static int bfd_rule_del ( const struct health_check * policy )
2023-03-14 14:15:29 +08:00
{
int ret = 0 ;
2023-07-13 15:24:50 +08:00
struct bfd_vtysh_client client ;
2023-03-14 14:15:29 +08:00
2023-07-13 15:24:50 +08:00
health_check_session_init_bfd_client ( & client ) ;
bfd_vtysh_connect ( & client ) ;
ret = bfd_vtysh_del_dev ( & client , policy - > address ) ;
if ( ret ! = 0 ) {
LOG_ERROR ( " bfd vtysh delete dev address [%s] failed! " , policy - > address ) ;
}
bfd_vtysh_close ( & client ) ;
return ret ;
}
2023-03-14 14:15:29 +08:00
2023-07-13 15:24:50 +08:00
static struct session_iterm * health_check_session_get ( uint64_t session_id )
{
struct session_iterm * tmp = NULL ;
HASH_FIND ( hh1 , g_handle . root_by_id , & session_id , sizeof ( session_id ) , tmp ) ;
return tmp ;
2023-03-14 14:15:29 +08:00
}
static uint64_t health_check_get_session_id ( )
{
struct session_iterm * tmp = NULL ;
uint64_t tmp_session_id = g_session_id ;
while ( 1 ) {
g_session_id + + ;
if ( g_session_id = = 0 )
g_session_id + + ;
if ( tmp_session_id = = g_session_id )
return 0 ;
2023-07-13 15:24:50 +08:00
tmp = health_check_session_get ( g_session_id ) ;
2023-03-14 14:15:29 +08:00
if ( tmp )
continue ;
break ;
}
return g_session_id ;
}
// return >0 : session id
// return 0 : fail
2023-02-06 10:34:23 +08:00
// struct health_check *policy : need deep copy
2024-09-23 16:50:09 +08:00
uint64_t health_check_session_add ( uuid_t * sf_uuid , int vsys_id , const struct health_check * policy )
2023-02-06 10:34:23 +08:00
{
2023-03-14 14:15:29 +08:00
uint64_t session_id = 0 ;
2023-10-12 11:59:42 +08:00
uint8_t mac [ ETH_ALEN ] = { 0 } ;
2023-02-21 21:24:15 +08:00
struct session_iterm * tmp = NULL ;
2023-03-30 17:44:33 +08:00
if ( enable = = 0 )
{
return 1 ;
}
2023-07-13 15:24:50 +08:00
pthread_rwlock_wrlock ( & g_handle . rwlock ) ;
2023-03-14 14:15:29 +08:00
session_id = health_check_get_session_id ( ) ;
if ( session_id = = 0 ) {
2023-07-13 15:24:50 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-03-14 14:15:29 +08:00
LOG_ERROR ( " health check get session id failed! " ) ;
return 0 ;
2023-02-21 21:24:15 +08:00
}
tmp = ( struct session_iterm * ) calloc ( 1 , sizeof ( struct session_iterm ) ) ;
assert ( tmp ) ;
2023-04-26 15:04:04 +08:00
tmp - > vsys_id = vsys_id ;
2023-02-21 21:24:15 +08:00
tmp - > session_id = session_id ;
2024-09-23 16:50:09 +08:00
uuid_copy ( tmp - > sf_uuid , * sf_uuid ) ;
2023-02-21 21:24:15 +08:00
memcpy ( & tmp - > policy , policy , sizeof ( struct health_check ) ) ;
HASH_ADD ( hh1 , g_handle . root_by_id , session_id , sizeof ( tmp - > session_id ) , tmp ) ;
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-03-14 14:15:29 +08:00
if ( policy - > method = = HEALTH_CHECK_METHOD_BFD ) {
2023-07-13 15:24:50 +08:00
health_check_method_table_add ( & g_handle_bfd , tmp - > policy . address ) ;
bfd_rule_add ( policy ) ;
}
else if ( policy - > method = = HEALTH_CHECK_METHOD_NONE ) {
health_check_method_table_add ( & g_handle_none , tmp - > policy . address ) ;
send_icmp_pkt ( tmp - > policy . address ) ;
get_mac_by_addr ( tmp - > policy . address , mac ) ;
health_check_method_table_set_mac ( & g_handle_none , tmp - > policy . address , mac ) ;
2023-03-14 14:15:29 +08:00
}
2024-09-23 16:50:09 +08:00
char sf_uuid_str [ UUID_STRING_SIZE ] = { 0 } ;
uuid_unparse ( * sf_uuid , sf_uuid_str ) ;
LOG_DEBUG ( " health check session table insert: profile id [%s] session id [%lu] address [%s] success " , sf_uuid_str , session_id , policy - > address ) ;
2023-03-14 14:15:29 +08:00
return session_id ;
2023-02-06 10:34:23 +08:00
}
// return 0 : success
// return -1 : key not exist
2024-09-23 16:50:09 +08:00
int health_check_session_del ( uint64_t session_id , uuid_t * sf_uuid , int vsys_id )
2023-02-06 10:34:23 +08:00
{
2023-02-21 21:24:15 +08:00
int ret = 0 ;
struct session_iterm * tmp = NULL ;
2023-03-30 17:44:33 +08:00
if ( enable = = 0 )
{
return 0 ;
}
2023-07-13 15:24:50 +08:00
pthread_rwlock_wrlock ( & g_handle . rwlock ) ;
tmp = health_check_session_get ( session_id ) ;
2023-02-21 21:24:15 +08:00
if ( ! tmp ) {
2023-07-13 15:24:50 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-03-14 14:15:29 +08:00
LOG_DEBUG ( " health check session table delete: session id [%lu] not exists " , session_id ) ;
2023-02-21 21:24:15 +08:00
return - 1 ;
}
2023-02-24 13:59:35 +08:00
if ( tmp - > policy . method = = HEALTH_CHECK_METHOD_BFD ) {
2023-07-13 15:24:50 +08:00
ret = health_check_method_table_del ( & g_handle_bfd , tmp - > policy . address ) ;
if ( ret ! = 0 )
2023-03-14 14:15:29 +08:00
goto end ;
2023-07-13 15:24:50 +08:00
bfd_rule_del ( & tmp - > policy ) ;
}
else if ( tmp - > policy . method = = HEALTH_CHECK_METHOD_NONE ) {
ret = health_check_method_table_del ( & g_handle_none , tmp - > policy . address ) ;
2023-02-21 21:24:15 +08:00
}
2023-03-14 14:15:29 +08:00
end :
2023-02-21 21:24:15 +08:00
HASH_DELETE ( hh1 , g_handle . root_by_id , tmp ) ;
2024-07-19 10:02:07 +08:00
struct sf_status_key key = { 0 } ;
key . vsys_id = vsys_id ;
2024-09-23 16:50:09 +08:00
uuid_copy ( key . sf_uuid , * sf_uuid ) ;
2024-07-19 10:02:07 +08:00
sf_status_delete ( g_sf_status , & key ) ;
2023-02-21 21:24:15 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
free ( tmp ) ;
tmp = NULL ;
2024-09-23 16:50:09 +08:00
char sf_uuid_str [ UUID_STRING_SIZE ] = { 0 } ;
uuid_unparse ( * sf_uuid , sf_uuid_str ) ;
LOG_DEBUG ( " health check session table delete: profile id [%s] session id [%lu] success " , sf_uuid_str , session_id ) ;
2023-02-06 10:34:23 +08:00
return 0 ;
}
// return 1 : active
// return 0 : inactive
// return -1 : key not exist
2023-03-14 14:15:29 +08:00
int health_check_session_get_status ( uint64_t session_id )
2023-02-06 10:34:23 +08:00
{
2023-02-21 21:24:15 +08:00
int status = 0 ;
struct session_iterm * tmp = NULL ;
2023-03-30 17:44:33 +08:00
if ( enable = = 0 )
{
return 1 ;
}
2023-02-23 11:13:41 +08:00
pthread_rwlock_rdlock ( & g_handle . rwlock ) ;
HASH_FIND ( hh1 , g_handle . root_by_id , & session_id , sizeof ( session_id ) , tmp ) ;
2023-02-21 21:24:15 +08:00
if ( ! tmp ) {
2023-03-14 14:15:29 +08:00
LOG_DEBUG ( " health check session table get status: session id [%lu] not exists " , session_id ) ;
2023-02-23 11:13:41 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-02-21 21:24:15 +08:00
return - 1 ;
}
status = tmp - > is_active ;
2023-02-23 11:13:41 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-03-14 14:15:29 +08:00
LOG_DEBUG ( " health check session id[%lu] get status [%d] " , session_id , status ) ;
2023-02-21 21:24:15 +08:00
return status ;
2023-02-06 10:34:23 +08:00
}
// return 0 : success
// return -1 : key not exist
2023-03-14 14:15:29 +08:00
int health_check_session_set_status ( uint64_t session_id , int is_active )
2023-02-06 10:34:23 +08:00
{
2023-02-21 21:24:15 +08:00
struct session_iterm * tmp = NULL ;
2023-03-30 17:44:33 +08:00
if ( enable = = 0 )
{
return 0 ;
}
2023-02-21 21:24:15 +08:00
pthread_rwlock_wrlock ( & g_handle . rwlock ) ;
HASH_FIND ( hh1 , g_handle . root_by_id , & session_id , sizeof ( session_id ) , tmp ) ;
if ( ! tmp ) {
2023-03-14 14:15:29 +08:00
LOG_DEBUG ( " health check session table set status: session id [%lu] not exists " , session_id ) ;
2023-02-21 21:24:15 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
return - 1 ;
}
tmp - > is_active = is_active ;
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-02-06 10:34:23 +08:00
return 0 ;
}
2023-02-21 21:24:15 +08:00
static int get_mac_by_addr ( char * addr , uint8_t * buf )
2023-02-20 15:30:32 +08:00
{
2023-04-26 15:04:04 +08:00
int sfd , ret ;
2023-02-21 21:24:15 +08:00
struct arpreq arp_req ;
struct sockaddr_in * sin ;
sin = ( struct sockaddr_in * ) & ( arp_req . arp_pa ) ;
memset ( & arp_req , 0 , sizeof ( arp_req ) ) ;
sin - > sin_family = AF_INET ;
inet_pton ( AF_INET , addr , & ( sin - > sin_addr ) ) ;
snprintf ( arp_req . arp_dev , IFNAMSIZ , hc_dev_name ) ;
sfd = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
2023-03-31 17:43:37 +08:00
if ( sfd = = - 1 )
2023-02-21 21:24:15 +08:00
return - 1 ;
2023-03-31 17:43:37 +08:00
ret = ioctl ( sfd , SIOCGARP , & arp_req ) ;
2023-07-13 15:24:50 +08:00
if ( ret = = 0 )
2023-10-12 11:59:42 +08:00
memcpy ( buf , arp_req . arp_ha . sa_data , ETH_ALEN ) ;
2023-02-21 21:24:15 +08:00
2023-03-31 17:43:37 +08:00
LOG_DEBUG ( " IP:%s, MAC: %02x:%02x:%02x:%02x:%02x:%02x " ,
2023-03-14 14:15:29 +08:00
addr , buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , buf [ 3 ] , buf [ 4 ] , buf [ 5 ] ) ;
2023-03-31 17:43:37 +08:00
close ( sfd ) ;
2023-02-20 15:30:32 +08:00
return 0 ;
}
2023-02-21 21:24:15 +08:00
static void * _health_check_session_foreach ( void * arg )
2023-02-06 10:34:23 +08:00
{
2023-02-21 21:24:15 +08:00
int is_active = 0 ;
2024-07-19 10:02:07 +08:00
int ouput_interval_ms = sf_status_get_ouput_interval_ms ( g_sf_status ) ;
2023-02-21 21:24:15 +08:00
struct bfd_vtysh_client client ;
struct session_iterm * tmp = NULL ;
struct session_iterm * node = NULL ;
2023-10-12 11:59:42 +08:00
uint8_t mac [ ETH_ALEN ] = { 0 } ;
uint8_t init_mac [ ETH_ALEN ] = { 0 } ;
2023-07-13 15:24:50 +08:00
struct sockaddr_in addr ;
2023-02-21 21:24:15 +08:00
2023-02-28 19:03:35 +08:00
struct timespec current_time ;
2024-07-19 10:02:07 +08:00
struct timespec last_output_time ;
2023-02-28 19:03:35 +08:00
clock_gettime ( CLOCK_MONOTONIC , & current_time ) ;
2024-07-19 10:02:07 +08:00
last_output_time = current_time ;
2023-02-28 19:03:35 +08:00
2023-02-21 21:24:15 +08:00
health_check_session_init_bfd_client ( & client ) ;
bfd_vtysh_connect ( & client ) ;
while ( 1 ) {
pthread_rwlock_wrlock ( & g_handle . rwlock ) ;
HASH_ITER ( hh1 , g_handle . root_by_id , node , tmp ) {
if ( node - > policy . method ! = HEALTH_CHECK_METHOD_BFD )
continue ;
2023-07-13 15:24:50 +08:00
if ( inet_pton ( AF_INET , node - > policy . address , & ( addr . sin_addr ) ) > 0 ) {
2023-02-27 14:30:37 +08:00
is_active = bfd_vtysh_get_dev_active ( & client , node - > policy . address ) ;
2023-03-31 17:43:37 +08:00
if ( is_active = = - 1 ) {
bfd_vtysh_close ( & client ) ;
health_check_session_recover_bfd ( & client ) ;
bfd_vtysh_connect ( & client ) ;
is_active = bfd_vtysh_get_dev_active ( & client , node - > policy . address ) ;
if ( is_active = = - 1 )
is_active = 0 ;
}
2023-02-27 14:30:37 +08:00
}
2023-03-31 17:43:37 +08:00
else {
is_active = 0 ;
}
2024-07-19 10:02:07 +08:00
struct sf_status_key key = { 0 } ;
key . vsys_id = node - > vsys_id ;
2024-09-23 16:50:09 +08:00
uuid_copy ( key . sf_uuid , node - > sf_uuid ) ;
2024-07-19 10:02:07 +08:00
sf_status_update ( g_sf_status , & key , is_active , 0 ) ;
2023-02-21 21:24:15 +08:00
if ( node - > is_active ! = is_active ) {
node - > is_active = is_active ;
if ( node - > is_active = = 1 ) {
2023-10-12 11:59:42 +08:00
memset ( mac , 0 , ETH_ALEN ) ;
2023-07-13 15:24:50 +08:00
get_mac_by_addr ( node - > policy . address , mac ) ;
health_check_method_table_set_mac ( & g_handle_bfd , node - > policy . address , mac ) ;
2023-02-21 21:24:15 +08:00
}
else {
2023-07-13 15:24:50 +08:00
health_check_method_table_set_mac ( & g_handle_bfd , node - > policy . address , init_mac ) ;
2023-02-21 21:24:15 +08:00
}
}
2024-07-19 10:02:07 +08:00
if ( next_check_wait_ms > node - > policy . interval_ms )
next_check_wait_ms = node - > policy . interval_ms ;
2023-02-21 21:24:15 +08:00
}
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-02-28 19:03:35 +08:00
clock_gettime ( CLOCK_MONOTONIC , & current_time ) ;
2024-07-19 10:02:07 +08:00
int next_output_wait_ms = ouput_interval_ms - ( TIMESPEC_TO_MSEC ( current_time ) - TIMESPEC_TO_MSEC ( last_output_time ) ) ;
if ( next_output_wait_ms < = 0 )
2023-02-28 19:03:35 +08:00
{
2024-07-19 10:02:07 +08:00
next_output_wait_ms = 0 ;
2023-02-28 19:03:35 +08:00
}
2024-07-19 10:02:07 +08:00
if ( next_output_wait_ms > = next_check_wait_ms )
2023-02-28 19:03:35 +08:00
{
2024-07-19 10:02:07 +08:00
usleep ( next_check_wait_ms * 1000 ) ;
2023-02-28 19:03:35 +08:00
}
else
{
2024-07-19 10:02:07 +08:00
usleep ( next_output_wait_ms * 1000 ) ;
clock_gettime ( CLOCK_MONOTONIC , & current_time ) ;
sf_status_output ( g_sf_status ) ;
last_output_time = current_time ;
usleep ( ( next_check_wait_ms - next_output_wait_ms ) * 1000 ) ;
2023-02-28 19:03:35 +08:00
}
2023-02-21 21:24:15 +08:00
}
bfd_vtysh_close ( & client ) ;
2023-02-28 21:42:52 +08:00
return NULL ;
2023-02-21 21:24:15 +08:00
}
2023-02-22 20:32:37 +08:00
static int health_check_session_foreach ( )
2023-02-21 21:24:15 +08:00
{
pthread_t pid ;
pthread_create ( & pid , NULL , _health_check_session_foreach , NULL ) ;
pthread_detach ( pid ) ;
return pid ;
}
2023-07-13 15:24:50 +08:00
static const char * health_check_method_str ( enum health_check_method method )
{
switch ( method ) {
case HEALTH_CHECK_METHOD_NONE :
return " HEALTH_CHECK_METHOD_NONE " ;
case HEALTH_CHECK_METHOD_IN_BAND_BFD :
return " HEALTH_CHECK_METHOD_IN_BAND_BFD " ;
case HEALTH_CHECK_METHOD_BFD :
return " HEALTH_CHECK_METHOD_BFD " ;
case HEALTH_CHECK_METHOD_HTTP :
return " HEALTH_CHECK_METHOD_HTTP " ;
default :
return NULL ;
}
}
2023-02-21 21:24:15 +08:00
// return 0 : success
// return -1 : key not exist
2023-10-12 11:59:42 +08:00
int health_check_session_get_mac ( uint64_t session_id , u_char mac_buff [ ] )
2023-02-21 21:24:15 +08:00
{
2023-07-13 15:24:50 +08:00
const char * str_method = NULL ;
2023-02-21 21:24:15 +08:00
struct session_iterm * tmp = NULL ;
2023-10-12 11:59:42 +08:00
uint8_t mac [ ETH_ALEN ] = { 0 } ;
uint8_t init_mac [ ETH_ALEN ] = { 0 } ;
2024-09-23 16:50:09 +08:00
char sf_uuid_str [ UUID_STRING_SIZE ] = { 0 } ;
2023-02-21 21:24:15 +08:00
2023-03-30 17:44:33 +08:00
if ( enable = = 0 )
{
2023-10-20 18:38:40 +08:00
memcpy ( mac_buff , default_gw_mac , ETH_ALEN ) ;
2023-03-30 17:44:33 +08:00
return 0 ;
}
2023-02-23 11:13:41 +08:00
pthread_rwlock_rdlock ( & g_handle . rwlock ) ;
HASH_FIND ( hh1 , g_handle . root_by_id , & session_id , sizeof ( session_id ) , tmp ) ;
2023-02-21 21:24:15 +08:00
if ( ! tmp ) {
2023-03-14 14:15:29 +08:00
LOG_DEBUG ( " health check session get mac: session id [%lu] not exists " , session_id ) ;
2023-02-23 11:13:41 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-02-21 21:24:15 +08:00
return - 1 ;
}
2024-09-23 16:50:09 +08:00
uuid_unparse ( tmp - > sf_uuid , sf_uuid_str ) ;
2023-07-13 15:24:50 +08:00
str_method = health_check_method_str ( tmp - > policy . method ) ;
if ( tmp - > policy . method = = HEALTH_CHECK_METHOD_BFD & & tmp - > is_active = = 0 ) {
2024-09-23 16:50:09 +08:00
LOG_DEBUG ( " health check session id [%lu] profile id [%s] health check method [%s] active is down " , session_id , sf_uuid_str , str_method ) ;
2023-02-24 13:59:35 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
return - 1 ;
}
2023-07-13 15:24:50 +08:00
if ( tmp - > policy . method = = HEALTH_CHECK_METHOD_BFD ) {
health_check_method_table_get_mac ( & g_handle_bfd , tmp - > policy . address , mac ) ;
}
else if ( tmp - > policy . method = = HEALTH_CHECK_METHOD_NONE ) {
health_check_method_table_get_mac ( & g_handle_none , tmp - > policy . address , mac ) ;
}
2023-10-12 11:59:42 +08:00
if ( memcmp ( mac , init_mac , ETH_ALEN ) = = 0 ) {
2023-12-25 11:04:58 +08:00
if ( strlen ( gateway_address ) = = 0 ) {
2024-09-23 16:50:09 +08:00
LOG_DEBUG ( " health check session id [%lu] profile id [%s] health check method [%s] get mac [null] " , session_id , sf_uuid_str , str_method ) ;
2023-12-25 11:04:58 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
return - 1 ;
}
2023-07-13 15:24:50 +08:00
health_check_method_table_get_mac ( & g_handle_none , gateway_address , mac ) ;
2023-10-12 11:59:42 +08:00
if ( memcmp ( mac , init_mac , ETH_ALEN ) = = 0 ) {
2024-09-23 16:50:09 +08:00
LOG_DEBUG ( " health check session id [%lu] profile id [%s] health check method [%s] get mac [null] " , session_id , sf_uuid_str , str_method ) ;
2023-07-13 15:24:50 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
return - 1 ;
}
}
2023-10-12 11:59:42 +08:00
memcpy ( mac_buff , mac , ETH_ALEN ) ;
2024-09-23 16:50:09 +08:00
LOG_DEBUG ( " health check session id [%lu] profile id [%s] health check method [%s] get mac [%02x:%02x:%02x:%02x:%02x:%02x] " , session_id , sf_uuid_str , str_method , mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] ) ;
2023-02-23 11:13:41 +08:00
pthread_rwlock_unlock ( & g_handle . rwlock ) ;
2023-02-21 21:24:15 +08:00
return 0 ;
2023-02-06 10:34:23 +08:00
}