* Wed Jun 23 2004 David Parrish <david@dparrish.com> 2.0.0
[l2tpns.git] / cli.c
diff --git a/cli.c b/cli.c
index af73a6c..892b8d1 100644 (file)
--- a/cli.c
+++ b/cli.c
@@ -1,5 +1,5 @@
 // L2TPNS Command Line Interface
-// $Id: cli.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
+// $Id: cli.c,v 1.5 2004-06-23 03:52:24 fred_nerk Exp $
 // vim: sw=4 ts=8
 
 #include <stdio.h>
@@ -7,6 +7,7 @@
 #include <sys/stat.h>
 #include <syslog.h>
 #include <malloc.h>
+#include <sched.h>
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
 #include <sys/types.h>
 #include <signal.h>
 #include <unistd.h>
+#include <libcli.h>
 #include "l2tpns.h"
-#include "libcli.h"
 #include "util.h"
+#include "cluster.h"
+#include "tbf.h"
+#ifdef BGP
+#include "bgp.h"
+#endif
 
 extern tunnelt *tunnel;
 extern sessiont *session;
 extern radiust *radius;
 extern ippoolt *ip_address_pool;
 extern struct Tstats *_statistics;
-extern int cli_pid;
 struct cli_def *cli = NULL;
 int cli_quit = 0;
-extern int clifd, udpfd, tapfd, snoopfd, radfd, ifrfd, cluster_sockfd;
+extern int clifd, udpfd, tapfd, snoopfd, ifrfd, cluster_sockfd;
+extern int *radfds;
 extern sessionidt *cli_session_kill;
 extern tunnelidt *cli_tunnel_kill;
-extern tbft *filter_buckets;
 extern struct configt *config;
 extern struct config_descriptt config_values[];
 extern char hostname[];
@@ -39,7 +44,7 @@ extern char hostname[];
 extern struct Tringbuffer *ringbuffer;
 #endif
 
-char *rcs_id = "$Id: cli.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $";
+char *rcs_id = "$Id: cli.c,v 1.5 2004-06-23 03:52:24 fred_nerk Exp $";
 
 char *debug_levels[] = {
     "CRIT",
@@ -75,6 +80,8 @@ int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_throttle(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_cluster(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc);
@@ -86,8 +93,6 @@ int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_debug(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_no_debug(struct cli_def *cli, char *command, char **argv, int argc);
-int cmd_watch_session(struct cli_def *cli, char *command, char **argv, int argc);
-int cmd_watch_tunnel(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_set(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, int argc);
@@ -99,21 +104,33 @@ void init_cli()
     FILE *f;
     char buf[4096];
     struct cli_command *c;
+    struct cli_command *c2;
     int on = 1;
     struct sockaddr_in addr;
 
     cli = cli_init();
 
     c = cli_register_command(cli, NULL, "show", NULL, NULL);
-    cli_register_command(cli, c, "session", cmd_show_session, "Show a list of sessions or details for a single session");
-    cli_register_command(cli, c, "tunnels", cmd_show_tunnels, "Show a list of tunnels or details for a single tunnel");
-    cli_register_command(cli, c, "users", cmd_show_users, "Show a list of all connected users");
-    cli_register_command(cli, c, "version", cmd_show_version, "Show currently running software version");
     cli_register_command(cli, c, "banana", cmd_show_banana, "Show a banana");
+#ifdef BGP
+    cli_register_command(cli, c, "bgp", cmd_show_bgp, "Show BGP status");
+#endif /* BGP */
+    cli_register_command(cli, c, "cluster", cmd_show_cluster, "Show cluster information");
+    cli_register_command(cli, c, "ipcache", cmd_show_ipcache, "Show contents of the IP cache");
+    cli_register_command(cli, c, "plugins", cmd_show_plugins, "List all installed plugins");
     cli_register_command(cli, c, "pool", cmd_show_pool, "Show the IP address allocation pool");
-    cli_register_command(cli, c, "running-config", cmd_show_run, "Show the currently running configuration");
     cli_register_command(cli, c, "radius", cmd_show_radius, "Show active radius queries");
-    cli_register_command(cli, c, "plugins", cmd_show_plugins, "List all installed plugins");
+    cli_register_command(cli, c, "running-config", cmd_show_run, "Show the currently running configuration");
+    cli_register_command(cli, c, "session", cmd_show_session, "Show a list of sessions or details for a single session");
+    cli_register_command(cli, c, "tbf", cmd_show_tbf, "List all token bucket filters in use");
+    cli_register_command(cli, c, "throttle", cmd_show_throttle, "List all throttled sessions and associated TBFs");
+    cli_register_command(cli, c, "tunnels", cmd_show_tunnels, "Show a list of tunnels or details for a single tunnel");
+    cli_register_command(cli, c, "users", cmd_show_users, "Show a list of all connected users or details of selected user");
+    cli_register_command(cli, c, "version", cmd_show_version, "Show currently running software version");
+
+    c2 = cli_register_command(cli, c, "histogram", NULL, NULL);
+    cli_register_command(cli, c2, "idle", cmd_show_hist_idle, "Show histogram of session idle times");
+    cli_register_command(cli, c2, "open", cmd_show_hist_open, "Show histogram of session durations");
 
 #ifdef STATISTICS
     cli_register_command(cli, c, "counters", cmd_show_counters, "Display all the internal counters and running totals");
@@ -130,24 +147,25 @@ void init_cli()
 
     cli_register_command(cli, NULL, "snoop", cmd_snoop, "Temporarily enable interception for a user");
     cli_register_command(cli, NULL, "throttle", cmd_throttle, "Temporarily enable throttling for a user");
+    cli_register_command(cli, NULL, "debug", cmd_debug, "Set the level of logging that is shown on the console");
+
+    c = cli_register_command(cli, NULL, "suspend", NULL, NULL);
+    cli_register_command(cli, c, "bgp", cmd_suspend_bgp, "Withdraw routes from BGP peer");
 
     c = cli_register_command(cli, NULL, "no", NULL, NULL);
     cli_register_command(cli, c, "snoop", cmd_no_snoop, "Temporarily disable interception for a user");
     cli_register_command(cli, c, "throttle", cmd_no_throttle, "Temporarily disable throttling for a user");
     cli_register_command(cli, c, "debug", cmd_no_debug, "Turn off logging of a certain level of debugging");
+    c2 = cli_register_command(cli, c, "suspend", NULL, NULL);
+    cli_register_command(cli, c2, "bgp", cmd_no_suspend_bgp, "Advertise routes to BGP peer");
 
     c = cli_register_command(cli, NULL, "drop", NULL, NULL);
     cli_register_command(cli, c, "user", cmd_drop_user, "Disconnect a user");
     cli_register_command(cli, c, "tunnel", cmd_drop_tunnel, "Disconnect a tunnel and all sessions on that tunnel");
     cli_register_command(cli, c, "session", cmd_drop_session, "Disconnect a session");
 
-    cli_register_command(cli, NULL, "debug", cmd_debug, "Set the level of logging that is shown on the console");
-
-    /*
-    c = cli_register_command(cli, NULL, "watch", NULL, NULL);
-    cli_register_command(cli, c, "session", cmd_watch_session, "Dump logs for a session");
-    cli_register_command(cli, c, "tunnel", cmd_watch_tunnel, "Dump logs for a tunnel");
-    */
+    c = cli_register_command(cli, NULL, "restart", NULL, NULL);
+    cli_register_command(cli, c, "bgp", cmd_restart_bgp, "Restart BGP");
 
     c = cli_register_command(cli, NULL, "load", NULL, NULL);
     cli_register_command(cli, c, "plugin", cmd_load_plugin, "Load a plugin");
@@ -202,16 +220,24 @@ void init_cli()
 
 void cli_do(int sockfd)
 {
-    if (fork()) return;
+    int i;
 
-    // Close sockets
-    if (udpfd) close(udpfd); udpfd = 0;
-    if (tapfd) close(tapfd); tapfd = 0;
-    if (snoopfd) close(snoopfd); snoopfd = 0;
-    if (radfd) close(radfd); radfd = 0;
-    if (ifrfd) close(ifrfd); ifrfd = 0;
-    if (cluster_sockfd) close(cluster_sockfd); cluster_sockfd = 0;
-    if (clifd) close(clifd); clifd = 0;
+    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, &params)) == 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);
@@ -220,6 +246,22 @@ void cli_do(int sockfd)
     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 (tapfd) close(tapfd); tapfd = 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 */
 
     log(3, 0, 0, 0, "Accepted connection to CLI\n");
 
@@ -233,7 +275,7 @@ void cli_do(int sockfd)
 
     {
        char prompt[1005];
-       snprintf(prompt, 1005, "%s> ", hostname);
+       snprintf(prompt, 1005, "l2tpns> ");
        cli_loop(cli, sockfd, prompt);
     }
 
@@ -283,15 +325,20 @@ int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc)
            cli_print(cli, "    Idle time:      %u seconds", abs(time_now - session[s].last_packet));
            cli_print(cli, "    Next Recv:      %u", session[s].nr);
            cli_print(cli, "    Next Send:      %u", session[s].ns);
-           cli_print(cli, "    Bytes In/Out:   %lu/%lu", (unsigned long)session[s].cin, (unsigned long)session[s].total_cout);
-           cli_print(cli, "    Pkts In/Out:    %lu/%lu", (unsigned long)session[s].pin, (unsigned long)session[s].pout);
+           cli_print(cli, "    Bytes In/Out:   %lu/%lu", (unsigned long)session[s].total_cout, (unsigned long)session[s].total_cin);
+           cli_print(cli, "    Pkts In/Out:    %lu/%lu", (unsigned long)session[s].pout, (unsigned long)session[s].pin);
+           cli_print(cli, "    MRU:            %d", session[s].mru);
            cli_print(cli, "    Radius Session: %u", session[s].radius);
            cli_print(cli, "    Rx Speed:       %lu", session[s].rx_connect_speed);
            cli_print(cli, "    Tx Speed:       %lu", session[s].tx_connect_speed);
-           cli_print(cli, "    Intercepted:    %s", session[s].snoop ? "YES" : "no");
+           if (session[s].snoop_ip && session[s].snoop_port)
+               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, "    Servicenet:     %s", session[s].servicenet ? "YES" : "no");
-           cli_print(cli, "    Filter Bucket:  %s", session[s].tbf ? filter_buckets[session[s].tbf].handle : "none");
+           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);
        }
        return CLI_OK;
     }
@@ -304,7 +351,7 @@ int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc)
            "IP",
            "I",
            "T",
-           "S",
+           "G",
            "opened",
            "downloaded",
            "uploaded",
@@ -322,9 +369,9 @@ int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc)
                session[i].tunnel,
                session[i].user[0] ? session[i].user : "*",
                userip,
-               (session[i].snoop) ? "Y" : "N",
+               (session[i].snoop_ip && session[i].snoop_port) ? "Y" : "N",
                (session[i].throttle) ? "Y" : "N",
-               (session[i].servicenet) ? "Y" : "N",
+               (session[i].walled_garden) ? "Y" : "N",
                abs(time_now - (unsigned long)session[i].opened),
                (unsigned long)session[i].total_cout,
                (unsigned long)session[i].total_cin,
@@ -413,14 +460,36 @@ int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc)
 
 int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc)
 {
+    char sid[32][8];
+    char *sargv[32];
+    int sargc = 0;
     int i;
     for (i = 0; i < MAXSESSION; i++)
     {
        if (!session[i].opened) continue;
        if (!session[i].user[0]) continue;
-       cli_print(cli, "%s",
-               session[i].user);
+       if (argc > 0)
+       {
+           int j;
+           for (j = 0; j < argc && sargc < 32; j++)
+           {
+               if (strcmp(argv[j], session[i].user) == 0)
+               {
+                   snprintf(sid[sargc], sizeof(sid[0]), "%d", i);
+                   sargv[sargc] = sid[sargc];
+                   sargc++;
+               }
+           }
+
+           continue;
+       }
+
+       cli_print(cli, "%s", session[i].user);
     }
+
+    if (sargc > 0)
+       return cmd_show_session(cli, "users", sargv, sargc);
+
     return CLI_OK;
 }
 
@@ -446,7 +515,7 @@ int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc)
     cli_print(cli, "%-10s %8lu %8lu %8lu %8lu", "TX",
            GET_STAT(tunnel_tx_bytes),
            GET_STAT(tunnel_tx_packets),
-           GET_STAT(tunnel_rx_errors),
+           GET_STAT(tunnel_tx_errors),
            GET_STAT(tunnel_retries));
     cli_print(cli, "");
 
@@ -469,6 +538,9 @@ int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc)
     cli_print(cli, "%-30s%lu", "session_overflow",     GET_STAT(session_overflow));
     cli_print(cli, "%-30s%lu", "ip_allocated",         GET_STAT(ip_allocated));
     cli_print(cli, "%-30s%lu", "ip_freed",             GET_STAT(ip_freed));
+    cli_print(cli, "%-30s%lu", "cluster_forwarded",    GET_STAT(c_forwarded));
+    cli_print(cli, "%-30s%lu", "recv_forward",         GET_STAT(recv_forward));
+
 
 #ifdef STAT_CALLS
     cli_print(cli, "\n%-30s%-10s", "Counter", "Value");
@@ -527,9 +599,8 @@ int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc)
        if (!ip_address_pool[i].address) continue;
        if (ip_address_pool[i].assigned)
        {
-           sessionidt s = sessionbyip(ip_address_pool[i].address);
            cli_print(cli, "%-15s    Y %8d %s",
-               inet_toa(ip_address_pool[i].address), s, session[s].user);
+               inet_toa(htonl(ip_address_pool[i].address)), ip_address_pool[i].session, session[ip_address_pool[i].session].user);
 
            used++;
        }
@@ -537,10 +608,10 @@ int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc)
        {
            if (ip_address_pool[i].last)
                cli_print(cli, "%-15s    N %8s [%s] %ds",
-                   inet_toa(ip_address_pool[i].address), "",
+                   inet_toa(htonl(ip_address_pool[i].address)), "",
                    ip_address_pool[i].user, time_now - ip_address_pool[i].last);
            else if (show_all)
-               cli_print(cli, "%-15s    N", inet_toa(ip_address_pool[i].address));
+               cli_print(cli, "%-15s    N", inet_toa(htonl(ip_address_pool[i].address)));
 
            free++;
        }
@@ -568,7 +639,6 @@ int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc)
        cmd_show_run(cli, command, argv, argc);
        cli_print_callback(cli, NULL);
        fclose(save_config_fh);
-       sleep(1);
     }
     else
     {
@@ -627,7 +697,7 @@ int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc)
     int i, free = 0, used = 0, show_all = 0;
     time_t time_now;
 
-    cli_print(cli, "%6s%6s%9s%9s%4s", "Radius", "State", "Session", "Retry", "Try");
+    cli_print(cli, "%6s%5s%6s%9s%9s%4s", "Radius", "Sock", "State", "Session", "Retry", "Try");
 
     time(&time_now);
 
@@ -643,8 +713,9 @@ int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc)
 
        if (!show_all && radius[i].state == RADIUSNULL) continue;
 
-       cli_print(cli, "%6d%6s%9d%9u%4d",
-               i,
+       cli_print(cli, "%6d%5d%6s%9d%9u%4d",
+               i >> RADIUS_SHIFT,
+               i & RADIUS_MASK,
                states[radius[i].state],
                radius[i].session,
                radius[i].retry,
@@ -670,6 +741,24 @@ int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc)
     return CLI_OK;
 }
 
+int cmd_show_throttle(struct cli_def *cli, char *command, char **argv, int argc)
+{
+    int i;
+    cli_print(cli, "Token bucket filters:");
+    cli_print(cli, "%-6s %8s %-4s", "ID", "Handle", "Used");
+    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);
+    }
+    return CLI_OK;
+}
+
 int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int argc)
 {
     cli_print(cli, " _\n"
@@ -702,6 +791,11 @@ int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc)
     int i;
     sessionidt s;
 
+    if (!config->cluster_iam_master)
+    {
+       cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
+       return CLI_OK;
+    }
     if (!argc)
     {
        cli_print(cli, "Specify a user to drop");
@@ -748,6 +842,11 @@ int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int argc)
     int i;
     tunnelidt tid;
 
+    if (!config->cluster_iam_master)
+    {
+       cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
+       return CLI_OK;
+    }
     if (!argc)
     {
        cli_print(cli, "Specify a tunnel to drop");
@@ -803,6 +902,11 @@ int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc)
     int i;
     sessionidt s;
 
+    if (!config->cluster_iam_master)
+    {
+       cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
+       return CLI_OK;
+    }
     if (!argc)
     {
        cli_print(cli, "Specify a session id to drop");
@@ -850,33 +954,56 @@ int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc)
 int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc)
 {
     int i;
+    ipt ip;
+    u16 port;
     sessionidt s;
 
-    if (!argc)
+    if (!config->cluster_iam_master)
     {
-       cli_print(cli, "Specify a user");
+       cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
+       return CLI_OK;
+    }
+
+    if (argc < 3)
+    {
+       cli_print(cli, "Specify username ip port");
        return CLI_OK;
     }
+
     for (i = 0; i < argc; i++)
     {
        if (strchr(argv[i], '?'))
        {
-           cli_print(cli, "username ...");
+           cli_print(cli, "username ip port");
            return CLI_OK;
        }
     }
 
-    for (i = 0; i < argc; i++)
+
+    if (!(s = sessionbyuser(argv[0])))
     {
-       if (!(s = sessionbyuser(argv[i])))
-       {
-           cli_print(cli, "User %s is not connected", argv[i]);
-           continue;
-       }
-       session[s].snoop = 1;
+       cli_print(cli, "User %s is not connected", argv[0]);
+       return CLI_OK;
+    }
 
-       cli_print(cli, "Snooping user %s", argv[i]);
+    ip = inet_addr(argv[1]);
+    if (!ip || ip == INADDR_NONE)
+    {
+       cli_print(cli, "Cannot parse IP \"%s\"", argv[1]);
+       return CLI_OK;
     }
+
+    port = atoi(argv[2]);
+    if (!port)
+    {
+       cli_print(cli, "Invalid port %s", argv[2]);
+       return CLI_OK;
+    }
+
+    session[s].snoop_ip = ip;
+    session[s].snoop_port = port;
+
+    cli_print(cli, "Snooping user %s to %s:%d", argv[0], inet_toa(session[s].snoop_ip), session[s].snoop_port);
     return CLI_OK;
 }
 
@@ -885,6 +1012,12 @@ int cmd_no_snoop(struct cli_def *cli, char *command, char **argv, int argc)
     int i;
     sessionidt s;
 
+    if (!config->cluster_iam_master)
+    {
+       cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
+       return CLI_OK;
+    }
+
     if (!argc)
     {
        cli_print(cli, "Specify a user");
@@ -906,7 +1039,8 @@ int cmd_no_snoop(struct cli_def *cli, char *command, char **argv, int argc)
            cli_print(cli, "User %s is not connected", argv[i]);
            continue;
        }
-       session[s].snoop = 0;
+       session[s].snoop_ip = 0;
+       session[s].snoop_port = 0;
 
        cli_print(cli, "Not snooping user %s", argv[i]);
     }
@@ -918,6 +1052,11 @@ int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc)
     int i;
     sessionidt s;
 
+    if (!config->cluster_iam_master)
+    {
+       cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
+       return CLI_OK;
+    }
     if (!argc)
     {
        cli_print(cli, "Specify a user");
@@ -939,9 +1078,10 @@ int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc)
            cli_print(cli, "User %s is not connected", argv[i]);
            continue;
        }
-       throttle_session(s, 1);
-
-       cli_print(cli, "throttling user %s", argv[i]);
+       if (!throttle_session(s, config->rl_rate))
+           cli_print(cli, "Error throttling %s", argv[i]);
+       else
+           cli_print(cli, "Throttling user %s", argv[i]);
     }
     return CLI_OK;
 }
@@ -951,6 +1091,11 @@ int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc)
     int i;
     sessionidt s;
 
+    if (!config->cluster_iam_master)
+    {
+       cli_print(cli, "Can't do this on a slave. Do it on %s", inet_toa(config->cluster_master_address));
+       return CLI_OK;
+    }
     if (!argc)
     {
        cli_print(cli, "Specify a user");
@@ -966,7 +1111,7 @@ int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc)
     }
 
     for (i = 0; i < argc; i++)
-       {
+    {
        if (!(s = sessionbyuser(argv[i])))
        {
            cli_print(cli, "User %s is not connected", argv[i]);
@@ -1047,46 +1192,6 @@ int cmd_no_debug(struct cli_def *cli, char *command, char **argv, int argc)
     return CLI_OK;
 }
 
-int cmd_watch_session(struct cli_def *cli, char *command, char **argv, int argc)
-{
-    sessionidt s;
-
-    if (argc != 1)
-    {
-       cli_print(cli, "Specify a single session to debug (0 to disable)");
-       return CLI_OK;
-    }
-    s = atoi(argv[0]);
-
-    if (debug_session)
-       cli_print(cli, "No longer debugging session %d", debug_session);
-
-    if (s) cli_print(cli, "Debugging session %d.", s);
-    debug_session = s;
-
-    return CLI_OK;
-}
-
-int cmd_watch_tunnel(struct cli_def *cli, char *command, char **argv, int argc)
-{
-    tunnelidt s;
-
-    if (argc != 1)
-    {
-       cli_print(cli, "Specify a single tunnel to debug (0 to disable)");
-       return CLI_OK;
-    }
-    s = atoi(argv[0]);
-
-    if (debug_tunnel)
-       cli_print(cli, "No longer debugging tunnel %d", debug_tunnel);
-
-    if (s) cli_print(cli, "Debugging tunnel %d.", s);
-    debug_tunnel = s;
-
-    return CLI_OK;
-}
-
 int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc)
 {
     int i, firstfree = 0;
@@ -1265,7 +1370,7 @@ int regular_stuff(struct cli_def *cli)
 
        if (show_message)
        {
-           ipt address = ntohl(ringbuffer->buffer[i].address);
+           ipt address = htonl(ringbuffer->buffer[i].address);
            char *ipaddr;
            struct in_addr addr;