diff --git a/l2tpns.c b/l2tpns.c index e5e877a..04ad4e0 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -137,6 +137,8 @@ static char time_now_string[64] = {0}; // Current time as a string. static int time_changed = 0; // time_now changed char main_quit = 0; // True if we're in the process of exiting. 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 *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 // 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)) /* Still cannot enable it */ @@ -1291,6 +1294,16 @@ static void set_kernel_accel(sessionidt s, int set) /* We don't know the tunnel yet */ 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); if (session[s].ppp.ipv6cp == Opened) routes6set(s, &session[s], 0); @@ -1323,7 +1336,7 @@ void switch_kernel_accel(sessionidt s) return; /* Try to enable */ - set_kernel_accel(s, 1); + set_kernel_accel(s, 1, 0); } else { @@ -1334,7 +1347,7 @@ void switch_kernel_accel(sessionidt s) return; /* 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; for (sid = 1; sid <= config->cluster_highest_sessionid ; ++sid) if (session[sid].tunnel == tid) - set_kernel_accel(sid, 0); + set_kernel_accel(sid, 0, 1); delete_kernel_tunnel(tid); } @@ -5833,12 +5846,12 @@ static void mainloop(void) if (s < 0) { 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) { LOG(1, sid, tid, "EOF on pppox socket\n"); - set_kernel_accel(sid, 0); + set_kernel_accel(sid, 0, 1); } else { @@ -5857,12 +5870,12 @@ static void mainloop(void) if (s < 0) { 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) { LOG(1, sid, tid, "EOF on ppp channel\n"); - set_kernel_accel(sid, 0); + set_kernel_accel(sid, 0, 1); } else processppp_from_kernel(sid, p, s, NULL); @@ -5878,12 +5891,12 @@ static void mainloop(void) if (s < 0) { 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) { LOG(1, sid, tid, "EOF on ppp if\n"); - set_kernel_accel(sid, 0); + set_kernel_accel(sid, 0, 1); } else processppp_from_kernel(sid, p, s, NULL); @@ -6051,6 +6064,32 @@ static void mainloop(void) 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) continue; diff --git a/l2tpns.h b/l2tpns.h index 7c5ad72..59852b9 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -452,6 +452,9 @@ typedef struct // time in milliseconds of the last fragment. uint64_t prev_time; + // Pending kernel switch + int needs_switch; + // l2tp PPPoL2TP socket int pppox_fd; struct pppol2tp_ioc_stats last_stats;