This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tango-tsg-service-chaining-…/platform/src/sf_metrics.cpp

219 lines
5.5 KiB
C++
Raw Normal View History

#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <MESA/MESA_prof_load.h>
#include "log.h"
#include "utils.h"
#include "sf_metrics.h"
#define SCE_SF_METRICS "service_chaining_rule_hits,vsys_id=%d,rule_id=%lu,sff_profile_id=%d,sf_profile_id=%d sent_pkts=%lu,sent_bytes=%lu,recv_pkts=%lu,recv_bytes=%lu"
// Must be defined before including uthash.h
#define HASH_KEYCMP(a, b, len) sf_metrics_key_cmp((struct sf_metrics_key *)(a), (struct sf_metrics_key *)(b))
#include "uthash.h"
struct node
{
struct sf_metrics_key key;
uint64_t sent_pkts;
uint64_t sent_bytes;
uint64_t recv_pkts;
uint64_t recv_bytes;
UT_hash_handle hh;
};
struct sf_metrics
{
int enable;
int interval_s;
int telegraf_listen_port;
char telegraf_bind_address[2048];
struct sockaddr_in sock_addr;
int sockfd;
struct node *htable;
uint64_t htable_elem_count;
};
static inline int sf_metrics_key_cmp(struct sf_metrics_key *a, struct sf_metrics_key *b)
{
if (a->sf_profile_id != b->sf_profile_id)
{
return 1;
}
if (a->sff_profile_id != b->sff_profile_id)
{
return 1;
}
if (a->rule_id != b->rule_id)
{
return 1;
}
if (a->vsys_id != b->vsys_id)
{
return 1;
}
return 0;
}
struct sf_metrics *sf_metrics_create(const char *profile)
{
struct sf_metrics *handle = (struct sf_metrics *)calloc(1, sizeof(struct sf_metrics));
assert(handle);
MESA_load_profile_int_def(profile, "METRICS", "enable", &(handle->enable), 1);
MESA_load_profile_int_def(profile, "METRICS", "interval_s", &(handle->interval_s), 1);
MESA_load_profile_int_def(profile, "METRICS", "telegraf_listen_port", &(handle->telegraf_listen_port), 8300);
MESA_load_profile_string_def(profile, "METRICS", "telegraf_bind_address", handle->telegraf_bind_address, sizeof(handle->telegraf_bind_address), "127.0.0.1");
if (handle->enable == 0)
{
return handle;
}
handle->sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
handle->sock_addr.sin_family = AF_INET;
handle->sock_addr.sin_port = htons(handle->telegraf_listen_port);
handle->sock_addr.sin_addr.s_addr = inet_addr(handle->telegraf_bind_address);
handle->htable_elem_count = 0;
if (handle->sockfd == -1)
{
LOG_ERROR("%s: failed to create udp sockfd %s:%d, errno: %d, %s", LOG_TAG_SF_METRICS, handle->telegraf_bind_address, handle->telegraf_listen_port, errno, strerror(errno));
sf_metrics_destory(handle);
return NULL;
}
return handle;
}
void sf_metrics_destory(struct sf_metrics *handle)
{
if (handle)
{
if (handle->sockfd)
{
close(handle->sockfd);
handle->sockfd = -1;
}
struct node *temp = NULL;
struct node *node = NULL;
HASH_ITER(hh, handle->htable, node, temp)
{
HASH_DELETE(hh, handle->htable, node);
free(node);
node = NULL;
}
handle->htable_elem_count = 0;
free(handle);
handle = NULL;
}
}
void sf_metrics_reset(struct sf_metrics *handle)
{
if (handle == NULL)
{
return;
}
if (handle->enable == 0)
{
return;
}
struct node *temp = NULL;
struct node *node = NULL;
HASH_ITER(hh, handle->htable, node, temp)
{
HASH_DELETE(hh, handle->htable, node);
free(node);
node = NULL;
handle->htable_elem_count--;
}
}
void sf_metrics_inc(struct sf_metrics *handle, struct sf_metrics_key *key, uint64_t rx_pkts, uint64_t rx_bytes, uint64_t tx_pkts, uint64_t tx_bytes)
{
if (handle->enable == 0)
{
return;
}
struct node *temp = NULL;
HASH_FIND(hh, handle->htable, key, sizeof(struct sf_metrics_key), temp);
if (temp)
{
temp->recv_pkts += rx_pkts;
temp->recv_bytes += rx_bytes;
temp->sent_pkts += tx_pkts;
temp->sent_bytes += tx_bytes;
}
else
{
temp = (struct node *)calloc(1, sizeof(struct node));
temp->key.vsys_id = key->vsys_id;
temp->key.rule_id = key->rule_id;
temp->key.sff_profile_id = key->sff_profile_id;
temp->key.sf_profile_id = key->sf_profile_id;
temp->recv_pkts = rx_pkts;
temp->recv_bytes = rx_bytes;
temp->sent_pkts = tx_pkts;
temp->sent_bytes = tx_bytes;
HASH_ADD(hh, handle->htable, key, sizeof(struct sf_metrics_key), temp);
}
}
void sf_metrics_send(struct sf_metrics *handle)
{
char buff[2048];
int nsend = 0;
int size = sizeof(buff);
struct node *temp = NULL;
struct node *node = NULL;
if (handle->enable == 0)
{
return;
}
HASH_ITER(hh, handle->htable, node, temp)
{
if (node->sent_pkts == 0 && node->recv_pkts == 0)
{
continue;
}
memset(buff, 0, size);
nsend = snprintf(buff, size, SCE_SF_METRICS,
node->key.vsys_id,
node->key.rule_id,
node->key.sff_profile_id,
node->key.sf_profile_id,
node->sent_pkts,
node->sent_bytes,
node->recv_pkts,
node->recv_bytes);
sendto(handle->sockfd, buff, nsend, 0, (struct sockaddr *)&handle->sock_addr, sizeof(handle->sock_addr));
}
}
int sf_metrics_get_interval(struct sf_metrics *handle)
{
return handle->interval_s;
}