Skip to content

Commit

Permalink
lldpad eloop select change to poll
Browse files Browse the repository at this point in the history
In an environment with 576 virtual NICs, when the function eloop_sock_table_dispatch calls FD_ISSET,
the value of file descriptor table->table[i].sock exceeds 1024 (the kernel fds structure has only 1024 bits).
As a result, the glibc determines that a buffer overflow occurs and aborts the process.

To solve this problem, we change select to poll because poll has no restriction on the fd size.
Poll allows file descriptors to listen to different events, such as POLLIN and POLLOUT.
Therefore, no need to create different queues for different events, we delete writers and exceptions
and rename readers to sock_table.
  • Loading branch information
huyizhen committed Jan 18, 2025
1 parent 3689d5a commit 6cc9c46
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 120 deletions.
144 changes: 53 additions & 91 deletions eloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include "eloop.h"
#include "include/messages.h"

Expand Down Expand Up @@ -69,7 +70,7 @@ int os_get_time(struct os_time *t)


struct eloop_sock {
int sock;
struct pollfd pfd;
void *eloop_data;
void *user_data;
eloop_sock_handler handler;
Expand Down Expand Up @@ -99,11 +100,7 @@ struct eloop_sock_table {
struct eloop_data {
void *user_data;

int max_sock;

struct eloop_sock_table readers;
struct eloop_sock_table writers;
struct eloop_sock_table exceptions;
struct eloop_sock_table sock_table;

struct eloop_timeout *timeout;

Expand All @@ -128,7 +125,7 @@ int eloop_init(void *user_data)


static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
int sock, eloop_sock_handler handler,
struct pollfd pfd, eloop_sock_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_sock *tmp;
Expand All @@ -142,14 +139,12 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
if (tmp == NULL)
return -ENOMEM;

tmp[table->count].sock = sock;
tmp[table->count].pfd = pfd;
tmp[table->count].eloop_data = eloop_data;
tmp[table->count].user_data = user_data;
tmp[table->count].handler = handler;
table->count++;
table->table = tmp;
if (sock > eloop.max_sock)
eloop.max_sock = sock;
table->changed = 1;

return 0;
Expand All @@ -165,7 +160,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
return;

for (i = 0; i < table->count; i++) {
if (table->table[i].sock == sock)
if (table->table[i].pfd.fd == sock)
break;
}
if (i == table->count)
Expand All @@ -181,22 +176,20 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,


static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
fd_set *fds)
struct pollfd *fds)
{
int i;

FD_ZERO(fds);

if (table->table == NULL)
return;

for (i = 0; i < table->count; i++)
FD_SET(table->table[i].sock, fds);
fds[i] = table->table[i].pfd;
}


static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
fd_set *fds)
struct pollfd *fds, int events)
{
int i;

Expand All @@ -205,8 +198,8 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *table,

table->changed = 0;
for (i = 0; i < table->count; i++) {
if (FD_ISSET(table->table[i].sock, fds)) {
table->table[i].handler(table->table[i].sock,
if (fds[i].revents & events) {
table->table[i].handler(table->table[i].pfd.fd,
table->table[i].eloop_data,
table->table[i].user_data);
if (table->changed)
Expand All @@ -220,10 +213,10 @@ static void eloop_sock_table_destroy(struct eloop_sock_table *table)
{
int rc, tc, sock;

if (table) {
if (table->table) {
tc = table->count;
while (tc > 0) {
sock = table->table[tc].sock;
sock = table->table[tc].pfd.fd;
rc = fcntl(sock, F_GETFD);
if (rc != -1) {
rc = close(sock);
Expand All @@ -237,54 +230,34 @@ static void eloop_sock_table_destroy(struct eloop_sock_table *table)
}
}


int eloop_register_read_sock(int sock, eloop_sock_handler handler,
void *eloop_data, void *user_data)
static int eloop_register_sock(struct pollfd pfd,
eloop_sock_handler handler,
void *eloop_data, void *user_data)
{
return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
eloop_data, user_data);
return eloop_sock_table_add_sock(&eloop.sock_table, pfd, handler,
eloop_data, user_data);
}


void eloop_unregister_read_sock(int sock)
int eloop_register_read_sock(int sock, eloop_sock_handler handler,
void *eloop_data, void *user_data)
{
eloop_unregister_sock(sock, EVENT_TYPE_READ);
struct pollfd pfd = {0};
pfd.fd = sock;
pfd.events = POLLIN;
return eloop_register_sock(pfd, handler, eloop_data, user_data);
}


static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
static void eloop_unregister_sock(int sock)
{
switch (type) {
case EVENT_TYPE_READ:
return &eloop.readers;
case EVENT_TYPE_WRITE:
return &eloop.writers;
case EVENT_TYPE_EXCEPTION:
return &eloop.exceptions;
}

return NULL;
eloop_sock_table_remove_sock(&eloop.sock_table, sock);
}


int eloop_register_sock(int sock, eloop_event_type type,
eloop_sock_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_sock_table *table;

table = eloop_get_sock_table(type);
return eloop_sock_table_add_sock(table, sock, handler,
eloop_data, user_data);
}


void eloop_unregister_sock(int sock, eloop_event_type type)
void eloop_unregister_read_sock(int sock)
{
struct eloop_sock_table *table;

table = eloop_get_sock_table(type);
eloop_sock_table_remove_sock(table, sock);
eloop_unregister_sock(sock);
}


Expand Down Expand Up @@ -465,42 +438,39 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
return eloop_register_signal(SIGHUP, handler, user_data);
}

static inline int os_time_to_ms(struct os_time *tv)
{
return ((tv)->sec * 1000 + (tv)->usec / 1000);
}

void eloop_run(void)
{
fd_set *rfds, *wfds, *efds;
int res;
struct timeval _tv;
int res, timeout = 0;
struct os_time tv, now;

rfds = malloc(sizeof(*rfds));
wfds = malloc(sizeof(*wfds));
efds = malloc(sizeof(*efds));
if (rfds == NULL || wfds == NULL || efds == NULL) {
printf("eloop_run - malloc failed\n");
goto out;
}
struct pollfd *fds = NULL;

while (!eloop.terminate &&
(eloop.timeout || eloop.readers.count > 0 ||
eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
(eloop.timeout || eloop.sock_table.count > 0)) {
if (eloop.timeout) {
os_get_time(&now);
if (os_time_before(&now, &eloop.timeout->time))
os_time_sub(&eloop.timeout->time, &now, &tv);
else
tv.sec = tv.usec = 0;
_tv.tv_sec = tv.sec;
_tv.tv_usec = tv.usec;
timeout = os_time_to_ms(&tv);
}

fds = (struct pollfd *)
realloc(fds, eloop.sock_table.count * sizeof(struct eloop_sock));
if (fds == NULL) {
perror("eloop_run realloc");
goto out;
}

eloop_sock_table_set_fds(&eloop.readers, rfds);
eloop_sock_table_set_fds(&eloop.writers, wfds);
eloop_sock_table_set_fds(&eloop.exceptions, efds);
res = select(eloop.max_sock + 1, rfds, wfds, efds,
eloop.timeout ? &_tv : NULL);
eloop_sock_table_set_fds(&eloop.sock_table, fds);
res = poll(fds, eloop.sock_table.count, eloop.timeout ? timeout : -1);
if (res < 0 && errno != EINTR && errno != 0) {
perror("select");
perror("poll");
goto out;
}
eloop_process_pending_signals();
Expand All @@ -522,16 +492,10 @@ void eloop_run(void)

if (res <= 0)
continue;

eloop_sock_table_dispatch(&eloop.readers, rfds);
eloop_sock_table_dispatch(&eloop.writers, wfds);
eloop_sock_table_dispatch(&eloop.exceptions, efds);
eloop_sock_table_dispatch(&eloop.sock_table, fds, POLLIN);
}

out:
free(rfds);
free(wfds);
free(efds);
free(fds);
}


Expand All @@ -551,9 +515,7 @@ void eloop_destroy(void)
timeout = timeout->next;
free(prev);
}
eloop_sock_table_destroy(&eloop.readers);
eloop_sock_table_destroy(&eloop.writers);
eloop_sock_table_destroy(&eloop.exceptions);
eloop_sock_table_destroy(&eloop.sock_table);
free(eloop.signals);
}

Expand All @@ -566,14 +528,14 @@ int eloop_terminated(void)

void eloop_wait_for_read_sock(int sock)
{
fd_set rfds;
struct pollfd pfd;

if (sock < 0)
return;

FD_ZERO(&rfds);
FD_SET(sock, &rfds);
select(sock + 1, &rfds, NULL, NULL, NULL);
pfd.fd = sock;
pfd.events = POLLIN;
poll(&pfd, 1, -1);
}


Expand Down
29 changes: 0 additions & 29 deletions include/eloop.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,35 +111,6 @@ int eloop_register_read_sock(int sock, eloop_sock_handler handler,
*/
void eloop_unregister_read_sock(int sock);

/**
* eloop_register_sock - Register handler for socket events
* @sock: File descriptor number for the socket
* @type: Type of event to wait for
* @handler: Callback function to be called when the event is triggered
* @eloop_data: Callback context data (eloop_ctx)
* @user_data: Callback context data (sock_ctx)
* Returns: 0 on success, -1 on failure
*
* Register an event notifier for the given socket's file descriptor. The
* handler function will be called whenever the that event is triggered for the
* socket. The handler function is responsible for clearing the event after
* having processed it in order to avoid eloop from calling the handler again
* for the same event.
*/
int eloop_register_sock(int sock, eloop_event_type type,
eloop_sock_handler handler,
void *eloop_data, void *user_data);

/**
* eloop_unregister_sock - Unregister handler for socket events
* @sock: File descriptor number for the socket
* @type: Type of event for which sock was registered
*
* Unregister a socket event notifier that was previously registered with
* eloop_register_sock().
*/
void eloop_unregister_sock(int sock, eloop_event_type type);

/**
* eloop_register_event - Register handler for generic events
* @event: Event to wait (eloop implementation specific)
Expand Down

0 comments on commit 6cc9c46

Please sign in to comment.