tools/ctdb: Display the locking statistics
[obnox/ctdb.git] / tools / ctdb.c
index 647363e1b8917394f47dae0bfdeb0b6dae1115ca..fcc44bb2b6fad549de19abf4907061bc02b5f2bf 100644 (file)
@@ -334,6 +334,10 @@ static void show_statistics(struct ctdb_statistics *s, int show_header)
                STATISTICS_FIELD(timeouts.call),
                STATISTICS_FIELD(timeouts.control),
                STATISTICS_FIELD(timeouts.traverse),
+               STATISTICS_FIELD(locks.num_calls),
+               STATISTICS_FIELD(locks.num_current),
+               STATISTICS_FIELD(locks.num_pending),
+               STATISTICS_FIELD(locks.num_failed),
                STATISTICS_FIELD(total_calls),
                STATISTICS_FIELD(pending_calls),
                STATISTICS_FIELD(lockwait_calls),
@@ -446,7 +450,14 @@ static void show_statistics(struct ctdb_statistics *s, int show_header)
                        printf(" %d", s->hop_count_bucket[i]);
                }
                printf("\n");
-               printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "reclock_ctdbd       MIN/AVG/MAX", s->reclock.ctdbd.min, s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0, s->reclock.ctdbd.max, s->reclock.ctdbd.num);
+               printf(" lock_buckets:");
+               for (i=0; i<MAX_COUNT_BUCKETS; i++) {
+                       printf(" %d", s->locks.buckets[i]);
+               }
+               printf("\n");
+               printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "locks_latency      MIN/AVG/MAX", s->locks.latency.min, s->locks.latency.num?s->locks.latency.total/s->locks.latency.num:0.0, s->locks.latency.max, s->locks.latency.num);
+
+               printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "reclock_ctdbd      MIN/AVG/MAX", s->reclock.ctdbd.min, s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0, s->reclock.ctdbd.max, s->reclock.ctdbd.num);
 
                printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "reclock_recd       MIN/AVG/MAX", s->reclock.recd.min, s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0, s->reclock.recd.max, s->reclock.recd.num);
 
@@ -576,7 +587,7 @@ static int control_stats(struct ctdb_context *ctdb, int argc, const char **argv)
 static int control_dbstatistics(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-       struct ctdb_db_statistics *dbstatistics;
+       struct ctdb_db_statistics *dbstat;
        struct ctdb_dbid_map *dbmap=NULL;
        int i, ret;
 
@@ -605,22 +616,50 @@ static int control_dbstatistics(struct ctdb_context *ctdb, int argc, const char
                return -1;
        }
 
-       if (!ctdb_getdbstat(ctdb_connection, options.pnn, dbmap->dbs[i].dbid, &dbstatistics)) {
+       if (!ctdb_getdbstat(ctdb_connection, options.pnn, dbmap->dbs[i].dbid, &dbstat)) {
                DEBUG(DEBUG_ERR,("Failed to read db statistics from node\n"));
                talloc_free(tmp_ctx);
                return -1;
        }
 
        printf("DB Statistics:\n");
-       printf("RO Delegations: %d\n", dbstatistics->db_ro_delegations);
-       printf("RO Revokes:     %d\n", dbstatistics->db_ro_revokes);
-       printf(" hop_count_buckets:");
-       for (i=0;i<MAX_COUNT_BUCKETS;i++) {
-               printf(" %d", dbstatistics->hop_count_bucket[i]);
+       printf(" %*s%-22s%*s%10u\n", 0, "", "ro_delegations", 4, "",
+               dbstat->db_ro_delegations);
+       printf(" %*s%-22s%*s%10u\n", 0, "", "ro_revokes", 4, "",
+               dbstat->db_ro_delegations);
+       printf(" %s\n", "locks");
+       printf(" %*s%-22s%*s%10u\n", 4, "", "total", 0, "",
+               dbstat->locks.num_calls);
+       printf(" %*s%-22s%*s%10u\n", 4, "", "failed", 0, "",
+               dbstat->locks.num_failed);
+       printf(" %*s%-22s%*s%10u\n", 4, "", "current", 0, "",
+               dbstat->locks.num_current);
+       printf(" %*s%-22s%*s%10u\n", 4, "", "pending", 0, "",
+               dbstat->locks.num_pending);
+       printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n",
+               "    latency_ctdbd  MIN/AVG/MAX",
+               dbstat->locks.latency.min,
+               (dbstat->locks.latency.num ?
+                dbstat->locks.latency.total /dbstat->locks.latency.num :
+                0.0),
+               dbstat->locks.latency.max,
+               dbstat->locks.latency.num);
+       printf(" %s", "    buckets:");
+       for (i=0; i<MAX_COUNT_BUCKETS; i++) {
+               printf(" %d", dbstat->hop_count_bucket[i]);
        }
        printf("\n");
+       printf("Num Hot Keys:     %d\n", dbstat->num_hot_keys);
+       for (i = 0; i < dbstat->num_hot_keys; i++) {
+               int j;
+               printf("Count:%d Key:", dbstat->hot_keys[i].count);
+               for (j = 0; j < dbstat->hot_keys[i].key.dsize; j++) {
+                       printf("%02x", dbstat->hot_keys[i].key.dptr[j]&0xff);
+               }
+               printf("\n");
+       }
 
-       ctdb_free_dbstat(dbstatistics);
+       ctdb_free_dbstat(dbstat);
        return 0;
 }
 
@@ -827,6 +866,12 @@ static bool is_partially_online(struct ctdb_node_and_flags *node)
        return ret;
 }
 
+static void control_status_header_machine(void)
+{
+       printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
+              ":Inactive:PartiallyOnline:ThisNode:\n");
+}
+
 static int control_status_1_machine(int mypnn, struct ctdb_node_and_flags *node)
 {
        printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", node->pnn,
@@ -873,8 +918,7 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
        }
 
        if (options.machinereadable) {
-               printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
-                      ":Inactive:PartiallyOnline:ThisNode:\n");
+               control_status_header_machine();
                for (i=0;i<nodemap->num;i++) {
                        if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
                                continue;
@@ -940,8 +984,7 @@ static int control_nodestatus(struct ctdb_context *ctdb, int argc, const char **
        }
 
        if (options.machinereadable) {
-               printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
-                      ":Inactive:PartiallyOnline:ThisNode:\n");
+               control_status_header_machine();
        } else if (pnn_mode == CTDB_BROADCAST_ALL) {
                printf("Number of nodes:%d\n", (int) talloc_array_length(nodes));
        }
@@ -975,23 +1018,62 @@ struct natgw_node {
        const char *addr;
 };
 
+static int find_natgw(struct ctdb_context *ctdb,
+                      struct ctdb_node_map *nodemap, uint32_t flags,
+                      uint32_t *pnn, const char **ip)
+{
+       int i;
+       uint32_t capabilities;
+
+       for (i=0;i<nodemap->num;i++) {
+               if (!(nodemap->nodes[i].flags & flags)) {
+                       if (!ctdb_getcapabilities(ctdb_connection, nodemap->nodes[i].pnn, &capabilities)) {
+                               DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
+                               return -1;
+                       }
+                       if (!(capabilities&CTDB_CAP_NATGW)) {
+                               continue;
+                       }
+                       *pnn = nodemap->nodes[i].pnn;
+                       *ip = ctdb_addr_to_str(&nodemap->nodes[i].addr);
+                       return 0;
+               }
+       }
+
+       return 2; /* matches ENOENT */
+}
+
 /*
   display the list of nodes belonging to this natgw configuration
  */
 static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        int i, ret;
-       uint32_t capabilities;
        const char *natgw_list;
        int nlines;
        char **lines;
        struct natgw_node *natgw_nodes = NULL;
        struct natgw_node *natgw_node;
        struct ctdb_node_map *nodemap=NULL;
+       uint32_t mypnn, pnn;
+       const char *ip;
 
+       /* When we have some nodes that could be the NATGW, make a
+        * series of attempts to find the first node that doesn't have
+        * certain status flags set.
+        */
+       uint32_t exclude_flags[] = {
+               /* Look for a nice healthy node */
+               NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY,
+               /* If not found, an UNHEALTHY/BANNED node will do */
+               NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED,
+               /* If not found, a STOPPED node will do */
+               NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED,
+               0,
+       };
 
        /* read the natgw nodes file into a linked list */
-       natgw_list = getenv("NATGW_NODES");
+       natgw_list = getenv("CTDB_NATGW_NODES");
        if (natgw_list == NULL) {
                natgw_list = "/etc/ctdb/natgw_nodes";
        }
@@ -1000,9 +1082,6 @@ static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **a
                ctdb_set_error(ctdb, "Failed to load natgw node list '%s'\n", natgw_list);
                return -1;
        }
-       while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
-               nlines--;
-       }
        for (i=0;i<nlines;i++) {
                char *node;
 
@@ -1024,12 +1103,14 @@ static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **a
                natgw_nodes = natgw_node;
        }
 
-       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
-       if (ret != 0) {
+       if (!ctdb_getnodemap(ctdb_connection, CTDB_CURRENT_NODE, &nodemap)) {
                DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node.\n"));
-               return ret;
+               return -1;
        }
 
+       /* Trim the nodemap so it only includes connected nodes in the
+        * current natgw group.
+        */
        i=0;
        while(i<nodemap->num) {
                for(natgw_node=natgw_nodes;natgw_node;natgw_node=natgw_node->next) {
@@ -1053,79 +1134,56 @@ static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **a
                }
 
                i++;
-       }               
+       }
 
-       /* pick a node to be natgwmaster
-        * we dont allow STOPPED, DELETED, BANNED or UNHEALTHY nodes to become the natgwmaster
-        */
-       for(i=0;i<nodemap->num;i++){
-               if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY))) {
-                       ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
-                       if (ret != 0) {
-                               DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
-                               return ret;
-                       }
-                       if (!(capabilities&CTDB_CAP_NATGW)) {
-                               continue;
-                       }
-                       printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
-                       break;
+       ret = 2; /* matches ENOENT */
+       pnn = -1;
+       ip = "0.0.0.0";
+       for (i = 0; exclude_flags[i] != 0; i++) {
+               ret = find_natgw(ctdb, nodemap,
+                                exclude_flags[i],
+                                &pnn, &ip);
+               if (ret == -1) {
+                       goto done;
                }
-       }
-       /* we couldnt find any healthy node, try unhealthy ones */
-       if (i == nodemap->num) {
-               for(i=0;i<nodemap->num;i++){
-                       if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED))) {
-                               ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
-                               if (ret != 0) {
-                                       DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
-                                       return ret;
-                               }
-                               if (!(capabilities&CTDB_CAP_NATGW)) {
-                                       continue;
-                               }
-                               printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
-                               break;
-                       }
+               if (ret == 0) {
+                       break;
                }
        }
-       /* unless all nodes are STOPPED, when we pick one anyway */
-       if (i == nodemap->num) {
-               for(i=0;i<nodemap->num;i++){
-                       if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED))) {
-                               ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
-                               if (ret != 0) {
-                                       DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
-                                       return ret;
-                               }
-                               if (!(capabilities&CTDB_CAP_NATGW)) {
-                                       continue;
-                               }
-                               printf("%d %s\n", nodemap->nodes[i].pnn, ctdb_addr_to_str(&nodemap->nodes[i].addr));
-                               break;
-                       }
-               }
-               /* or if we still can not find any */
-               if (i == nodemap->num) {
-                       printf("-1 0.0.0.0\n");
-                       ret = 2; /* matches ENOENT */
-               }
+
+       if (options.machinereadable) {
+               printf(":Node:IP:\n");
+               printf(":%d:%s:\n", pnn, ip);
+       } else {
+               printf("%d %s\n", pnn, ip);
        }
 
        /* print the pruned list of nodes belonging to this natgw list */
+       if (!ctdb_getpnn(ctdb_connection, options.pnn, &mypnn)) {
+               DEBUG(DEBUG_NOTICE, ("Unable to get PNN from node %u\n", options.pnn));
+               /* This is actually harmless and will only result in
+                * the "this node" indication being missing
+                */
+               mypnn = -1;
+       }
+       if (options.machinereadable) {
+               control_status_header_machine();
+       } else {
+               printf("Number of nodes:%d\n", nodemap->num);
+       }
        for(i=0;i<nodemap->num;i++){
                if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
                        continue;
                }
-               printf(":%d:%s:%d:%d:%d:%d:%d\n", nodemap->nodes[i].pnn,
-                       ctdb_addr_to_str(&nodemap->nodes[i].addr),
-                      !!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
-                      !!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
-                      !!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
-                      !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
-                      !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED));
+               if (options.machinereadable) {
+                       control_status_1_machine(mypnn, &(nodemap->nodes[i]));
+               } else {
+                       control_status_1_human(mypnn, &(nodemap->nodes[i]));
+               }
        }
 
+done:
+       ctdb_free_nodemap(nodemap);
        return ret;
 }
 
@@ -2068,6 +2126,27 @@ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
        return 0;
 }
 
+/*
+  add a public ip address to a node
+ */
+static int control_ipiface(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       ctdb_sock_addr addr;
+
+       if (argc != 1) {
+               usage();
+       }
+
+       if (!parse_ip(argv[0], NULL, 0, &addr)) {
+               printf("Badly formed ip : %s\n", argv[0]);
+               return -1;
+       }
+
+       printf("IP on interface %s\n", ctdb_sys_find_ifname(&addr));
+
+       return 0;
+}
+
 static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv);
 
 static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **argv, ctdb_sock_addr *addr)
@@ -3119,12 +3198,10 @@ static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **
 static int control_getcapabilities(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        uint32_t capabilities;
-       int ret;
 
-       ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), options.pnn, &capabilities);
-       if (ret != 0) {
+       if (!ctdb_getcapabilities(ctdb_connection, options.pnn, &capabilities)) {
                DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", options.pnn));
-               return ret;
+               return -1;
        }
        
        if (!options.machinereadable){
@@ -3153,15 +3230,16 @@ static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv)
        int i, ret;
        int healthy_count = 0;
 
-       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
-       if (ret != 0) {
+       if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
                DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
-               return ret;
+               return -1;
        }
 
        capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
        CTDB_NO_MEMORY(ctdb, capabilities);
        
+       ret = 0;
+
        /* collect capabilities for all connected nodes */
        for (i=0; i<nodemap->num; i++) {
                if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
@@ -3171,10 +3249,10 @@ static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv)
                        continue;
                }
        
-               ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
-               if (ret != 0) {
+               if (!ctdb_getcapabilities(ctdb_connection, i, &capabilities[i])) {
                        DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
-                       return ret;
+                       ret = -1;
+                       goto done;
                }
 
                if (!(capabilities[i] & CTDB_CAP_LVS)) {
@@ -3208,7 +3286,9 @@ static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv)
                        ctdb_addr_to_str(&nodemap->nodes[i].addr));
        }
 
-       return 0;
+done:
+       ctdb_free_nodemap(nodemap);
+       return ret;
 }
 
 /*
@@ -3221,14 +3301,15 @@ static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **a
        int i, ret;
        int healthy_count = 0;
 
-       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
-       if (ret != 0) {
+       if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
                DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
-               return ret;
+               return -1;
        }
 
        capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
        CTDB_NO_MEMORY(ctdb, capabilities);
+
+       ret = -1;
        
        /* collect capabilities for all connected nodes */
        for (i=0; i<nodemap->num; i++) {
@@ -3239,10 +3320,10 @@ static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **a
                        continue;
                }
        
-               ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
-               if (ret != 0) {
+               if (!ctdb_getcapabilities(ctdb_connection, i, &capabilities[i])) {
                        DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
-                       return ret;
+                       ret = -1;
+                       goto done;
                }
 
                if (!(capabilities[i] & CTDB_CAP_LVS)) {
@@ -3277,11 +3358,14 @@ static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **a
                } else {
                        printf("Node %d is LVS master\n", i);
                }
-               return 0;
+               ret = 0;
+               goto done;
        }
 
        printf("There is no LVS master\n");
-       return -1;
+done:
+       ctdb_free_nodemap(nodemap);
+       return ret;
 }
 
 /*
@@ -3428,7 +3512,7 @@ static int control_cattdb(struct ctdb_context *ctdb, int argc, const char **argv
                return -1;
        }
 
-       ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, false, 0);
+       ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
 
        if (ctdb_db == NULL) {
                DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
@@ -3994,6 +4078,96 @@ static int control_clearlog(struct ctdb_context *ctdb, int argc, const char **ar
 }
 
 
+static uint32_t reloadips_finished;
+
+static void reloadips_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+                            TDB_DATA data, void *private_data)
+{
+       reloadips_finished = 1;
+}
+
+static int reloadips_all(struct ctdb_context *ctdb)
+{
+       struct reloadips_all_reply rips;
+       struct ctdb_node_map *nodemap=NULL;
+       TDB_DATA data;
+       uint32_t recmaster;
+       int ret, i;
+
+       /* check that there are valid nodes available */
+       if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+               return 1;
+       }
+       for (i=0; i<nodemap->num;i++) {
+               if (nodemap->nodes[i].flags != 0) {
+                       DEBUG(DEBUG_ERR,("reloadips -n all  can only be used when all nodes are up and healthy. Aborting due to problem with node %d\n", i));
+                       return 1;
+               }
+       }
+
+
+       rips.pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+       if (rips.pnn == -1) {
+               DEBUG(DEBUG_ERR, ("Failed to get pnn of local node\n"));
+               return 1;
+       }
+       rips.srvid = getpid();
+
+
+       /* register a message port for receiveing the reply so that we
+          can receive the reply
+       */
+       ctdb_client_set_message_handler(ctdb, rips.srvid, reloadips_handler, NULL);
+
+       if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
+               DEBUG(DEBUG_ERR, ("Unable to get recmaster from node\n"));
+               return -1;
+       }
+
+
+       data.dptr = (uint8_t *)&rips;
+       data.dsize = sizeof(rips);
+
+       ret = ctdb_client_send_message(ctdb, recmaster, CTDB_SRVID_RELOAD_ALL_IPS, data);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Failed to send reload all ips request message to %u\n", options.pnn));
+               return 1;
+       }
+
+       reloadips_finished = 0;
+       while (reloadips_finished == 0) {
+               event_loop_once(ctdb->ev);
+       }
+
+       return 0;
+}
+
+/*
+  reload public ips on a specific node
+ */
+static int control_reloadips(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       int32_t res;
+       char *errmsg;
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+       if (options.pnn == CTDB_BROADCAST_ALL) {
+               return reloadips_all(ctdb);
+       }
+
+       ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_RELOAD_PUBLIC_IPS,
+                          0, tdb_null, tmp_ctx, NULL, &res, NULL, &errmsg);
+       if (ret != 0 || res != 0) {
+               DEBUG(DEBUG_ERR,("Failed to reload ips\n"));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
+       talloc_free(tmp_ctx);
+       return 0;
+}
 
 /*
   display a list of the databases on a remote ctdb
@@ -5663,7 +5837,7 @@ static const struct {
        { "restoredb",        control_restoredb,        false,  false, "restore the database from a file.", "<file> [dbname]"},
        { "dumpdbbackup",    control_dumpdbbackup,      false,  true,  "dump database backup from a file.", "<file>"},
        { "wipedb",           control_wipedb,        false,     false, "wipe the contents of a database.", "<dbname>"},
-       { "recmaster",        control_recmaster,        false,  false, "show the pnn for the recovery master."},
+       { "recmaster",        control_recmaster,        true,   false, "show the pnn for the recovery master."},
        { "scriptstatus",     control_scriptstatus,     true,   false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
        { "enablescript",     control_enablescript,  false,     false, "enable an eventscript", "<script>"},
        { "disablescript",    control_disablescript,  false,    false, "disable an eventscript", "<script>"},
@@ -5692,6 +5866,8 @@ static const struct {
        { "getdbseqnum",     control_getdbseqnum,       false,  false, "get the sequence number off a database", "<dbid>" },
        { "nodestatus",      control_nodestatus,        true,   false,  "show and return node status" },
        { "dbstatistics",    control_dbstatistics,      false,  false, "show db statistics", "<db>" },
+       { "reloadips",       control_reloadips,         false,  false, "reload the public addresses file on a node" },
+       { "ipiface",         control_ipiface,           true,   true,  "Find which interface an ip address is hsoted on", "<ip>" },
 };
 
 /*
@@ -5805,7 +5981,6 @@ int main(int argc, const char *argv[])
                DEBUG(DEBUG_ERR, ("Failed to initialize event system\n"));
                exit(1);
        }
-       tevent_loop_allow_nesting(ev);
 
        for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
                if (strcmp(control, ctdb_commands[i].name) == 0) {
@@ -5870,6 +6045,7 @@ int main(int argc, const char *argv[])
 
        ctdb_disconnect(ctdb_connection);
        talloc_free(ctdb);
+       talloc_free(ev);
        (void)poptFreeContext(pc);
 
        return ret;