Skip to content

Commit

Permalink
Update loading and chaining of the ipfix flow exporter
Browse files Browse the repository at this point in the history
Signed-off-by: Santhosh Fernandes <[email protected]>
  • Loading branch information
sanfern committed Oct 2, 2023
1 parent a300dc3 commit c42da87
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 367 deletions.
70 changes: 28 additions & 42 deletions ipfix-flow-exporter/bpf_ipfix_egress_kern.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright Contributors to the L3AF Project.
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)

#define KBUILD_MODNAME "foo"

#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
Expand All @@ -16,49 +18,9 @@
#include "bpf_ipfix_kern_common.h"

#define DEBUG 1

#define EGRESS 1

#define ICMP 1

#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})

#define PIN_GLOBAL_NS 2
#define PIN_OBJECT_NS 1


/* EGRESS MAP FOR FLOW RECORD INFO */
struct bpf_elf_map SEC("maps") egress_flow_record_info_map = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(u32),
.size_value = sizeof(flow_record_t),
.pinning = PIN_GLOBAL_NS,
.max_elem = 30000,
};

/* EGRESS MAP FOR LAST RECORD PACKET INFO */
struct bpf_elf_map SEC("maps") last_egress_flow_record_info_map = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(u32),
.size_value = sizeof(flow_record_t),
.pinning = PIN_GLOBAL_NS,
.max_elem = 30000,
};

/* EGRESS MAP FOR CHAINING */
struct bpf_elf_map SEC("maps") ipfix_egress_jmp_table = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.size_key = sizeof(u32),
.size_value = sizeof(u32),
.pinning = PIN_GLOBAL_NS,
.max_elem = 1
};

#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
Expand All @@ -79,12 +41,36 @@ struct bpf_elf_map SEC("maps") ipfix_egress_jmp_table = {

#define TCP_FLAGS (TCP_FIN|TCP_SYN|TCP_RST|TCP_ACK|TCP_URG|TCP_ECE|TCP_CWR)

/* EGRESS MAP FOR FLOW RECORD INFO */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, flow_record_t);
__uint(max_entries, 30000);
} egress_flow_record_info_map SEC(".maps");

/* EGRESS MAP FOR LAST RECORD PACKET INFO */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, flow_record_t);
__uint(max_entries, 30000);
} last_egress_flow_record_info_map SEC(".maps");

/* EGRESS MAP FOR CHAINING */
struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__type(key, u32);
__type(value, u32);
__uint(max_entries, 1);
} ipfix_egress_jmp_table SEC(".maps");

static u32 flow_key_hash (const flow_key_t f) {
u32 hash_val = (((u32)f.sa * 0xef6e15aa)
^((u32)f.da * 0x65cd52a0)
^ ((u32)f.sp * 0x8216)
^ ((u32)f.dp * 0xdda37)
^ ((u32)f.prot * 0xbc06)) ;
^ ((u32)f.prot * 0xbc06));
return hash_val;
}

Expand Down Expand Up @@ -305,7 +291,7 @@ static __always_inline bool parse_egress_eth(struct ethhdr *eth, void *data_end,
return true;
}

SEC("egress_flow_monitoring")
SEC("tc_egress_flow_monitoring")
int _egress_flow_monitoring(struct __sk_buff *skb)
{
void *data = (void *)(long)skb->data;
Expand Down
78 changes: 16 additions & 62 deletions ipfix-flow-exporter/bpf_ipfix_egress_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,33 @@ static const char *__doc__=" BPF IPFIX : To get packet flow data by handling the
#define EXIT_OK 0
#define EXIT_FAIL 1

const char egress[] = "egress_flow_monitoring";

/* Ingress Specific variables */
bool attach_tc_egress_filter = false;
char if_name[IF_NAMESIZE];
char *egress_log_file_path = "/var/log/tb/l3af/egress_ipfix.log";
char *egress_log_file_path = "/var/log/l3af/egress_ipfix.log";

void sig_handler(int signo)
{
log_info("Received shutdown signal, cleaning up");
flow_record_poll(egress_fd, last_egress_fd, EGRESS);
if (attach_tc_egress_filter)
tc_cleanup(chain, if_name, EGRESS, egress_bpf_map, last_egress_bpf_map, bpf_map_file_path, ipfix_egress_jmp_table);
log_info("Cleaned up");
close_logfile();
exit(EXIT_SUCCESS);
}

int populate_egress_fds(void) {
egress_fd = bpf_obj_get(egress_bpf_map);
char map_file[MAP_PATH_SIZE];
get_bpf_map_file(if_name, egress_bpf_map, map_file);

egress_fd = bpf_obj_get(&map_file);
if (egress_fd < 0) {
fprintf(stderr, "ERROR: cannot open bpf_obj_get(%s)",
egress_bpf_map);
close_logfile();
return EXIT_FAILURE;
}

last_egress_fd = bpf_obj_get(last_egress_bpf_map);
get_bpf_map_file(if_name, last_egress_bpf_map, map_file);
last_egress_fd = bpf_obj_get(&map_file);
if (last_egress_fd < 0) {
fprintf(stderr, "ERROR: cannot open bpf_obj_get(%s)", last_egress_bpf_map);
close_logfile();
Expand All @@ -53,23 +52,13 @@ int main(int argc, char **argv)
{
char filename[256];
int opt = 0, long_index = 0, l = 0;
bool remove_egress_tc_filter = false;
verbosity = LOG_INFO;
long flow_timeout = 0;
char *eptr;
/* Parse commands line args */
while ((opt = getopt_long(argc, argv, "hq",
long_options, &long_index)) != -1) {
switch (opt) {
case 'm':
if(optarg){
bpf_map_file_path = (char *) malloc(1 + strnlen(optarg, MAX_FILENAME_LENGTH));
cpy(optarg, bpf_map_file_path);
if(!validate_map_name(bpf_map_file_path))
return EXIT_FAILURE;
chain = true;
}
break;
case 'q':
if(optarg)
verbosity = (int)(strtol(optarg, &eptr, 10));
Expand All @@ -85,7 +74,6 @@ int main(int argc, char **argv)
if_name);
return EXIT_FAILURE;
}
attach_tc_egress_filter = true;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
l = get_length(filename);
filename[l] = '\0';
Expand All @@ -94,22 +82,10 @@ int main(int argc, char **argv)
if(optarg)
remote_ip = optarg;
break;
case 'r':
if (optarg &&
(!validate_ifname(optarg, (char *)&if_name))) {
log_err("ERR: input --remove=ifname invalid");
return EXIT_FAILURE;
}
if (get_length(if_name) == 0) {
log_err("ERR: need input --list=ifname");
return EXIT_FAILURE;
}
remove_egress_tc_filter = true;
break;
case 't':
if(optarg) {
flow_timeout = strtol(optarg, &eptr, 10);
flow_timeout_counter = flow_timeout / 10;
flow_timeout_counter = flow_timeout / 10;
}
break;
case 'p':
Expand All @@ -132,37 +108,15 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}

if(attach_tc_egress_filter) {
if(chain == true){
if (tc_chain_bpf(bpf_map_file_path, filename, egress) != 1) {
fprintf(stderr, "ERR: tc chain egress failed \n");
close_logfile();
return EXIT_FAILURE;
}
}
else {
if (tc_attach_filter(if_name, filename, EGRESS, egress) != 1) {
fprintf(stderr, "ERR: TC EGRESS filter attach failed\n");
close_logfile();
return EXIT_FAILURE;
}
}
if (populate_egress_fds() == EXIT_FAILURE) {
fprintf(stderr, "ERR: Fetching TC EGRESS maps failed\n");
close_logfile();
return EXIT_FAILURE;
}
if (remote_ip == NULL) {
log_info("Remote IP is not configured by user, so configuring localhost as remote_ip");
remote_ip = "127.0.0.1" ;
}
if (populate_egress_fds() == EXIT_FAILURE) {
fprintf(stderr, "ERR: Fetching TC EGRESS maps failed\n");
close_logfile();
return EXIT_FAILURE;
}

if (remove_egress_tc_filter) {
log_debug("TC remove egress filters on device %s",
if_name);
tc_remove_filter(if_name, EGRESS);
return EXIT_SUCCESS;
if (remote_ip == NULL) {
log_err("Remote IP is not configured by user, Please provide the remote ip");
close_logfile();
return EXIT_FAILURE;
}

if (signal(SIGINT, sig_handler) ||
Expand Down
69 changes: 29 additions & 40 deletions ipfix-flow-exporter/bpf_ipfix_ingress_kern.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright Contributors to the L3AF Project.
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)

#define KBUILD_MODNAME "foo"

#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
Expand All @@ -19,44 +21,6 @@
#define INGRESS 0
#define ICMP 1

#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})

#define PIN_GLOBAL_NS 2
#define PIN_OBJECT_NS 1


/* INGRESS MAP FOR FLOW RECORD INFO */
struct bpf_elf_map SEC("maps") ingress_flow_record_info_map = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(u32),
.size_value = sizeof(flow_record_t),
.pinning = PIN_GLOBAL_NS,
.max_elem = 30000,
};

/* INGRESS MAP FOR LAST RECORD PACKET INFO */
struct bpf_elf_map SEC("maps") last_ingress_flow_record_info_map = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(u32),
.size_value = sizeof(flow_record_t),
.pinning = PIN_GLOBAL_NS,
.max_elem = 30000,
};

/* INGRESS MAP FOR CHAINING */
struct bpf_elf_map SEC("maps") ipfix_ingress_jmp_table = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.size_key = sizeof(u32),
.size_value = sizeof(u32),
.pinning = PIN_GLOBAL_NS,
.max_elem = 1
};

#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
Expand All @@ -77,12 +41,37 @@ struct bpf_elf_map SEC("maps") ipfix_ingress_jmp_table = {

#define TCP_FLAGS (TCP_FIN|TCP_SYN|TCP_RST|TCP_ACK|TCP_URG|TCP_ECE|TCP_CWR)

/* INGRESS MAP FOR FLOW RECORD INFO */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, flow_record_t);
__uint(max_entries, 30000);
} ingress_flow_record_info_map SEC(".maps");


/* INGRESS MAP FOR LAST RECORD PACKET INFO */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, flow_record_t);
__uint(max_entries, 30000);
} last_ingress_flow_record_info_map SEC(".maps");

/* INGRESS MAP FOR CHAINING */
struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__type(key, u32);
__type(value, u32);
__uint(max_entries, 1);
} ipfix_ingress_jmp_table SEC(".maps");

static u32 flow_key_hash (const flow_key_t f) {
u32 hash_val = (((u32)f.sa * 0xef6e15aa)
^((u32)f.da * 0x65cd52a0)
^ ((u32)f.sp * 0x8216)
^ ((u32)f.dp * 0xdda37)
^ ((u32)f.prot * 0xbc06)) ;
^ ((u32)f.prot * 0xbc06));
return hash_val;
}

Expand Down Expand Up @@ -303,7 +292,7 @@ static __always_inline bool parse_ingress_eth(struct ethhdr *eth, void *data_end
return true;
}

SEC("ingress_flow_monitoring")
SEC("tc_ingress_flow_monitoring")
int _ingress_flow_monitoring(struct __sk_buff *skb)
{
void *data = (void *)(long)skb->data;
Expand Down
Loading

0 comments on commit c42da87

Please sign in to comment.