Throttle switching kernel acceleration

Creating/destroying interfaces etc. does take some time. When e.g. receiving
a lot of sessions as new slave, we don't want to stay stuck creating
hundreds of interfaces while we are already receiving control messages
that we have to forward to master not too late. Switching kernel
acceleration can wait a bit most of the time.
This commit is contained in:
Samuel Thibault 2024-01-21 03:09:43 +01:00
parent a22295d804
commit a957ff08ee
2 changed files with 52 additions and 10 deletions

View file

@ -137,6 +137,8 @@ static char time_now_string[64] = {0}; // Current time as a string.
static int time_changed = 0; // time_now changed static int time_changed = 0; // time_now changed
char main_quit = 0; // True if we're in the process of exiting. char main_quit = 0; // True if we're in the process of exiting.
static char main_reload = 0; // Re-load pending static char main_reload = 0; // Re-load pending
#define MAX_KERNEL_SWITCHES 20 // Maximum number of kernel switches per 1/10th second
static int kernel_switches = 0; // How many kernel switches we performed since last cleanup
linked_list *loaded_plugins; linked_list *loaded_plugins;
linked_list *plugins[MAX_PLUGIN_TYPES]; linked_list *plugins[MAX_PLUGIN_TYPES];
@ -1280,7 +1282,8 @@ static int delete_kernel_accel(sessionidt s)
// //
// Enable (set=1) or disable (set=0) kernel PPP acceleration // Enable (set=1) or disable (set=0) kernel PPP acceleration
// This basically calls create/delete_kernel_accel, but also updates routes // This basically calls create/delete_kernel_accel, but also updates routes
static void set_kernel_accel(sessionidt s, int set) // If now is 0, we may delay this if we have already made a lot of switches since last cleanup
static void set_kernel_accel(sessionidt s, int set, int now)
{ {
if (set && !can_kernel_accel(s)) if (set && !can_kernel_accel(s))
/* Still cannot enable it */ /* Still cannot enable it */
@ -1291,6 +1294,16 @@ static void set_kernel_accel(sessionidt s, int set)
/* We don't know the tunnel yet */ /* We don't know the tunnel yet */
return; return;
if (set && !now && kernel_switches >= MAX_KERNEL_SWITCHES)
{
// We already performed many switches, throttle a bit by just
// marking as pending
sess_local[s].needs_switch = 1;
return;
}
kernel_switches++;
sess_local[s].needs_switch = 0;
routesset(s, &session[s], 0); routesset(s, &session[s], 0);
if (session[s].ppp.ipv6cp == Opened) if (session[s].ppp.ipv6cp == Opened)
routes6set(s, &session[s], 0); routes6set(s, &session[s], 0);
@ -1323,7 +1336,7 @@ void switch_kernel_accel(sessionidt s)
return; return;
/* Try to enable */ /* Try to enable */
set_kernel_accel(s, 1); set_kernel_accel(s, 1, 0);
} }
else else
{ {
@ -1334,7 +1347,7 @@ void switch_kernel_accel(sessionidt s)
return; return;
/* Has to disable it */ /* Has to disable it */
set_kernel_accel(s, 0); set_kernel_accel(s, 0, 1);
} }
} }
@ -5805,7 +5818,7 @@ static void mainloop(void)
sessionidt sid; sessionidt sid;
for (sid = 1; sid <= config->cluster_highest_sessionid ; ++sid) for (sid = 1; sid <= config->cluster_highest_sessionid ; ++sid)
if (session[sid].tunnel == tid) if (session[sid].tunnel == tid)
set_kernel_accel(sid, 0); set_kernel_accel(sid, 0, 1);
delete_kernel_tunnel(tid); delete_kernel_tunnel(tid);
} }
@ -5833,12 +5846,12 @@ static void mainloop(void)
if (s < 0) if (s < 0)
{ {
LOG(1, sid, tid, "Error on pppox socket: %s\n", strerror(errno)); LOG(1, sid, tid, "Error on pppox socket: %s\n", strerror(errno));
set_kernel_accel(sid, 0); set_kernel_accel(sid, 0, 1);
} }
else if (s == 0) else if (s == 0)
{ {
LOG(1, sid, tid, "EOF on pppox socket\n"); LOG(1, sid, tid, "EOF on pppox socket\n");
set_kernel_accel(sid, 0); set_kernel_accel(sid, 0, 1);
} }
else else
{ {
@ -5857,12 +5870,12 @@ static void mainloop(void)
if (s < 0) if (s < 0)
{ {
LOG(1, sid, tid, "Error on ppp channel: %s\n", strerror(errno)); LOG(1, sid, tid, "Error on ppp channel: %s\n", strerror(errno));
set_kernel_accel(sid, 0); set_kernel_accel(sid, 0, 1);
} }
else if (s == 0) else if (s == 0)
{ {
LOG(1, sid, tid, "EOF on ppp channel\n"); LOG(1, sid, tid, "EOF on ppp channel\n");
set_kernel_accel(sid, 0); set_kernel_accel(sid, 0, 1);
} }
else else
processppp_from_kernel(sid, p, s, NULL); processppp_from_kernel(sid, p, s, NULL);
@ -5878,12 +5891,12 @@ static void mainloop(void)
if (s < 0) if (s < 0)
{ {
LOG(1, sid, tid, "Error on ppp if: %s\n", strerror(errno)); LOG(1, sid, tid, "Error on ppp if: %s\n", strerror(errno));
set_kernel_accel(sid, 0); set_kernel_accel(sid, 0, 1);
} }
else if (s == 0) else if (s == 0)
{ {
LOG(1, sid, tid, "EOF on ppp if\n"); LOG(1, sid, tid, "EOF on ppp if\n");
set_kernel_accel(sid, 0); set_kernel_accel(sid, 0, 1);
} }
else else
processppp_from_kernel(sid, p, s, NULL); processppp_from_kernel(sid, p, s, NULL);
@ -6051,6 +6064,32 @@ static void mainloop(void)
next_cluster_ping = TIME + config->cluster_hb_interval; next_cluster_ping = TIME + config->cluster_hb_interval;
} }
// Handle trying to enable kernel accel
{
static double last_switch = 0;
double this_switch;
double diff;
TIME = now(&this_switch);
diff = this_switch - last_switch;
// Run during idle time (after we've handled
// all incoming packets) or every 1/10th sec
if (!more || diff > 0.1)
{
kernel_switches = 0;
for (i = 1; i <= config->cluster_highest_sessionid; i++)
{
// Delayed kernel switch
if (session[i].ppp.lcp == Opened && sess_local[i].needs_switch)
set_kernel_accel(i, can_kernel_accel(i), 0);
}
last_switch = this_switch;
}
}
if (!config->cluster_iam_master) if (!config->cluster_iam_master)
continue; continue;

View file

@ -452,6 +452,9 @@ typedef struct
// time in milliseconds of the last fragment. // time in milliseconds of the last fragment.
uint64_t prev_time; uint64_t prev_time;
// Pending kernel switch
int needs_switch;
// l2tp PPPoL2TP socket // l2tp PPPoL2TP socket
int pppox_fd; int pppox_fd;
struct pppol2tp_ioc_stats last_stats; struct pppol2tp_ioc_stats last_stats;