Implement new logging system.

This commit is contained in:
Christian Deacon
2025-02-26 09:56:28 -05:00
parent b943c0d5f7
commit bf761af250
9 changed files with 224 additions and 52 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
xdpfw xdpfw
xdpfw.s xdpfw.s
xdpfw.conf xdpfw.conf
*.log

View File

@@ -13,6 +13,7 @@ LOADER_DIR = $(SRC_DIR)/loader
XDP_DIR = $(SRC_DIR)/xdp XDP_DIR = $(SRC_DIR)/xdp
ETC_DIR = /etc/xdpfw ETC_DIR = /etc/xdpfw
LOG_DIR = /var/log/xdpfw
# Additional build directories. # Additional build directories.
BUILD_LOADER_DIR = $(BUILD_DIR)/loader BUILD_LOADER_DIR = $(BUILD_DIR)/loader
@@ -52,6 +53,9 @@ LOADER_UTILS_CMDLINE_OBJ = cmdline.o
LOADER_UTILS_XDP_SRC = xdp.c LOADER_UTILS_XDP_SRC = xdp.c
LOADER_UTILS_XDP_OBJ = xdp.o LOADER_UTILS_XDP_OBJ = xdp.o
LOADER_UTILS_LOGGING_SRC = logging.c
LOADER_UTILS_LOGGING_OBJ = logging.o
LOADER_UTILS_STATS_SRC = stats.c LOADER_UTILS_STATS_SRC = stats.c
LOADER_UTILS_STATS_OBJ = stats.o LOADER_UTILS_STATS_OBJ = stats.o
@@ -59,7 +63,7 @@ LOADER_UTILS_HELPERS_SRC = helpers.c
LOADER_UTILS_HELPERS_OBJ = helpers.o LOADER_UTILS_HELPERS_OBJ = helpers.o
# Loader objects. # Loader objects.
LOADER_OBJS = $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CMDLINE_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_HELPERS_OBJ) LOADER_OBJS = $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CMDLINE_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_LOGGING_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_HELPERS_OBJ)
ifeq ($(LIBXDP_STATIC), 1) ifeq ($(LIBXDP_STATIC), 1)
LOADER_OBJS := $(LIBBPF_OBJS) $(LIBXDP_OBJS) $(LOADER_OBJS) LOADER_OBJS := $(LIBBPF_OBJS) $(LIBXDP_OBJS) $(LOADER_OBJS)
@@ -93,7 +97,7 @@ all: loader xdp
loader: loader_utils loader: loader_utils
$(CC) $(INCS) $(FLAGS) $(FLAGS_LOADER) -o $(BUILD_LOADER_DIR)/$(LOADER_OUT) $(LOADER_OBJS) $(LOADER_DIR)/$(LOADER_SRC) $(CC) $(INCS) $(FLAGS) $(FLAGS_LOADER) -o $(BUILD_LOADER_DIR)/$(LOADER_OUT) $(LOADER_OBJS) $(LOADER_DIR)/$(LOADER_SRC)
loader_utils: loader_utils_config loader_utils_cmdline loader_utils_helpers loader_utils_xdp loader_utils_stats loader_utils: loader_utils_config loader_utils_cmdline loader_utils_helpers loader_utils_xdp loader_utils_logging loader_utils_stats
loader_utils_config: loader_utils_config:
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_CONFIG_SRC) $(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_CONFIG_SRC)
@@ -104,6 +108,9 @@ loader_utils_cmdline:
loader_utils_xdp: loader_utils_xdp:
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_XDP_SRC) $(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_XDP_SRC)
loader_utils_logging:
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_LOGGING_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_LOGGING_SRC)
loader_utils_stats: loader_utils_stats:
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_STATS_SRC) $(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_STATS_SRC)
@@ -128,6 +135,8 @@ libxdp_clean:
install: install:
mkdir -p $(ETC_DIR) mkdir -p $(ETC_DIR)
mkdir -p $(LOG_DIR)
cp -n xdpfw.conf.example $(ETC_DIR)/xdpfw.conf cp -n xdpfw.conf.example $(ETC_DIR)/xdpfw.conf
cp -n other/xdpfw.service /etc/systemd/system/ cp -n other/xdpfw.service /etc/systemd/system/

View File

@@ -14,6 +14,7 @@
#include <loader/utils/cmdline.h> #include <loader/utils/cmdline.h>
#include <loader/utils/config.h> #include <loader/utils/config.h>
#include <loader/utils/xdp.h> #include <loader/utils/xdp.h>
#include <loader/utils/logging.h>
#include <loader/utils/stats.h> #include <loader/utils/stats.h>
#include <loader/utils/helpers.h> #include <loader/utils/helpers.h>
@@ -37,16 +38,6 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// Raise RLimit.
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if (setrlimit(RLIMIT_MEMLOCK, &rl))
{
fprintf(stderr, "[ERROR] Failed to raise rlimit. Please make sure this program is ran as root!\n");
return EXIT_FAILURE;
}
// Initialize config. // Initialize config.
config__t cfg = {0}; config__t cfg = {0};
@@ -68,54 +59,87 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
LogMsg(&cfg, 2, 0, "Raising RLimit...");
// Raise RLimit.
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if (setrlimit(RLIMIT_MEMLOCK, &rl))
{
LogMsg(&cfg, 0, 1, "[ERROR] Failed to raise rlimit. Please make sure this program is ran as root!\n");
return EXIT_FAILURE;
}
LogMsg(&cfg, 2, 0, "Retrieving interface index for '%s'...", cfg.interface);
// Get interface index. // Get interface index.
int ifidx = if_nametoindex(cfg.interface); int ifidx = if_nametoindex(cfg.interface);
if (ifidx < 0) if (ifidx < 0)
{ {
fprintf(stderr, "[ERROR] Failed to retrieve index of network interface '%s'.\n", cfg.interface); LogMsg(&cfg, 0, 1, "[ERROR] Failed to retrieve index of network interface '%s'.\n", cfg.interface);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
LogMsg(&cfg, 2, 0, "Loading XDP/BPF program at '%s'...", XDP_OBJ_PATH);
// Load BPF object. // Load BPF object.
struct xdp_program *prog = LoadBpfObj(XDP_OBJ_PATH); struct xdp_program *prog = LoadBpfObj(XDP_OBJ_PATH);
if (prog == NULL) if (prog == NULL)
{ {
fprintf(stderr, "[ERROR] Failed to load eBPF object file. Object path => %s.\n", XDP_OBJ_PATH); LogMsg(&cfg, 0, 1, "[ERROR] Failed to load eBPF object file. Object path => %s.\n", XDP_OBJ_PATH);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
LogMsg(&cfg, 2, 0, "Attaching XDP program to interface '%s'...", cfg.interface);
// Attach XDP program. // Attach XDP program.
if ((ret = AttachXdp(prog, ifidx, 0, &cmd)) != 0) char *mode_used = NULL;
if ((ret = AttachXdp(prog, &mode_used, ifidx, 0, &cmd)) != 0)
{ {
fprintf(stderr, "[ERROR] Failed to attach XDP program to interface '%s' (%d).\n", cfg.interface, ret); LogMsg(&cfg, 0, 1, "[ERROR] Failed to attach XDP program to interface '%s' using available modes (%d).\n", cfg.interface, ret);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (mode_used != NULL)
{
LogMsg(&cfg, 1, 0, "Attached XDP program using mode '%s'...", mode_used);
}
LogMsg(&cfg, 2, 0, "Retrieving BPF map FDs...");
// Retrieve BPF maps. // Retrieve BPF maps.
int filters_map = FindMapFd(prog, "filters_map"); int filters_map = FindMapFd(prog, "filters_map");
// Check for valid maps. // Check for valid maps.
if (filters_map < 0) if (filters_map < 0)
{ {
fprintf(stderr, "[ERROR] Failed to find 'filters_map' BPF map.\n"); LogMsg(&cfg, 0, 1, "[ERROR] Failed to find 'filters_map' BPF map.\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
LogMsg(&cfg, 3, 0, "filters_map FD => %d.", filters_map);
int stats_map = FindMapFd(prog, "stats_map"); int stats_map = FindMapFd(prog, "stats_map");
if (stats_map < 0) if (stats_map < 0)
{ {
fprintf(stderr, "[ERROR] Failed to find 'stats_map' BPF map.\n"); LogMsg(&cfg, 0, 1, "[ERROR] Failed to find 'stats_map' BPF map.\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
LogMsg(&cfg, 3, 0, "stats_map FD => %d.", stats_map);
LogMsg(&cfg, 2, 0, "Updating filters...");
// Update BPF maps. // Update BPF maps.
UpdateFilters(filters_map, &cfg); UpdateFilters(filters_map, &cfg);
@@ -126,6 +150,8 @@ int main(int argc, char *argv[])
// Receive CPU count for stats map parsing. // Receive CPU count for stats map parsing.
int cpus = get_nprocs_conf(); int cpus = get_nprocs_conf();
LogMsg(&cfg, 4, 0, "Retrieved %d CPUs on host.", cpus);
unsigned int end_time = (cmd.time > 0) ? time(NULL) + cmd.time : 0; unsigned int end_time = (cmd.time > 0) ? time(NULL) + cmd.time : 0;
// Create last updated variables. // Create last updated variables.
@@ -159,7 +185,7 @@ int main(int argc, char *argv[])
// Update config. // Update config.
if ((ret = LoadConfig(&cfg, cmd.cfgfile)) != 0) if ((ret = LoadConfig(&cfg, cmd.cfgfile)) != 0)
{ {
fprintf(stderr, "[WARNING] Failed to load config after update check (%d)...\n", ret); LogMsg(&cfg, 1, 0, "[WARNING] Failed to load config after update check (%d)...\n", ret);
} }
// Update BPF maps. // Update BPF maps.
@@ -178,7 +204,7 @@ int main(int argc, char *argv[])
{ {
if (CalculateStats(stats_map, cpus)) if (CalculateStats(stats_map, cpus))
{ {
fprintf(stderr, "[WARNING] Failed to calculate packet stats. Stats map FD => %d...\n", stats_map); LogMsg(&cfg, 1, 0, "[WARNING] Failed to calculate packet stats. Stats map FD => %d...\n", stats_map);
} }
} }
@@ -188,14 +214,14 @@ int main(int argc, char *argv[])
fprintf(stdout, "\n"); fprintf(stdout, "\n");
// Detach XDP program. // Detach XDP program.
if (AttachXdp(prog, ifidx, 1, &cmd)) if (AttachXdp(prog, &mode_used, ifidx, 1, &cmd))
{ {
fprintf(stderr, "[ERROR] Failed to detach XDP program from interface '%s'.\n", cfg.interface); LogMsg(&cfg, 0, 1, "[ERROR] Failed to detach XDP program from interface '%s'.\n", cfg.interface);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
fprintf(stdout, "Cleaned up and exiting...\n"); LogMsg(&cfg, 1, 0, "Cleaned up and exiting...\n");
// Exit program successfully. // Exit program successfully.
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@@ -46,6 +46,8 @@ int LoadConfig(config__t *cfg, char *cfg_file)
*/ */
void SetCfgDefaults(config__t *cfg) void SetCfgDefaults(config__t *cfg)
{ {
cfg->verbose = 1;
cfg->log_file = strdup("/var/log/xdpfw/xdpfw.log");
cfg->updatetime = 0; cfg->updatetime = 0;
cfg->interface = NULL; cfg->interface = NULL;
cfg->nostats = 0; cfg->nostats = 0;
@@ -168,6 +170,35 @@ int ReadCfg(config__t *cfg)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
int verbose;
if (config_lookup_int(&conf, "verbose", &verbose) == CONFIG_TRUE)
{
cfg->verbose = verbose;
}
const char* log_file;
if (config_lookup_string(&conf, "log_file", &log_file) == CONFIG_TRUE)
{
// We must free previous value to prevent memory leak.
if (cfg->log_file != NULL)
{
free(cfg->log_file);
cfg->log_file = NULL;
}
if (strlen(log_file) > 0)
{
cfg->log_file = strdup(log_file);
}
else
{
cfg->log_file = NULL;
}
}
// Get interface. // Get interface.
const char *interface; const char *interface;

View File

@@ -13,6 +13,8 @@
struct config struct config
{ {
int verbose;
char *log_file;
char *interface; char *interface;
u16 updatetime; u16 updatetime;
unsigned int nostats : 1; unsigned int nostats : 1;

View File

@@ -0,0 +1,96 @@
#include <loader/utils/logging.h>
/**
* Prints a log message to stdout/stderr along with a file if specified.
*
* @param req_lvl The required level for this message.
* @param cur_lvl The current verbose level.
* @param error If 1, sets pipe to stderr instead of stdout.
* @param msg The log message.
* @param args A VA list of arguments for the message.
*
* @return void
*/
static void LogMsgRaw(int req_lvl, int cur_lvl, int error, const char* log_path, const char* msg, va_list args)
{
if (cur_lvl < req_lvl)
{
return;
}
FILE* pipe = stdout;
if (error)
{
pipe = stderr;
}
// We need to format the message.
va_list args_copy;
va_copy(args_copy, args);
int len = vsnprintf(NULL, 0, msg, args_copy);
va_end(args_copy);
if (len < 0)
{
return;
}
char f_msg[len + 1];
vsnprintf(f_msg, sizeof(f_msg), msg, args);
char full_msg[len + 6 + 1];
snprintf(full_msg, sizeof(full_msg), "[%d] %s", req_lvl, f_msg);
fprintf(pipe, "%s\n", full_msg);
if (log_path != NULL)
{
FILE* log_file = fopen(log_path, "a");
if (!log_file)
{
return;
}
time_t now = time(NULL);
struct tm* tm_val = localtime(&now);
if (!tm_val)
{
fclose(log_file);
return;
}
char log_file_msg[len + 22 + 1];
snprintf(log_file_msg, sizeof(log_file_msg), "[%02d-%02d-%02d %02d:%02d:%02d]%s", tm_val->tm_year % 100, tm_val->tm_mon + 1, tm_val->tm_mday,
tm_val->tm_hour, tm_val->tm_min, tm_val->tm_sec, full_msg);
fprintf(log_file, "%s\n", log_file_msg);
fclose(log_file);
}
}
/**
* Prints a log message using LogMsgRaw().
*
* @param cfg A pointer to the config structure.
* @param req_lvl The required level for this message.
* @param error Whether this is an error.
* @param msg The log message with format support.
*
* @return void
*/
void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...)
{
va_list args;
va_start(args, msg);
LogMsgRaw(req_lvl, cfg->verbose, error, (const char*)cfg->log_file, msg, args);
va_end(args);
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <common/all.h>
#include <loader/utils/config.h>
#include <xdp/libxdp.h>
void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...);

View File

@@ -60,31 +60,32 @@ struct xdp_program *LoadBpfObj(const char *file_name)
* Attempts to attach or detach (progfd = -1) a BPF/XDP program to an interface. * Attempts to attach or detach (progfd = -1) a BPF/XDP program to an interface.
* *
* @param prog A pointer to the XDP program structure. * @param prog A pointer to the XDP program structure.
* @param mode_used The mode being used.
* @param ifidx The index to the interface to attach to. * @param ifidx The index to the interface to attach to.
* @param detach If above 0, attempts to detach XDP program. * @param detach If above 0, attempts to detach XDP program.
* @param cmd A pointer to a cmdline struct that includes command line arguments (mostly checking for offload/HW mode set). * @param cmd A pointer to a cmdline struct that includes command line arguments (mostly checking for offload/HW mode set).
* *
* @return 0 on success and 1 on error. * @return 0 on success and 1 on error.
*/ */
int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd) int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdline_t *cmd)
{ {
int err; int err;
u32 mode = XDP_MODE_NATIVE; u32 attach_mode = XDP_MODE_NATIVE;
char *smode;
smode = "DRV/native"; *mode = "DRV/native";
if (cmd->offload) if (cmd->offload)
{ {
smode = "HW/offload"; *mode = "HW/offload";
mode = XDP_MODE_HW; attach_mode = XDP_MODE_HW;
} }
else if (cmd->skb) else if (cmd->skb)
{ {
smode = "SKB/generic"; *mode = "SKB/generic";
mode = XDP_MODE_SKB;
attach_mode = XDP_MODE_SKB;
} }
int exit = 0; int exit = 0;
@@ -96,39 +97,35 @@ int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd)
if (detach) if (detach)
{ {
err = xdp_program__detach(prog, ifidx, mode, 0); err = xdp_program__detach(prog, ifidx, attach_mode, 0);
} }
else else
{ {
err = xdp_program__attach(prog, ifidx, mode, 0); err = xdp_program__attach(prog, ifidx, attach_mode, 0);
} }
if (err) if (err)
{ {
if (err)
{
fprintf(stderr, "Could not attach with mode %s (%s) (%d).\n", smode, strerror(-err), -err);
}
// Decrease mode. // Decrease mode.
switch (mode) switch (attach_mode)
{ {
case XDP_MODE_HW: case XDP_MODE_HW:
mode = XDP_MODE_NATIVE; attach_mode = XDP_MODE_NATIVE;
smode = "DRV/native"; *mode = "DRV/native";
break; break;
case XDP_MODE_NATIVE: case XDP_MODE_NATIVE:
mode = XDP_MODE_SKB; attach_mode = XDP_MODE_SKB;
smode = "SKB/generic"; *mode = "SKB/generic";
break; break;
case XDP_MODE_SKB: case XDP_MODE_SKB:
// Exit loop. // Exit loop.
exit = 1; exit = 1;
smode = NULL;
*mode = NULL;
break; break;
} }
@@ -142,16 +139,11 @@ int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd)
} }
// If exit is set to 1 or smode is NULL, it indicates full failure. // If exit is set to 1 or smode is NULL, it indicates full failure.
if (exit || smode == NULL) if (exit || *mode == NULL)
{ {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (detach < 1)
{
fprintf(stdout, "Loaded XDP program on mode %s...\n", smode);
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -12,5 +12,5 @@
int FindMapFd(struct xdp_program *prog, const char *map_name); int FindMapFd(struct xdp_program *prog, const char *map_name);
struct xdp_program *LoadBpfObj(const char *file_name); struct xdp_program *LoadBpfObj(const char *file_name);
int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd); int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdline_t *cmd);
void UpdateFilters(int filters_map, config__t *cfg); void UpdateFilters(int filters_map, config__t *cfg);