У меня есть так называемая distributor
программа, которая порождает другую программу af_xdp_user
для каждого IP-адреса, переданного distributor
. Перед этим distributor
создает общую память:
int create_shrd_memory(uint64_t size) {
const int shmid = shmget(SHM_KEY, size, IPC_CREAT | IPC_EXCL);
if(shmid == -1) {
if(errno == EEXIST) {
printf("Shared memory with Key %d already exists, continue...\n", SHM_KEY);
return SHM_KEY;
} else {
fprintf(stderr, "Failed to obtain Shared Memory: %s\n", strerror(errno));
perror("shmget");
exit(1);
}
}
return shmid;
}
Этот ключ общей памяти затем передается каждому подпроцессу в качестве аргумента командной строки (вместе с несколькими другими аргументами):
#define SHM_KEY 0x1235
bool global_exit = false;
static void exit_application(int signal)
{
signal = signal;
global_exit = true;
}
int main(int argc, char **argv) {
const uint8_t amnt_of_ip_addrs = argc - 1;
const int shmid = create_shrd_memory( sizeof(struct stats_record) * amnt_of_ip_addrs );
char shrdmemid[96];
char shrdmemidx[96];
pid_t childs[amnt_of_ip_addrs];
for(uint8_t ip_index = 1; ip_index < argc; ip_index++) {
printf("Forked for IP: %s\n", argv[ip_index]);
pid_t pid = fork();
if(pid == 0) { /* child */
static char argv_child[13][18] = { "af_xdp_user", "--dev", "eth20", "--shrdmem", "", "--shrdmemidx", "", "--progsec", "xdp_sock", "--filename", "af_xdp_kern.o", "-Q", ""};
sprintf(shrdmemid, "%d", shmid);
sprintf(shrdmemidx, "%d", ip_index - 1);
strcpy(argv_child[4], shrdmemid);
strcpy(argv_child[6], shrdmemidx);
strcpy(argv_child[12], shrdmemidx);
printf("Arguments:\n");
for(uint8_t arg_idx = 0; arg_idx < sizeof(argv_child) / sizeof(argv_child[0]); arg_idx++) {
printf("\t%s\n", argv_child[arg_idx]);
}
execl("af_xdp_user", argv_child[0], argv_child[1], argv_child[2], argv_child[3], argv_child[4], argv_child[5], argv_child[6], argv_child[7], argv_child[8], argv_child[9], argv_child[10], NULL);
} else if(pid < 0) {
printf("FORK FAILED!\n");
} else {
// childs[ip_index - 1] = pid;
}
}
signal(SIGINT, exit_application);
while(!global_exit) {
print_statistics(amnt_of_ip_addrs);
sleep(2);
}
}
С print_statistics
- функцией, которая обращается (в будущем ко всем структурам stats_record
) к первой stats_record
-структуре разделяемой памяти и печатает количество полученных пакетов:
void print_statistics(const int amnt_of_processes) {
printf("STATISTICS:\n");
char *shmd = shmat(SHM_KEY, NULL, 0);
struct stats_record *stats = (struct stats_record*)(shmd);
printf("\tREC PACKETS: %lu\n", stats->rx_packets);
}
Каждый подпроцесс с программой af_xdp_user
затем записывает определенную статистику о полученных IP-пакетах в struct stats_record
следующим образом:
char *shm_data = shmat(cfg->shrdmem_id, NULL, 0);
if(shm_data == -1) {
fprintf(stderr, "Failed to obain shared memory: %s\n", strerror(errno));
exit(1);
}
struct stats_record *stats = (struct stats_record*)(shm_data + sizeof(struct stats_record) * cfg->shrdmem_idx);
...
stats->rx_bytes += amnt_of_packets * bytes;
stats->rx_packets += rcvd;
shmdt(shm_data);
Я не знаю, получил ли я идею fork()
верно, но я получаю странный вывод:
$ sudo ./distributor 127.0.0.1
Shared memory with Key 4661 already exists, continue...
Forked for IP: 127.0.0.1
STATISTICS:
Arguments:
af_xdp_user
--dev
eth20
--shrdmem
4661
--shrdmemidx
0
--progsec
xdp_sock
--filename
af_xdp_kern.o
-Q
0
SHRDMEM-ID: 4661
SHRDMEM-IDX: 0
Segmentation fault
$ RX-Queue: 0
...
Failed to obain shared memory: Invalid argument
Обратите внимание на второе $
, которое я получаю в командной строке. На мой взгляд, это означает, что distributor
завершено, но я не знаю, почему оно завершится?