From 14013054f38b44ed80237772299acbd405eb00c3 Mon Sep 17 00:00:00 2001 From: Brendan O'Dea Date: Tue, 2 Nov 2004 04:35:03 +0000 Subject: [PATCH] - Use 2 seperate u16 values for throttle rate in/out - Defer adding radius fds to the select loop until become_master --- Changes | 2 + Makefile | 2 +- autothrottle.c | 8 +- cli.c | 190 ++++++++++++++++++++++++++---------------- cluster.c | 4 +- l2tpns.c | 220 ++++++++++++++++++++++++------------------------- l2tpns.h | 13 +-- util.c | 61 +++++++++++++- util.h | 1 + 9 files changed, 303 insertions(+), 198 deletions(-) diff --git a/Changes b/Changes index 563e646..7f3f45f 100644 --- a/Changes +++ b/Changes @@ -12,6 +12,8 @@ - Shared_malloc returns NULL on failure - Sync changes - Unfsck 4->8 indenting change +- Use 2 seperate u16 values for throttle rate in/out +- Defer adding radius fds to the select loop until become_master * Thu Sep 02 2004 David Parrish 2.0.2 - Combined LCP patches from Iain and Yuri. This should allow Windows 2k/XP diff --git a/Makefile b/Makefile index cfd6e16..d3c9bbd 100644 --- a/Makefile +++ b/Makefile @@ -121,7 +121,7 @@ md5.o: md5.c md5.h ppp.o: ppp.c l2tpns.h constants.h plugin.h util.h tbf.h cluster.h radius.o: radius.c md5.h constants.h l2tpns.h plugin.h util.h tbf.o: tbf.c l2tpns.h util.h tbf.h -util.o: util.c l2tpns.h +util.o: util.c l2tpns.h bgp.h garden.so: garden.c l2tpns.h plugin.h control.h autothrottle.so: autothrottle.c l2tpns.h plugin.h control.h autosnoop.so: autosnoop.c l2tpns.h plugin.h control.h diff --git a/autothrottle.c b/autothrottle.c index 118c03d..65f3ff7 100644 --- a/autothrottle.c +++ b/autothrottle.c @@ -34,13 +34,13 @@ int plugin_radius_response(struct param_radius_response *data) switch (i) { case 2: // output - data->s->throttle |= (rate & 0xFFFF); + data->s->throttle_out = rate; free(pt); p->log(3, 0, p->get_id_by_session(data->s), data->s->tunnel, " Set output throttle rate %dkb/s\n", rate); return PLUGIN_RET_OK; case 3: //input - data->s->throttle |= (rate << 16); + data->s->throttle_in = rate; free(pt); p->log(3, 0, p->get_id_by_session(data->s), data->s->tunnel, " Set input throttle rate %dkb/s\n", rate); return PLUGIN_RET_OK; @@ -66,12 +66,12 @@ int plugin_radius_response(struct param_radius_response *data) if (strcmp(data->value, "yes") == 0) { p->log(3, 0, p->get_id_by_session(data->s), data->s->tunnel, " Throttling user\n"); - data->s->throttle = 1; + data->s->throttle_in = data->s->throttle_out = config->rl_rate; } else if (strcmp(data->value, "no") == 0) { p->log(3, 0, p->get_id_by_session(data->s), data->s->tunnel, " Not throttling user\n"); - data->s->throttle = 0; + data->s->throttle_in = data->s->throttle_out = 0; } } diff --git a/cli.c b/cli.c index c223b91..e8e219f 100644 --- a/cli.c +++ b/cli.c @@ -2,7 +2,7 @@ // vim: sw=8 ts=8 char const *cvs_name = "$Name: $"; -char const *cvs_id_cli = "$Id: cli.c,v 1.19 2004-10-30 07:35:31 bodea Exp $"; +char const *cvs_id_cli = "$Id: cli.c,v 1.20 2004-11-02 04:35:03 bodea Exp $"; #include #include @@ -10,7 +10,6 @@ char const *cvs_id_cli = "$Id: cli.c,v 1.19 2004-10-30 07:35:31 bodea Exp $"; #include #include #include -#include #include #include #include @@ -39,8 +38,6 @@ extern ippoolt *ip_address_pool; extern struct Tstats *_statistics; struct cli_def *cli = NULL; int cli_quit = 0; -extern int clifd, udpfd, tunfd, snoopfd, ifrfd, cluster_sockfd; -extern int *radfds; extern struct configt *config; extern struct config_descriptt config_values[]; #ifdef RINGBUFFER @@ -237,52 +234,11 @@ void init_cli(char *hostname) void cli_do(int sockfd) { - int i; int require_auth = 1; struct sockaddr_in addr; int l = sizeof(addr); - if (fork()) return; - if (config->scheduler_fifo) - { - int ret; - struct sched_param params = {0}; - params.sched_priority = 0; - if ((ret = sched_setscheduler(0, SCHED_OTHER, ¶ms)) == 0) - { - log(3, 0, 0, 0, "Dropped FIFO scheduler\n"); - } - else - { - log(0, 0, 0, 0, "Error setting scheduler to OTHER: %s\n", strerror(errno)); - log(0, 0, 0, 0, "This is probably really really bad.\n"); - } - } - - signal(SIGPIPE, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - signal(SIGHUP, SIG_DFL); - signal(SIGUSR1, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGKILL, SIG_DFL); - signal(SIGALRM, SIG_DFL); - signal(SIGTERM, SIG_DFL); - - // Close sockets - if (udpfd) close(udpfd); udpfd = 0; - if (tunfd) close(tunfd); tunfd = 0; - if (snoopfd) close(snoopfd); snoopfd = 0; - for (i = 0; i < config->num_radfds; i++) - if (radfds[i]) close(radfds[i]); - if (ifrfd) close(ifrfd); ifrfd = 0; - if (cluster_sockfd) close(cluster_sockfd); cluster_sockfd = 0; - if (clifd) close(clifd); clifd = 0; -#ifdef BGP - for (i = 0; i < BGP_NUM_PEERS; i++) - if (bgp_peers[i].sock != -1) - close(bgp_peers[i].sock); -#endif /* BGP */ - + if (fork_and_close()) return; if (getpeername(sockfd, (struct sockaddr *)&addr, &l) == 0) { log(3, 0, 0, 0, "Accepted connection to CLI from %s\n", inet_toa(addr.sin_addr.s_addr)); @@ -412,8 +368,18 @@ int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc) cli_print(cli, " Intercepted: %s:%d", inet_toa(session[s].snoop_ip), session[s] .snoop_port); else cli_print(cli, " Intercepted: no"); - cli_print(cli, " Throttled: %s", session[s].throttle ? "YES" : "no"); + cli_print(cli, " Walled Garden: %s", session[s].walled_garden ? "YES" : "no"); + { + int t = (session[s].throttle_in || session[s].throttle_out); + cli_print(cli, " Throttled: %s%s%.0d%s%s%.0d%s%s", + t ? "YES" : "no", t ? " (" : "", + session[s].throttle_in, session[s].throttle_in ? "kbps" : t ? "-" : "", + t ? "/" : "", + session[s].throttle_out, session[s].throttle_out ? "kbps" : t ? "-" : "", + t ? ")" : ""); + } + b_in = session[s].tbf_in; b_out = session[s].tbf_out; if (b_in || b_out) @@ -454,7 +420,7 @@ int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc) } // Show Summary - cli_print(cli, " %s %4s %-32s %-15s %s %s %s %10s %10s %10s %4s %-15s %s", + cli_print(cli, "%5s %4s %-32s %-15s %s %s %s %10s %10s %10s %4s %-15s %s", "SID", "TID", "Username", @@ -481,7 +447,7 @@ int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc) session[i].user[0] ? session[i].user : "*", userip, (session[i].snoop_ip && session[i].snoop_port) ? "Y" : "N", - (session[i].throttle) ? "Y" : "N", + (session[i].throttle_in || session[i].throttle_out) ? "Y" : "N", (session[i].walled_garden) ? "Y" : "N", abs(time_now - (unsigned long)session[i].opened), (unsigned long)session[i].total_cout, @@ -983,17 +949,26 @@ int cmd_show_throttle(struct cli_def *cli, char *command, char **argv, int argc) if (CLI_HELP_REQUESTED) return CLI_HELP_NO_ARGS; - cli_print(cli, "Token bucket filters:"); - cli_print(cli, "%-6s %8s %-4s", "ID", "Handle", "Used"); + cli_print(cli, "%5s %4s %-32s %7s %6s %6s %6s", + "SID", + "TID", + "Username", + "Rate In", + "Out", + "TBFI", + "TBFO"); + for (i = 0; i < MAXSESSION; i++) { - if (!session[i].throttle) - continue; - - cli_print(cli, "%-6d %8d %8d", - i, - session[i].tbf_in, - session[i].tbf_out); + if (session[i].throttle_in || session[i].throttle_out) + cli_print(cli, "%5d %4d %-32s %6d %6d %6d %6d", + i, + session[i].tunnel, + session[i].user, + session[i].throttle_in, + session[i].throttle_out, + session[i].tbf_in, + session[i].tbf_out); } return CLI_OK; @@ -1275,21 +1250,42 @@ int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc) int rate_out = 0; sessionidt s; + /* + throttle USER - throttle in/out to default rate + throttle USER RATE - throttle in/out to default rate + throttle USER in RATE - throttle input only + throttle USER out RATE - throttle output only + throttle USER in RATE out RATE - throttle both + */ + if (CLI_HELP_REQUESTED) { switch (argc) { case 1: - return cli_arg_help(cli, 0, "user", "Username of session to throttle", NULL); + return cli_arg_help(cli, 0, + "USER", "Username of session to throttle", NULL); case 2: - return cli_arg_help(cli, 1, "rate", "Incoming rate in kb/s", NULL); + return cli_arg_help(cli, 1, + "RATE", "Rate in kbps (in and out)", + "in", "Select incoming rate", + "out", "Select outgoing rate", NULL); + + case 4: + return cli_arg_help(cli, 1, + "in", "Select incoming rate", + "out", "Select outgoing rate", NULL); case 3: - return cli_arg_help(cli, 1, "rate", "Outgoing rate in kb/s", NULL); + if (isdigit(argv[1][0])) + return cli_arg_help(cli, 1, NULL); + + case 5: + return cli_arg_help(cli, 0, "RATE", "Rate in kbps", NULL); default: - return cli_arg_help(cli, argc > 1, "user", "Username of session to throttle", NULL); + return cli_arg_help(cli, argc > 1, NULL); } } @@ -1305,24 +1301,71 @@ int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc) return CLI_OK; } - rate_in = rate_out = config->rl_rate; - if (argc >= 2) rate_in = atoi(argv[1]); - if (argc >= 3) rate_out = atoi(argv[2]); - if (!(s = sessionbyuser(argv[0]))) { cli_print(cli, "User %s is not connected", argv[0]); return CLI_OK; } - if (session[s].throttle) + if (argc == 1) + { + rate_in = rate_out = config->rl_rate; + } + else if (argc == 2) + { + rate_in = rate_out = atoi(argv[1]); + if (rate_in < 1) + { + cli_print(cli, "Invalid rate \"%s\"", argv[1]); + return CLI_OK; + } + } + else if (argc == 3 || argc == 5) + { + int i; + for (i = 1; i < argc - 1; i += 2) + { + int len = strlen(argv[i]); + int r = 0; + if (!strncasecmp(argv[i], "in", len)) + r = rate_in = atoi(argv[i+1]); + else if (!strncasecmp(argv[i], "out", len)) + r = rate_out = atoi(argv[i+1]); + + if (r < 1) + { + cli_print(cli, "Invalid rate specification \"%s %s\"", argv[i], argv[i+1]); + return CLI_OK; + } + } + } + else + { + cli_print(cli, "Invalid arguments"); + return CLI_OK; + } + + if ((rate_in && session[s].throttle_in) || (rate_out && session[s].throttle_out)) { cli_print(cli, "User %s already throttled, unthrottle first", argv[0]); return CLI_OK; } + cli_session_actions[s].throttle_in = cli_session_actions[s].throttle_out = -1; + if (rate_in && session[s].throttle_in != rate_in) + cli_session_actions[s].throttle_in = rate_in; + + if (rate_out && session[s].throttle_out != rate_out) + cli_session_actions[s].throttle_out = rate_out; + + if (cli_session_actions[s].throttle_in == -1 && + cli_session_actions[s].throttle_out == -1) + { + cli_print(cli, "User %s already throttled at this rate", argv[0]); + return CLI_OK; + } + cli_print(cli, "Throttling user %s", argv[0]); - cli_session_actions[s].throttle = rate_in << 16 | rate_out; cli_session_actions[s].action |= CLI_SESS_THROTTLE; return CLI_OK; @@ -1357,14 +1400,15 @@ int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc) continue; } - if (!session[s].throttle) + if (session[s].throttle_in || session[s].throttle_out) + { + cli_print(cli, "Unthrottling user %s", argv[i]); + cli_session_actions[s].action |= CLI_SESS_NOTHROTTLE; + } + else { cli_print(cli, "User %s not throttled", argv[i]); - continue; } - - cli_print(cli, "Unthrottling user %s", argv[i]); - cli_session_actions[s].action |= CLI_SESS_NOTHROTTLE; } return CLI_OK; diff --git a/cluster.c b/cluster.c index 8a46b04..e78ed69 100644 --- a/cluster.c +++ b/cluster.c @@ -1,6 +1,6 @@ // L2TPNS Clustering Stuff -char const *cvs_id_cluster = "$Id: cluster.c,v 1.14 2004-10-30 07:35:00 bodea Exp $"; +char const *cvs_id_cluster = "$Id: cluster.c,v 1.15 2004-11-02 04:35:03 bodea Exp $"; #include #include @@ -589,7 +589,7 @@ void cluster_check_master(void) session[i].tbf_in = session[i].tbf_out = 0; // Remove stale pointers from old master. - throttle_session(i, session[i].throttle); + throttle_session(i, session[i].throttle_in, session[i].throttle_out); if (session[i].tunnel != T_FREE && i > config->cluster_highest_sessionid) config->cluster_highest_sessionid = i; diff --git a/l2tpns.c b/l2tpns.c index 6bd3af7..c0a60a7 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // vim: sw=8 ts=8 -char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.36 2004-10-30 07:17:41 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.37 2004-11-02 04:35:04 bodea Exp $"; #include #include @@ -967,65 +967,48 @@ void controladd(controlt * c, tunnelidt t, sessionidt s) // // Throttle or Unthrottle a session // -// Throttle the data folling through a session -// to be no more than 'throttle' kbit/sec each way. +// Throttle the data from/to through a session to no more than +// 'rate_in' kbit/sec in (from user) or 'rate_out' kbit/sec out (to +// user). // -int throttle_session(sessionidt s, int throttle) +// If either value is -1, the current value is retained for that +// direction. +// +void throttle_session(sessionidt s, int rate_in, int rate_out) { if (!session[s].tunnel) - return 0; // No-one home. + return; // No-one home. if (!*session[s].user) - return 0; // User not logged in + return; // User not logged in - if (throttle) + if (rate_in >= 0) { - int rate_in = throttle & 0x0000FFFF; - int rate_out = throttle >> 16; - - if (session[s].tbf_in || session[s].tbf_out) - { - if (throttle == session[s].throttle) - return 1; - - // Currently throttled but the rate is changing. - + int bytes = rate_in * 1024 / 8; // kbits to bytes + if (session[s].tbf_in) free_tbf(session[s].tbf_in); - free_tbf(session[s].tbf_out); - } - if (rate_in) session[s].tbf_in = new_tbf(s, rate_in * 1024 / 4, rate_in * 1024 / 8, send_ipin); - if (rate_out) session[s].tbf_out = new_tbf(s, rate_out * 1024 / 4, rate_out * 1024 / 8, send_ipout); - - if (throttle != session[s].throttle) - { - // Changed. Flood to slaves. - session[s].throttle = throttle; - cluster_send_session(s); - } + if (rate_in > 0) + session[s].tbf_in = new_tbf(s, bytes * 2, bytes, send_ipin); + else + session[s].tbf_in = 0; - return 1; + session[s].throttle_in = rate_in; } - // else Unthrottling. - - if (!session[s].tbf_in && !session[s].tbf_out && !session[s].throttle) - return 0; - - free_tbf(session[s].tbf_in); - session[s].tbf_in = 0; + if (rate_out >= 0) + { + int bytes = rate_out * 1024 / 8; + if (session[s].tbf_out) + free_tbf(session[s].tbf_out); - free_tbf(session[s].tbf_out); - session[s].tbf_out = 0; + if (rate_out > 0) + session[s].tbf_out = new_tbf(s, bytes * 2, bytes, send_ipin); + else + session[s].tbf_out = 0; - if (throttle != session[s].throttle) - { - // Changed. Flood to slaves. - session[s].throttle = throttle; - cluster_send_session(s); + session[s].throttle_out = rate_out; } - - return 0; } // start tidy shutdown of session @@ -1091,16 +1074,18 @@ void sessionshutdown(sessionidt s, char *reason) } else free_ip_address(s); - - if (session[s].throttle) // Unthrottle if throttled. - throttle_session(s, 0); } + + if (session[s].throttle_in || session[s].throttle_out) // Unthrottle if throttled. + throttle_session(s, 0, 0); + { // Send CDN controlt *c = controlnew(14); // sending CDN control16(c, 1, 3, 1); // result code (admin reasons - TBA make error, general error, add message control16(c, 14, s, 1); // assigned session (our end) controladd(c, session[s].tunnel, s); // send the message } + cluster_send_session(s); } @@ -1159,8 +1144,6 @@ void sessionkill(sessionidt s, char *reason) log(2, 0, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason); - throttle_session(s, 0); // Force session to be un-throttle. Free'ing TBF structures. - memset(&session[s], 0, sizeof(session[s])); session[s].tunnel = T_FREE; // Mark it as free. session[s].next = sessionfree; @@ -1578,7 +1561,7 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr) case 13: // Response // Why did they send a response? We never challenge. log(2, ntohl(addr->sin_addr.s_addr), s, t, " received unexpected challenge response\n"); - break; + break; case 14: // assigned session asession = session[s].far = ntohs(*(u16 *) (b)); @@ -2141,7 +2124,14 @@ int regular_cleanups(void) a = 0; // dead, no need to check for other actions } - if (a & CLI_SESS_SNOOP) + if (a & CLI_SESS_NOSNOOP) + { + log(2, 0, s, session[s].tunnel, "Unsnooping session by CLI\n"); + session[s].snoop_ip = 0; + session[s].snoop_port = 0; + send++; + } + else if (a & CLI_SESS_SNOOP) { log(2, 0, s, session[s].tunnel, "Snooping session by CLI (to %s:%d)\n", inet_toa(cli_session_actions[s].snoop_ip), cli_session_actions[s].snoop_port); @@ -2151,27 +2141,20 @@ int regular_cleanups(void) send++; } - if (a & CLI_SESS_NOSNOOP) + if (a & CLI_SESS_NOTHROTTLE) { - log(2, 0, s, session[s].tunnel, "Unsnooping session by CLI\n"); - session[s].snoop_ip = 0; - session[s].snoop_port = 0; + log(2, 0, s, session[s].tunnel, "Un-throttling session by CLI\n"); + throttle_session(s, 0, 0); send++; } - - if (a & CLI_SESS_THROTTLE) + else if (a & CLI_SESS_THROTTLE) { log(2, 0, s, session[s].tunnel, "Throttling session by CLI (to %dkb/s up and %dkb/s down)\n", - cli_session_actions[s].throttle & 0xFFFF, - cli_session_actions[s].throttle >> 16); - - throttle_session(s, cli_session_actions[s].throttle); - } + cli_session_actions[s].throttle_in, + cli_session_actions[s].throttle_out); - if (a & CLI_SESS_NOTHROTTLE) - { - log(2, 0, s, session[s].tunnel, "Un-throttling session by CLI\n"); - throttle_session(s, 0); + throttle_session(s, cli_session_actions[s].throttle_in, cli_session_actions[s].throttle_out); + send++; } if (send) @@ -2246,11 +2229,13 @@ int still_busy(void) return 0; } +static fd_set readset; +static int readset_n = 0; + // main loop - gets packets on tun or udp and processes them void mainloop(void) { - fd_set cr; - int cn, i; + int i; u8 buf[65536]; struct timeval to; clockt next_cluster_ping = 0; // send initial ping immediately @@ -2259,29 +2244,22 @@ void mainloop(void) log(4, 0, 0, 0, "Beginning of main loop. udpfd=%d, tunfd=%d, cluster_sockfd=%d, controlfd=%d\n", udpfd, tunfd, cluster_sockfd, controlfd); - FD_ZERO(&cr); - FD_SET(udpfd, &cr); - FD_SET(tunfd, &cr); - FD_SET(controlfd, &cr); - FD_SET(clifd, &cr); - if (cluster_sockfd) FD_SET(cluster_sockfd, &cr); - cn = udpfd; - if (cn < tunfd) cn = tunfd; - if (cn < controlfd) cn = controlfd; - if (cn < clifd) cn = clifd; - if (cn < cluster_sockfd) cn = cluster_sockfd; - for (i = 0; i < config->num_radfds; i++) - { - if (!radfds[i]) continue; - FD_SET(radfds[i], &cr); - if (radfds[i] > cn) - cn = radfds[i]; - } + FD_ZERO(&readset); + FD_SET(udpfd, &readset); + FD_SET(tunfd, &readset); + FD_SET(controlfd, &readset); + FD_SET(clifd, &readset); + if (cluster_sockfd) FD_SET(cluster_sockfd, &readset); + readset_n = udpfd; + if (tunfd > readset_n) readset_n = tunfd; + if (controlfd > readset_n) readset_n = controlfd; + if (clifd > readset_n) readset_n = clifd; + if (cluster_sockfd > readset_n) readset_n = cluster_sockfd; while (!main_quit || still_busy()) { fd_set r; - int n = cn; + int n = readset_n; #ifdef BGP fd_set w; int bgp_set[BGP_NUM_PEERS]; @@ -2293,7 +2271,7 @@ void mainloop(void) update_config(); } - memcpy(&r, &cr, sizeof(fd_set)); + memcpy(&r, &readset, sizeof(fd_set)); to.tv_sec = 0; to.tv_usec = 100000; // 1/10th of a second. @@ -2325,7 +2303,8 @@ void mainloop(void) TIME = now(); if (n < 0) { - if (errno == EINTR) + if (errno == EINTR || + errno == ECHILD) // EINTR was clobbered by sigchild_handler() continue; log(0, 0, 0, 0, "Error returned from select(): %s\n", strerror(errno)); @@ -2358,9 +2337,11 @@ void mainloop(void) break; } } - for (i = 0; i < config->num_radfds; i++) - if (FD_ISSET(radfds[i], &r)) - processrad(buf, recv(radfds[i], buf, sizeof(buf), 0), i); + + if (config->cluster_iam_master) + for (i = 0; i < config->num_radfds; i++) + if (FD_ISSET(radfds[i], &r)) + processrad(buf, recv(radfds[i], buf, sizeof(buf), 0), i); if (FD_ISSET(cluster_sockfd, &r)) { @@ -2874,7 +2855,7 @@ void dump_acct_info() for (i = 0; i < MAXSESSION; i++) { - if (!session[i].opened || !session[i].ip || (!session[i].cin && !session[i].cout) || !*session[i].user || session[i].walled_garden) + if (!session[i].opened || !session[i].ip || !(session[i].cin || session[i].cout) || !*session[i].user || session[i].walled_garden) continue; if (!f) { @@ -2897,11 +2878,11 @@ void dump_acct_info() log(4, 0, 0, 0, "Dumping accounting information for %s\n", session[i].user); fprintf(f, "%s %s %d %u %u\n", - session[i].user, // username - inet_toa(htonl(session[i].ip)), // ip - (session[i].throttle) ? 2 : 1, // qos - (u32)session[i].cin, // uptxoctets - (u32)session[i].cout); // downrxoctets + session[i].user, // username + inet_toa(htonl(session[i].ip)), // ip + (session[i].throttle_in || session[i].throttle_out) ? 2 : 1, // qos + (u32)session[i].cin, // uptxoctets + (u32)session[i].cout); // downrxoctets session[i].pin = session[i].cin = 0; session[i].pout = session[i].cout = 0; @@ -3599,10 +3580,9 @@ int sessionsetup(tunnelidt t, sessionidt s) run_plugins(PLUGIN_NEW_SESSION, &data); } - // Force throttling on or off (Actually : refresh the current throttling status) - // This has the advantage of cleaning up after another throttled user who may have left - // firewall rules lying around - throttle_session(s, session[s].throttle); + // Allocate TBFs if throttled + if (session[s].throttle_in || session[s].throttle_out) + throttle_session(s, session[s].throttle_in, session[s].throttle_out); session[s].last_packet = time_now; @@ -3691,6 +3671,12 @@ int load_session(sessionidt s, sessiont *new) // for walking the sessions to forward byte counts to the master. config->cluster_highest_sessionid = s; + // TEMP: old session struct used a u32 to define the throttle + // speed for both up/down, new uses a u16 for each. Deal with + // sessions from an old master for migration. + if (new->throttle_out == 0 && new->tbf_out) + new->throttle_out = new->throttle_in; + memcpy(&session[s], new, sizeof(session[s])); // Copy over.. // Do fixups into address pool. @@ -3946,19 +3932,33 @@ tunnelidt new_tunnel() // void become_master(void) { - int s; + int s, i; run_plugins(PLUGIN_BECOME_MASTER, NULL); - for (s = 1; s <= config->cluster_highest_sessionid ; ++s) + // running a bunch of iptables commands is slow and can cause + // the master to drop tunnels on takeover--kludge around the + // problem by forking for the moment (note: race) + if (!fork_and_close()) { - if (!session[s].tunnel) // Not an in-use session. - continue; + for (s = 1; s <= config->cluster_highest_sessionid ; ++s) + { + if (!session[s].tunnel) // Not an in-use session. + continue; - run_plugins(PLUGIN_NEW_SESSION_MASTER, &session[s]); + run_plugins(PLUGIN_NEW_SESSION_MASTER, &session[s]); + } + exit(0); } -} - + // add radius fds + for (i = 0; i < config->num_radfds; i++) + { + if (!radfds[i]) continue; + FD_SET(radfds[i], &readset); + if (radfds[i] > readset_n) + readset_n = radfds[i]; + } +} int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc) { diff --git a/l2tpns.h b/l2tpns.h index bc6938f..3e7573e 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1,5 +1,5 @@ // L2TPNS Global Stuff -// $Id: l2tpns.h,v 1.25 2004-10-30 07:17:41 bodea Exp $ +// $Id: l2tpns.h,v 1.26 2004-11-02 04:35:04 bodea Exp $ #ifndef __L2TPNS_H__ #define __L2TPNS_H__ @@ -122,7 +122,8 @@ struct cli_session_actions { char action; ipt snoop_ip; u16 snoop_port; - int throttle; + int throttle_in; + int throttle_out; }; #define CLI_SESS_KILL 0x01 @@ -172,7 +173,8 @@ typedef struct sessions u32 total_cin; // This counter is never reset while a session is open u32 total_cout; // This counter is never reset while a session is open u32 id; // session id - u32 throttle; // non-zero if this session is throttled. + u16 throttle_in; // upstream throttle rate (kbps) + u16 throttle_out; // downstream throttle rate clockt opened; // when started clockt die; // being closed, when to finally free time_t last_packet; // Last packet from the user (used for idle timeouts) @@ -419,7 +421,7 @@ struct configt ipt default_dns1, default_dns2; - unsigned long rl_rate; // throttle rate + unsigned long rl_rate; // default throttle rate int num_tbfs; // number of throttle buckets int save_state; @@ -565,7 +567,7 @@ void host_unreachable(ipt destination, u16 id, ipt source, char *packet, int pac void fix_address_pool(int sid); void rebuild_address_pool(void); void send_ipin(sessionidt s, u8 * buf, int len); -int throttle_session(sessionidt s, int throttle); +void throttle_session(sessionidt s, int rate_in, int rate_out); int load_session(sessionidt, sessiont *); void become_master(void); // We're the master; kick off any required master initializations. extern tunnelt *tunnel; @@ -597,6 +599,7 @@ extern u32 last_id; extern struct Tstats *_statistics; extern ipt my_address; extern int tun_write(u8 *data, int size); +extern int clifd; #define TIME (config->current_time) diff --git a/util.c b/util.c index 8ba99a0..572af84 100644 --- a/util.c +++ b/util.c @@ -1,15 +1,21 @@ /* Misc util functions */ -char const *cvs_id_util = "$Id: util.c,v 1.3 2004-09-02 04:18:07 fred_nerk Exp $"; - -#include "l2tpns.h" +char const *cvs_id_util = "$Id: util.c,v 1.4 2004-11-02 04:35:04 bodea Exp $"; +#include +#include +#include #include #include #include #include #include +#include "l2tpns.h" +#ifdef BGP +#include "bgp.h" +#endif + char *inet_toa(unsigned long addr) { struct in_addr in; @@ -27,3 +33,52 @@ void *shared_malloc(unsigned int size) return p; } + +extern int udpfd, tunfd, snoopfd, ifrfd, cluster_sockfd; +extern int *radfds; + +pid_t fork_and_close() +{ + pid_t pid = fork(); + int i; + + if (pid) + return pid; + + if (config->scheduler_fifo) + { + struct sched_param params = {0}; + params.sched_priority = 0; + if (sched_setscheduler(0, SCHED_OTHER, ¶ms)) + { + log(0, 0, 0, 0, "Error setting scheduler to OTHER after fork: %s\n", strerror(errno)); + log(0, 0, 0, 0, "This is probably really really bad.\n"); + } + } + + signal(SIGPIPE, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGUSR1, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGKILL, SIG_DFL); + signal(SIGALRM, SIG_DFL); + signal(SIGTERM, SIG_DFL); + + // Close sockets + if (udpfd) close(udpfd); udpfd = 0; + if (tunfd) close(tunfd); tunfd = 0; + if (snoopfd) close(snoopfd); snoopfd = 0; + for (i = 0; i < config->num_radfds; i++) + if (radfds[i]) close(radfds[i]); + if (ifrfd) close(ifrfd); ifrfd = 0; + if (cluster_sockfd) close(cluster_sockfd); cluster_sockfd = 0; + if (clifd) close(clifd); clifd = 0; +#ifdef BGP + for (i = 0; i < BGP_NUM_PEERS; i++) + if (bgp_peers[i].sock != -1) + close(bgp_peers[i].sock); +#endif /* BGP */ + + return pid; +} diff --git a/util.h b/util.h index 21c82a3..5fe9d4f 100644 --- a/util.h +++ b/util.h @@ -3,5 +3,6 @@ char *inet_toa(unsigned long addr); void *shared_malloc(unsigned int size); +pid_t fork_and_close(void); #endif /* __UTIL_H__ */ -- 2.20.1