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>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#include <errno.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-06 10:34:23 +08:00
|
|
|
#include "health_check.h"
|
|
|
|
|
|
2023-02-21 21:24:15 +08:00
|
|
|
|
|
|
|
|
#define HC_MAC_LEN 6
|
|
|
|
|
#define HC_DEV_NAME_LEN 16
|
|
|
|
|
#define HC_LOCAL_ADDRESS_LEN 64
|
|
|
|
|
|
2023-02-06 10:34:23 +08:00
|
|
|
struct session_table
|
|
|
|
|
{
|
|
|
|
|
// rwlock ???;
|
|
|
|
|
// 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
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct session_table g_handle;
|
|
|
|
|
|
|
|
|
|
struct session_iterm
|
|
|
|
|
{
|
|
|
|
|
int session_id; // key
|
|
|
|
|
|
|
|
|
|
struct health_check policy; // value1: deep copy
|
2023-02-21 21:24:15 +08:00
|
|
|
int is_active; // value2
|
|
|
|
|
uint8_t mac[HC_MAC_LEN]; // value3
|
|
|
|
|
|
|
|
|
|
UT_hash_handle hh1; /* handle for first hash table */
|
2023-02-06 10:34:23 +08:00
|
|
|
};
|
|
|
|
|
|
2023-02-21 21:24:15 +08:00
|
|
|
int sleep_ms = 300;
|
|
|
|
|
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];
|
|
|
|
|
uint8_t default_gw_mac[HC_MAC_LEN];
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
static struct session_iterm *health_check_get_iterm_by_id(int session_id)
|
|
|
|
|
{
|
|
|
|
|
struct session_iterm *tmp = NULL;
|
|
|
|
|
pthread_rwlock_rdlock(&g_handle.rwlock);
|
|
|
|
|
HASH_FIND(hh1, g_handle.root_by_id, &session_id, sizeof(session_id), tmp);
|
|
|
|
|
pthread_rwlock_unlock(&g_handle.rwlock);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void health_check_session_init(const char *profile)
|
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);
|
|
|
|
|
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");
|
|
|
|
|
MESA_load_profile_string_def(profile, "bfdd", "gateway", gateway_address, sizeof(gateway_address), "127.0.0.1");
|
|
|
|
|
|
|
|
|
|
// TODO: 循环获取?
|
|
|
|
|
get_mac_by_addr(gateway_address, default_gw_mac);
|
|
|
|
|
health_check_session_foreach();
|
|
|
|
|
}
|
2023-02-06 10:34:23 +08:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return 0 : success
|
|
|
|
|
// return -1 : key exist
|
|
|
|
|
// struct health_check *policy : need deep copy
|
|
|
|
|
int health_check_session_add(int session_id, const struct health_check *policy)
|
|
|
|
|
{
|
2023-02-21 21:24:15 +08:00
|
|
|
int ret = 0;
|
|
|
|
|
struct bfd_vtysh_client client;
|
|
|
|
|
struct session_iterm *tmp = NULL;
|
|
|
|
|
|
|
|
|
|
tmp = health_check_get_iterm_by_id(session_id);
|
|
|
|
|
if (tmp) {
|
|
|
|
|
LOG_DEBUG("health check session table insert: key %d exists", session_id);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmp = (struct session_iterm *)calloc(1, sizeof(struct session_iterm));
|
|
|
|
|
assert(tmp);
|
|
|
|
|
|
|
|
|
|
health_check_session_init_bfd_client(&client);
|
|
|
|
|
bfd_vtysh_connect(&client);
|
2023-02-23 21:11:07 +08:00
|
|
|
ret = bfd_vtysh_add_dev(&client, policy->address, policy->retires, policy->interval_ms);
|
2023-02-21 21:24:15 +08:00
|
|
|
if (ret != 0) {
|
2023-02-23 21:11:07 +08:00
|
|
|
LOG_DEBUG("bfd vtysh add dev address [%s] failed!", policy->address);
|
2023-02-21 21:24:15 +08:00
|
|
|
bfd_vtysh_close(&client);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
bfd_vtysh_close(&client);
|
|
|
|
|
|
|
|
|
|
memset(tmp, 0, sizeof(*tmp));
|
|
|
|
|
tmp->session_id = session_id;
|
|
|
|
|
memcpy(&tmp->policy, policy, sizeof(struct health_check));
|
|
|
|
|
|
|
|
|
|
pthread_rwlock_wrlock(&g_handle.rwlock);
|
|
|
|
|
HASH_ADD(hh1, g_handle.root_by_id, session_id, sizeof(tmp->session_id), tmp);
|
|
|
|
|
pthread_rwlock_unlock(&g_handle.rwlock);
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("health check session table insert: key %d success", session_id);
|
2023-02-06 10:34:23 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return 0 : success
|
|
|
|
|
// return -1 : key not exist
|
|
|
|
|
int health_check_session_del(int session_id)
|
|
|
|
|
{
|
2023-02-21 21:24:15 +08:00
|
|
|
int ret = 0;
|
|
|
|
|
struct bfd_vtysh_client client;
|
|
|
|
|
struct session_iterm *tmp = NULL;
|
|
|
|
|
|
|
|
|
|
tmp = health_check_get_iterm_by_id(session_id);
|
|
|
|
|
if (!tmp) {
|
|
|
|
|
LOG_DEBUG("health check session table delete: key %d not exists", session_id);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
health_check_session_init_bfd_client(&client);
|
|
|
|
|
bfd_vtysh_connect(&client);
|
2023-02-23 21:11:07 +08:00
|
|
|
ret = bfd_vtysh_del_dev(&client, tmp->policy.address);
|
2023-02-21 21:24:15 +08:00
|
|
|
if (ret != 0) {
|
|
|
|
|
LOG_DEBUG("bfd vtysh delete dev address [%s] failed!", tmp->policy.address);
|
|
|
|
|
bfd_vtysh_close(&client);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
bfd_vtysh_close(&client);
|
|
|
|
|
|
|
|
|
|
pthread_rwlock_wrlock(&g_handle.rwlock);
|
|
|
|
|
HASH_DELETE(hh1, g_handle.root_by_id, tmp);
|
|
|
|
|
pthread_rwlock_unlock(&g_handle.rwlock);
|
|
|
|
|
free(tmp);
|
|
|
|
|
tmp = NULL;
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("health check session table delete: key %d success", session_id);
|
2023-02-06 10:34:23 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return 1 : active
|
|
|
|
|
// return 0 : inactive
|
|
|
|
|
// return -1 : key not exist
|
|
|
|
|
int health_check_session_get_status(int session_id)
|
|
|
|
|
{
|
2023-02-21 21:24:15 +08:00
|
|
|
int status = 0;
|
|
|
|
|
struct session_iterm *tmp = NULL;
|
|
|
|
|
|
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) {
|
|
|
|
|
LOG_DEBUG("health check session table get status: key %d 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-02-21 21:24:15 +08:00
|
|
|
LOG_DEBUG("health check session get status: %d", status);
|
|
|
|
|
return status;
|
2023-02-06 10:34:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return 0 : success
|
|
|
|
|
// return -1 : key not exist
|
|
|
|
|
int health_check_session_set_status(int session_id, int is_active)
|
|
|
|
|
{
|
2023-02-21 21:24:15 +08:00
|
|
|
struct session_iterm *tmp = NULL;
|
|
|
|
|
|
|
|
|
|
pthread_rwlock_wrlock(&g_handle.rwlock);
|
|
|
|
|
HASH_FIND(hh1, g_handle.root_by_id, &session_id, sizeof(session_id), tmp);
|
|
|
|
|
if (!tmp) {
|
|
|
|
|
LOG_DEBUG("health check session table get status: key %d not exists", session_id);
|
|
|
|
|
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-02-21 21:24:15 +08:00
|
|
|
int sfd, saved_errno, ret;
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
saved_errno = errno;
|
|
|
|
|
ret = ioctl(sfd, SIOCGARP, &arp_req);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
LOG_DEBUG("Get ARP entry failed : %s\n", strerror(errno));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
errno = saved_errno;
|
|
|
|
|
|
|
|
|
|
if (arp_req.arp_flags & ATF_COM)
|
|
|
|
|
memcpy(buf, arp_req.arp_ha.sa_data, HC_MAC_LEN);
|
|
|
|
|
else
|
|
|
|
|
memcpy(buf, default_gw_mac, HC_MAC_LEN);
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
|
|
|
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
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;
|
|
|
|
|
struct bfd_vtysh_client client;
|
|
|
|
|
struct session_iterm *tmp = NULL;
|
|
|
|
|
struct session_iterm *node = NULL;
|
|
|
|
|
|
|
|
|
|
health_check_session_init_bfd_client(&client);
|
|
|
|
|
bfd_vtysh_connect(&client);
|
|
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
|
// TODO: 改为读锁,更新数据入队列,通过写锁更新
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
is_active = bfd_vtysh_get_dev_active(&client, node->policy.address);
|
|
|
|
|
if (is_active == -1)
|
|
|
|
|
continue;
|
|
|
|
|
if (node->is_active != is_active) {
|
|
|
|
|
node->is_active = is_active;
|
|
|
|
|
if (node->is_active == 1) {
|
|
|
|
|
get_mac_by_addr(node->policy.address, node->mac);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
memset(node->mac, 0, sizeof(node->mac));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (sleep_ms > node->policy.interval_ms)
|
|
|
|
|
sleep_ms = node->policy.interval_ms;
|
|
|
|
|
}
|
|
|
|
|
pthread_rwlock_unlock(&g_handle.rwlock);
|
|
|
|
|
usleep(sleep_ms*1000);
|
|
|
|
|
}
|
|
|
|
|
bfd_vtysh_close(&client);
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return 0 : success
|
|
|
|
|
// return -1 : key not exist
|
|
|
|
|
int health_check_session_get_mac(int session_id, char *mac_buff)
|
|
|
|
|
{
|
|
|
|
|
uint8_t *p = NULL;
|
|
|
|
|
struct session_iterm *tmp = NULL;
|
|
|
|
|
|
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) {
|
|
|
|
|
LOG_DEBUG("health check session table get status: key %d 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p = (uint8_t *)tmp->mac;
|
|
|
|
|
snprintf(mac_buff, 18, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2], p[3], p[4], p[5]);
|
2023-02-23 11:13:41 +08:00
|
|
|
pthread_rwlock_unlock(&g_handle.rwlock);
|
2023-02-21 21:24:15 +08:00
|
|
|
LOG_DEBUG("health check session get mac: %s", mac_buff);
|
|
|
|
|
return 0;
|
2023-02-06 10:34:23 +08:00
|
|
|
}
|