- Add support for LCP Ident and CallBack (rejection only) from Yuri
- Initiate LCP if not attempted by the client, or in renegotiation - Yuri
- Indentation and style cleanups
+- Per-user upload and download throttle rates - Yuri
+- Make autothrottle.so understand cisco lcp:interface-config - Yuri
+- Show filter stats in show session - Yuri
* Tue Jul 13 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.1
- Update INSTALL, Docs/manual.html documentation.
int __plugin_api_version = 1;
struct pluginfuncs *p;
+#define THROTTLE_KEY "lcp:interface-config"
+
int plugin_radius_response(struct param_radius_response *data)
{
- if (strcmp(data->key, "throttle") == 0)
+ char *t;
+ int i = 0;
+ int rate;
+
+ if (strncmp(data->key, THROTTLE_KEY, strlen(THROTTLE_KEY)) == 0)
+ {
+ char *pt = strdup(data->value);
+ while ((t = strsep(&pt, " ")) != NULL)
+ {
+ if (strcmp(t, "serv") == 0)
+ i = 1;
+ else if (strcmp(t, "o") && i == 1)
+ i = 2;
+ else if (strcmp(t, "i") && i == 1)
+ i = 3;
+ else if (i > 1 && (rate = atoi(t)) > 0)
+ {
+ switch (i)
+ {
+ case 2: // output
+ data->s->throttle |= (rate & 0xFFFF);
+ 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);
+ 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;
+
+ default:
+ p->log(1, 0, p->get_id_by_session(data->s), data->s->tunnel, "Syntax error in rate limit AV pair: %s=%s\n", data->key, data->value);
+ free(pt);
+ return PLUGIN_RET_OK;
+ }
+ }
+ else
+ {
+ free(pt);
+ p->log(1, 0, p->get_id_by_session(data->s), data->s->tunnel, "Syntax error in rate limit AV pair: %s=%s\n",
+ data->key, data->value);
+ return PLUGIN_RET_OK;
+ }
+ }
+ free(pt);
+ }
+ else if (strcmp(data->key, "throttle") == 0)
{
if (strcmp(data->value, "yes") == 0)
{
- p->log(3, 0, 0, 0, " Throttling user\n");
+ p->log(3, 0, p->get_id_by_session(data->s), data->s->tunnel, " Throttling user\n");
data->s->throttle = 1;
}
else if (strcmp(data->value, "no") == 0)
{
- p->log(3, 0, 0, 0, " Not throttling user\n");
+ p->log(3, 0, p->get_id_by_session(data->s), data->s->tunnel, " Not throttling user\n");
data->s->throttle = 0;
}
}
+
+ p->log(4, 0, p->get_id_by_session(data->s), data->s->tunnel, "autothrottle module ignoring AV pair %s=%s\n",
+ data->key, data->value);
+
return PLUGIN_RET_OK;
}
// L2TPNS Command Line Interface
-// vim: sw=4 ts=8
+// vim: sw=8 ts=8
char const *cvs_name = "$Name: $";
-char const *cvs_id_cli = "$Id: cli.c,v 1.12 2004-08-26 04:38:40 fred_nerk Exp $";
+char const *cvs_id_cli = "$Id: cli.c,v 1.13 2004-08-26 06:22:37 fred_nerk Exp $";
#include <stdio.h>
#include <stdarg.h>
#endif
extern struct cli_session_actions *cli_session_actions;
extern struct cli_tunnel_actions *cli_tunnel_actions;
+extern tbft *filter_list;
char *debug_levels[] = {
"CRIT",
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)
close(bgp_peers[i].sock);
#endif /* BGP */
+ if (getpeername(sockfd, (struct sockaddr *)&addr, &l) == 0)
{
- int require_auth = 1;
- struct sockaddr_in addr;
- int l = sizeof(addr);
- 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));
- require_auth = addr.sin_addr.s_addr != inet_addr("127.0.0.1");
- }
- else
- log(0, 0, 0, 0, "getpeername() failed on cli socket. Requiring authentication: %s\n", strerror(errno));
+ log(3, 0, 0, 0, "Accepted connection to CLI from %s\n", inet_toa(addr.sin_addr.s_addr));
+ require_auth = addr.sin_addr.s_addr != inet_addr("127.0.0.1");
+ }
+ else
+ log(0, 0, 0, 0, "getpeername() failed on cli socket. Requiring authentication: %s\n", strerror(errno));
- if (require_auth)
- {
- log(3, 0, 0, 0, "CLI is remote, requiring authentication\n");
- if (!cli->users) /* paranoia */
- {
- log(0, 0, 0, 0, "No users for remote authentication! Exiting CLI\n");
- exit(0);
- }
- }
- else
+ if (require_auth)
+ {
+ log(3, 0, 0, 0, "CLI is remote, requiring authentication\n");
+ if (!cli->users) /* paranoia */
{
- /* no username/pass required */
- cli->users = 0;
+ log(0, 0, 0, 0, "No users for remote authentication! Exiting CLI\n");
+ exit(0);
}
}
+ else
+ {
+ /* no username/pass required */
+ cli->users = 0;
+ }
debug_session = 0;
debug_tunnel = 0;
cli_loop(cli, sockfd);
close(sockfd);
- log(3, 0, 0, 0, "Closed CLI connection\n");
+ log(3, 0, 0, 0, "Closed CLI connection from %s\n", inet_toa(addr.sin_addr.s_addr));
exit(0);
}
// Show individual session
for (i = 0; i < argc; i++)
{
- unsigned int s;
+ unsigned int s, b_in, b_out;
s = atoi(argv[i]);
if (s <= 0 || s >= MAXSESSION)
{
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");
- cli_print(cli, " Filter BucketI: %d", session[s].tbf_in);
- cli_print(cli, " Filter BucketO: %d", session[s].tbf_out);
+ b_in = session[s].tbf_in;
+ b_out = session[s].tbf_out;
+ if (b_in || b_out)
+ cli_print(cli, " %5s %6s %6s | %7s %7s %8s %8s %8s %8s",
+ "Rate", "Credit", "Queued", "ByteIn", "PackIn",
+ "ByteSent", "PackSent", "PackDrop", "PackDelay");
+
+ if (b_in)
+ cli_print(cli, " TBFI#%d%1s %5d %6d %6d | %7d %7d %8d %8d %8d %8d",
+ b_in,
+ (filter_list[b_in].next ? "*" : " "),
+ filter_list[b_in].rate * 8,
+ filter_list[b_in].credit,
+ filter_list[b_in].queued,
+ filter_list[b_in].b_queued,
+ filter_list[b_in].p_queued,
+ filter_list[b_in].b_sent,
+ filter_list[b_in].p_sent,
+ filter_list[b_in].p_dropped,
+ filter_list[b_in].p_delayed);
+
+ if (b_out)
+ cli_print(cli, " TBFO#%d%1s %5d %6d %6d | %7d %7d %8d %8d %8d %8d",
+ b_out,
+ (filter_list[b_out].next ? "*" : " "),
+ filter_list[b_out].rate * 8,
+ filter_list[b_out].credit,
+ filter_list[b_out].queued,
+ filter_list[b_out].b_queued,
+ filter_list[b_out].p_queued,
+ filter_list[b_out].b_sent,
+ filter_list[b_out].p_sent,
+ filter_list[b_out].p_dropped,
+ filter_list[b_out].p_delayed);
+
}
return CLI_OK;
}
int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc)
{
- int i;
+ int rate_in = 0;
+ int rate_out = 0;
sessionidt s;
if (CLI_HELP_REQUESTED)
- return cli_arg_help(cli, argc > 1,
- "USER", "Username of session to throttle", NULL);
+ {
+ switch (argc)
+ {
+ case 1:
+ 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);
+
+ case 3:
+ return cli_arg_help(cli, 1, "rate", "Outgoing rate in kb/s", NULL);
+
+ default:
+ return cli_arg_help(cli, argc > 1, "user", "Username of session to throttle", NULL);
+ }
+ }
if (!config->cluster_iam_master)
{
return CLI_OK;
}
- if (!argc)
+ 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, "Specify a user");
+ cli_print(cli, "User %s is not connected", argv[0]);
return CLI_OK;
}
- for (i = 0; i < argc; i++)
+ if (session[s].throttle)
{
- if (!(s = sessionbyuser(argv[i])))
- {
- cli_print(cli, "User %s is not connected", argv[i]);
- continue;
- }
-
- if (session[s].throttle)
- {
- cli_print(cli, "User %s already throttled", argv[i]);
- continue;
- }
-
- cli_print(cli, "Throttling user %s", argv[i]);
- cli_session_actions[s].throttle = config->rl_rate; // could be configurable at some stage
- cli_session_actions[s].action |= CLI_SESS_THROTTLE;
+ cli_print(cli, "User %s already throttled, unthrottle first", 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;
}
case 3:
if (!argv[2][1])
- return cli_arg_help(cli, 1, NULL);
+ return cli_arg_help(cli, 1, NULL);
default:
return CLI_OK;
// 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.23 2004-08-26 04:43:52 fred_nerk Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.24 2004-08-26 06:22:37 fred_nerk Exp $";
#include <arpa/inet.h>
#include <assert.h>
if (throttle)
{
+ int rate_in = throttle & 0x0000FFFF;
+ int rate_out = throttle >> 16;
+
if (session[s].tbf_in || session[s].tbf_out)
{
if (throttle == session[s].throttle)
free_tbf(session[s].tbf_out);
}
- session[s].tbf_in = new_tbf(s, throttle*1024/4, throttle*1024/8, send_ipin);
- session[s].tbf_out = new_tbf(s, throttle*1024/4, throttle*1024/8, send_ipout);
+ 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)
{
if (a & CLI_SESS_THROTTLE)
{
- log(2, 0, s, session[s].tunnel, "Throttling session by CLI (to %d)\n",
- cli_session_actions[s].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);
}
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
+ 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].pin = session[i].cin = 0;
// L2TPNS: token bucket filters
-char const *cvs_id_tbf = "$Id: tbf.c,v 1.4 2004-07-08 16:54:35 bodea Exp $";
+char const *cvs_id_tbf = "$Id: tbf.c,v 1.5 2004-08-26 06:22:37 fred_nerk Exp $";
#define _GNU_SOURCE
#include "util.h"
#include "tbf.h"
-// Need a time interval.
-
-#define TBF_MAX_QUEUE 2 // Maximum of 2 queued packet per
-#define TBF_MAX_SIZE 3000 // Maxiumum queued packet size is 2048.
-
-#define TBF_MAX_CREDIT 6000 // Maximum 6000 bytes of credit.
-#define TBF_RATE 360 // 360 bytes per 1/10th of a second.
-
-typedef struct {
- int credit;
- int lasttime;
- int queued;
- int oldest; // Position of packet in the ring buffer.
- sessionidt sid; // associated session ID.
- int max_credit; // Maximum amount of credit available (burst size).
- int rate; // How many bytes of credit per second we get? (sustained rate)
- void (*send)(sessionidt s, u8 *, int); // Routine to actually send out the data.
- int prev; // Timer chain position.
- int next; // Timer chain position.
-
- u32 b_queued; // Total bytes sent through this TBF
- u32 b_sent; // Total bytes sucessfully made it to the network.
- u32 p_queued; // ditto packets.
- u32 p_sent; // ditto packets.
- u32 b_dropped; // Total bytes dropped.
- u32 p_dropped; // Total packets dropped.
- u32 p_delayed; // Total packets not sent immediately.
-
- int sizes[TBF_MAX_QUEUE];
- char packets[TBF_MAX_QUEUE][TBF_MAX_SIZE];
-} tbft;
-
-
-static tbft *filter_list = NULL;
+tbft *filter_list = NULL;
static int filter_list_size = 0;
static int timer_chain = -1; // Head of timer chain.
#ifndef __TBF_H__
#define __TBF_H__
+// Need a time interval.
+
+#define TBF_MAX_QUEUE 2 // Maximum of 2 queued packet per
+#define TBF_MAX_SIZE 3000 // Maxiumum queued packet size is 2048.
+
+#define TBF_MAX_CREDIT 6000 // Maximum 6000 bytes of credit.
+#define TBF_RATE 360 // 360 bytes per 1/10th of a second.
+
+typedef struct {
+ int credit;
+ int lasttime;
+ int queued;
+ int oldest; // Position of packet in the ring buffer.
+ sessionidt sid; // associated session ID.
+ int max_credit; // Maximum amount of credit available (burst size).
+ int rate; // How many bytes of credit per second we get? (sustained rate)
+ void (*send)(sessionidt s, u8 *, int); // Routine to actually send out the data.
+ int prev; // Timer chain position.
+ int next; // Timer chain position.
+
+ u32 b_queued; // Total bytes sent through this TBF
+ u32 b_sent; // Total bytes sucessfully made it to the network.
+ u32 p_queued; // ditto packets.
+ u32 p_sent; // ditto packets.
+ u32 b_dropped; // Total bytes dropped.
+ u32 p_dropped; // Total packets dropped.
+ u32 p_delayed; // Total packets not sent immediately.
+
+ int sizes[TBF_MAX_QUEUE];
+ char packets[TBF_MAX_QUEUE][TBF_MAX_SIZE];
+} tbft;
+
void init_tbf(void);
int tbf_run_timer(void);
int tbf_queue_packet(int tbf_id, char * data, int size);