]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
automatic cleanup of tcp tickle records
authorAndrew Tridgell <tridge@samba.org>
Sun, 27 May 2007 14:34:40 +0000 (00:34 +1000)
committerAndrew Tridgell <tridge@samba.org>
Sun, 27 May 2007 14:34:40 +0000 (00:34 +1000)
(This used to be ctdb commit ede79b571bf89b89f1b8394f262ca0689f8c65f3)

ctdb/common/ctdb_control.c
ctdb/common/ctdb_daemon.c
ctdb/include/ctdb_private.h
ctdb/takeover/ctdb_takeover.c
ctdb/takeover/system.c

index fd3dcf9988246cbad5b35f23f0e5b6b4762a3625..5b9e6904f9a6535c6c325049a747c7be18ec6e37 100644 (file)
@@ -274,14 +274,18 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
 
        case CTDB_CONTROL_TCP_CLIENT: 
                CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp));
-               return ctdb_control_tcp_client(ctdb, client_id, indata);
+               return ctdb_control_tcp_client(ctdb, client_id, srcnode, indata);
+
+       case CTDB_CONTROL_STARTUP: 
+               CHECK_CONTROL_DATA_SIZE(0);
+               return ctdb_control_startup(ctdb, srcnode);
 
        case CTDB_CONTROL_TCP_ADD: 
-               CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp));
+               CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp_vnn));
                return ctdb_control_tcp_add(ctdb, indata);
 
        case CTDB_CONTROL_TCP_REMOVE: 
-               CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp));
+               CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp_vnn));
                return ctdb_control_tcp_remove(ctdb, indata);
 
        default:
index 4bf1d1a605d15a82171ad32b7784c0f6269590c9..a420f4613d34b977a6fe63700ec0e289e085cdd4 100644 (file)
@@ -56,6 +56,12 @@ static void ctdb_main_loop(struct ctdb_context *ctdb)
                ctdb_fatal(ctdb, "transport failed to start");
        }
 
+       /* tell all other nodes we've just started up */
+       ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL,
+                                0, CTDB_CONTROL_STARTUP, 0,
+                                CTDB_CTRL_FLAG_NOREPLY,
+                                tdb_null, NULL, NULL);
+
        /* go into a wait loop to allow other nodes to complete */
        event_loop_wait(ctdb->ev);
 
index 61b459108c88cd6152ce11fd4a496706f96a9bda..ab2d529f694f6d7d349a449512a25c61e0e6492a 100644 (file)
@@ -414,6 +414,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS,
                    CTDB_CONTROL_TCP_CLIENT,
                    CTDB_CONTROL_TCP_ADD,
                    CTDB_CONTROL_TCP_REMOVE,
+                   CTDB_CONTROL_STARTUP,
 };
 
 /*
@@ -442,13 +443,22 @@ struct ctdb_control_set_call {
 };
 
 /*
-  struct for tcp_client, tcp_add and tcp_remove controls
+  struct for tcp_client control
  */
 struct ctdb_control_tcp {
        struct sockaddr_in src;
        struct sockaddr_in dest;
 };
 
+/*
+  struct for tcp_add and tcp_remove controls
+ */
+struct ctdb_control_tcp_vnn {
+       uint32_t vnn;
+       struct sockaddr_in src;
+       struct sockaddr_in dest;
+};
+
 enum call_state {CTDB_CALL_WAIT, CTDB_CALL_DONE, CTDB_CALL_ERROR};
 
 #define CTDB_LMASTER_ANY       0xffffffff
@@ -918,6 +928,7 @@ int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout,
 
 /* from takeover/system.c */
 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface);
+bool ctdb_sys_have_ip(const char *ip);
 int ctdb_sys_take_ip(const char *ip, const char *interface);
 int ctdb_sys_release_ip(const char *ip, const char *interface);
 int ctdb_sys_send_ack(const struct sockaddr_in *dest, 
@@ -928,9 +939,10 @@ int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
 int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap);
 
 int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, 
-                               TDB_DATA indata);
+                               uint32_t srcnode, TDB_DATA indata);
 int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata);
 int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn);
 
 void ctdb_takeover_client_destructor_hook(struct ctdb_client *client);
 
index c3bc12e76711097eac80d604181b81bc9c0aed3a..5f86b08513a0c6fccd6b268fa7a0ff1e9ab9ece1 100644 (file)
@@ -44,8 +44,9 @@ struct ctdb_takeover_arp {
  */
 struct ctdb_tcp_list {
        struct ctdb_tcp_list *prev, *next;
+       uint32_t vnn;
        struct sockaddr_in saddr;
-       struct sockaddr_in daddr;       
+       struct sockaddr_in daddr;
 };
 
 
@@ -102,6 +103,10 @@ int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, TDB_DATA indata)
        char *ip = inet_ntoa(sin->sin_addr);
        struct ctdb_tcp_list *tcp;
 
+       if (ctdb_sys_have_ip(ip)) {
+               return 0;
+       }
+
        DEBUG(0,("Takover of IP %s on interface %s\n", ip, ctdb->takeover.interface));
        ret = ctdb_sys_take_ip(ip, ctdb->takeover.interface);
        if (ret != 0) {
@@ -148,6 +153,10 @@ int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, TDB_DATA indata)
        char *ip = inet_ntoa(sin->sin_addr);
        int ret;
 
+       if (!ctdb_sys_have_ip(ip)) {
+               return 0;
+       }
+
        DEBUG(0,("Release of IP %s on interface %s\n", ip, ctdb->takeover.interface));
 
        /* stop any previous arps */
@@ -281,26 +290,36 @@ int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap)
   called by a client to inform us of a TCP connection that it is managing
   that should tickled with an ACK when IP takeover is done
  */
-int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, 
+int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, uint32_t vnn,
                                TDB_DATA indata)
 {
        struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
        struct ctdb_control_tcp *p = (struct ctdb_control_tcp *)indata.dptr;
        struct ctdb_tcp_list *tcp;
+       struct ctdb_control_tcp_vnn t;
        int ret;
+       TDB_DATA data;
 
        tcp = talloc(client, struct ctdb_tcp_list);
        CTDB_NO_MEMORY(ctdb, tcp);
 
+       tcp->vnn   = vnn;
        tcp->saddr = p->src;
        tcp->daddr = p->dest;
 
        DLIST_ADD(client->tcp_list, tcp);
 
+       t.vnn  = vnn;
+       t.src  = p->src;
+       t.dest = p->dest;
+
+       data.dptr = (uint8_t *)&t;
+       data.dsize = sizeof(t);
+
        /* tell all nodes about this tcp connection */
        ret = ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_VNNMAP, 0, 
                                       CTDB_CONTROL_TCP_ADD,
-                                      0, CTDB_CTRL_FLAG_NOREPLY, indata, NULL, NULL);
+                                      0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
        if (ret != 0) {
                DEBUG(0,(__location__ " Failed to send CTDB_CONTROL_TCP_ADD\n"));
                return -1;
@@ -342,12 +361,13 @@ static struct ctdb_tcp_list *ctdb_tcp_find(struct ctdb_tcp_list *list,
  */
 int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-       struct ctdb_control_tcp *p = (struct ctdb_control_tcp *)indata.dptr;
+       struct ctdb_control_tcp_vnn *p = (struct ctdb_control_tcp_vnn *)indata.dptr;
        struct ctdb_tcp_list *tcp;
 
        tcp = talloc(ctdb, struct ctdb_tcp_list);
        CTDB_NO_MEMORY(ctdb, tcp);
 
+       tcp->vnn   = p->vnn;
        tcp->saddr = p->src;
        tcp->daddr = p->dest;
 
@@ -365,9 +385,10 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
  */
 int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-       struct ctdb_control_tcp *p = (struct ctdb_control_tcp *)indata.dptr;
+       struct ctdb_control_tcp_vnn *p = (struct ctdb_control_tcp_vnn *)indata.dptr;
        struct ctdb_tcp_list t, *tcp;
 
+       t.vnn   = p->vnn;
        t.saddr = p->src;
        t.daddr = p->dest;
 
@@ -380,6 +401,23 @@ int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata)
 }
 
 
+/*
+  called when a daemon restarts - wipes all tcp entries from that vnn
+ */
+int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn)
+{
+       struct ctdb_tcp_list *tcp, *next;       
+       for (tcp=ctdb->tcp_list;tcp;tcp=next) {
+               next = tcp->next;
+               if (tcp->vnn == vnn) {
+                       DLIST_REMOVE(ctdb->tcp_list, tcp);
+                       talloc_free(tcp);
+               }
+       }
+       return 0;
+}
+
+
 /*
   called when a client structure goes away - hook to remove
   elements from the tcp_list in all daemons
@@ -388,9 +426,10 @@ void ctdb_takeover_client_destructor_hook(struct ctdb_client *client)
 {
        while (client->tcp_list) {
                TDB_DATA data;
-               struct ctdb_control_tcp p;
+               struct ctdb_control_tcp_vnn p;
                struct ctdb_tcp_list *tcp = client->tcp_list;
                DLIST_REMOVE(client->tcp_list, tcp);
+               p.vnn = tcp->vnn;
                p.src = tcp->saddr;
                p.dest = tcp->daddr;
                data.dptr = (uint8_t *)&p;
index be1baefa4f7c46f10400ca32a519384bd4d8951e..d4a03460eac9bfb0bc787eb0737b380686be40fb 100644 (file)
@@ -233,6 +233,29 @@ int ctdb_sys_send_ack(const struct sockaddr_in *dest,
 }
 
 
+/*
+  see if we currently have an interface with the given IP
+
+  we try to bind to it, and if that fails then we don't have that IP
+  on an interface
+ */
+bool ctdb_sys_have_ip(const char *ip)
+{
+       struct sockaddr_in sin;
+       int s;
+       int ret;
+
+       sin.sin_port = 0;
+       inet_aton(ip, &sin.sin_addr);
+       sin.sin_family = AF_INET;
+       s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (s == -1) {
+               return false;
+       }
+       ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
+       close(s);
+       return ret == 0;
+}
 
 /*
   takeover an IP on an interface