- merge from ronnie
authorAndrew Tridgell <tridge@samba.org>
Fri, 13 Jul 2007 01:31:18 +0000 (11:31 +1000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 13 Jul 2007 01:31:18 +0000 (11:31 +1000)
- cleaner handling of system capture socket

(This used to be ctdb commit d194a41a71b8466d0726dcbae3970a86386fcb3c)

12 files changed:
ctdb/client/ctdb_client.c
ctdb/common/ctdb_util.c
ctdb/common/system.c
ctdb/config/events.d/60.nfs
ctdb/doc/ctdbd.1
ctdb/doc/ctdbd.1.html
ctdb/include/ctdb_private.h
ctdb/server/ctdb_call.c
ctdb/server/ctdb_control.c
ctdb/server/ctdb_server.c
ctdb/server/ctdb_takeover.c
ctdb/tools/ctdb.c

index b72faa83d7e07a9fcf97ed3527b1749309f848e0..fcf6e7bf56bb69690567630a661924ac6fb8d999 100644 (file)
@@ -2094,6 +2094,32 @@ int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
 }
 
 
+/*
+  kill a tcp connection
+ */
+int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, 
+                     struct timeval timeout, 
+                     uint32_t destnode,
+                     struct ctdb_control_killtcp *killtcp)
+{
+       TDB_DATA data;
+       int32_t res;
+       int ret;
+
+       data.dsize = sizeof(struct ctdb_control_killtcp);
+       data.dptr  = (unsigned char *)killtcp;
+
+       ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_KILL_TCP, 0, data, NULL,
+                          NULL, &res, &timeout, NULL);
+       if (ret != 0 || res != 0) {
+               DEBUG(0,(__location__ " ctdb_control for killtcp failed\n"));
+               return -1;
+       }
+
+       return 0;
+}
+
+
 /*
   initialise the ctdb daemon for client applications
 
index 4890a141ea73031a58420aa537d115b5eff4a06f..54b1e4e7ff5f68887b7f1c169533401b253cf651 100644 (file)
@@ -196,7 +196,6 @@ void ctdb_set_scheduler(struct ctdb_context *ctdb)
 {
 #if HAVE_SCHED_SETSCHEDULER    
        struct sched_param p;
-
        if (ctdb->saved_scheduler_param == NULL) {
                ctdb->saved_scheduler_param = talloc_size(ctdb, sizeof(p));
        }
@@ -210,7 +209,8 @@ void ctdb_set_scheduler(struct ctdb_context *ctdb)
        p.sched_priority = 1;
 
        if (sched_setscheduler(0, SCHED_FIFO, &p) == -1) {
-               DEBUG(0,("Unable to set scheduler to SCHED_FIFO (%s)\n", strerror(errno)));
+               DEBUG(0,("Unable to set scheduler to SCHED_FIFO (%s)\n", 
+                        strerror(errno)));
        } else {
                DEBUG(0,("Set scheduler to SCHED_FIFO\n"));
        }
index 1e536f5e8a4eef2c066d8debb4d7a3133be863e5..f4f12a168ba91e78e8680ee7433ddc09391a7386 100644 (file)
@@ -24,7 +24,7 @@
 #include "system/wait.h"
 #include "../include/ctdb_private.h"
 #include "lib/events/events.h"
-#include <net/ethernet.h>
+#include <netinet/if_ether.h>
 #include <net/if_arp.h>
 
 
@@ -183,12 +183,12 @@ static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
   This can also be used to send RST segments (if rst is true) and also
   if correct seq and ack numbers are provided.
  */
-int ctdb_sys_send_tcp(const struct sockaddr_in *dest, 
+int ctdb_sys_send_tcp(int s,
+                     const struct sockaddr_in *dest, 
                      const struct sockaddr_in *src,
                      uint32_t seq, uint32_t ack, int rst)
 {
-       int s, ret;
-       uint32_t one = 1;
+       int ret;
        struct {
                struct iphdr ip;
                struct tcphdr tcp;
@@ -200,21 +200,6 @@ int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
                return -1;
        }
 
-       s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
-       if (s == -1) {
-               DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
-                        strerror(errno)));
-               return -1;
-       }
-
-       ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
-       if (ret != 0) {
-               DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
-                        strerror(errno)));
-               close(s);
-               return -1;
-       }
-
        ZERO_STRUCT(pkt);
        pkt.ip.version  = 4;
        pkt.ip.ihl      = sizeof(pkt.ip)/4;
@@ -234,17 +219,15 @@ int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
                pkt.tcp.rst      = 1;
        }
        pkt.tcp.doff     = sizeof(pkt.tcp)/4;
-       pkt.tcp.window   = htons(1234);
+       pkt.tcp.window   = htons(1234); /* this makes it easier to spot in a sniffer */
        pkt.tcp.check    = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
 
        ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
        if (ret != sizeof(pkt)) {
                DEBUG(0,(__location__ " failed sendto (%s)\n", strerror(errno)));
-               close(s);
                return -1;
        }
 
-       close(s);
        return 0;
 }
 
@@ -273,113 +256,115 @@ bool ctdb_sys_have_ip(const char *ip)
        return ret == 0;
 }
 
-static void ctdb_wait_handler(struct event_context *ev, struct timed_event *te, 
-                             struct timeval yt, void *p)
+/* 
+   This function is used to open a raw socket to capture from
+ */
+int ctdb_sys_open_capture_socket(void)
 {
-       uint32_t *timed_out = (uint32_t *)p;
-       (*timed_out) = 1;
-}
+       int s;
+
+       /* Open a socket to capture all traffic */
+       s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       if (s == -1) {
+               DEBUG(0,(__location__ " failed to open raw socket\n"));
+               return -1;
+       }
 
-/* This function is used to kill (RST) the specified tcp connection.
+       set_nonblocking(s);
+       set_close_on_exec(s);
 
-   This function is not asynchronous and will block until the operation
-   was successful or it timesout.
+       return s;
+}
+
+/* 
+   This function is used to open a raw socket to send tickles from
  */
-int ctdb_sys_kill_tcp(struct event_context *ev,
-                     const struct sockaddr_in *dst, 
-                     const struct sockaddr_in *src)
+int ctdb_sys_open_sending_socket(void)
 {
        int s, ret;
-       uint32_t timedout;
-       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+       uint32_t one = 1;
+
+       s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+       if (s == -1) {
+               DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
+                        strerror(errno)));
+               return -1;
+       }
+
+       ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
+       if (ret != 0) {
+               DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
+                        strerror(errno)));
+               close(s);
+               return -1;
+       }
+
+       set_nonblocking(s);
+       set_close_on_exec(s);
+
+       return s;
+}
+
+/*
+  called when the raw socket becomes readable
+ */
+int ctdb_sys_read_tcp_packet(int s, struct sockaddr_in *src, struct sockaddr_in *dst,
+                            uint32_t *ack_seq, uint32_t *seq)
+{
+       int ret;
 #define RCVPKTSIZE 100
        char pkt[RCVPKTSIZE];
        struct ether_header *eth;
        struct iphdr *ip;
        struct tcphdr *tcp;
 
-       /* Open a socket to capture all traffic */
-       s=socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-       if (s == -1){
-               DEBUG(0,(__location__ " failed to open raw socket\n"));
+       ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
+       if (ret < sizeof(*eth)+sizeof(*ip)) {
                return -1;
        }
 
-       /* We wait for up to 1 second for the ACK coming back */
-       timedout = 0;
-       event_add_timed(ev, tmp_ctx, timeval_current_ofs(1, 0), ctdb_wait_handler, &timedout);
+       /* Ethernet */
+       eth = (struct ether_header *)pkt;
 
-       /* Send a tickle ack to probe what the real seq/ack numbers are */
-       ctdb_sys_send_tcp(dst, src, 0, 0, 0);
-
-       /* Wait until we either time out or we succeeds in sending the RST */
-       while (timedout==0) {
-               event_loop_once(ev);
-
-               ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
-               if (ret < sizeof(*eth)+sizeof(*ip)) {
-                       continue;
-               }
-
-               /* Ethernet */
-               eth = (struct ether_header *)pkt;
-               /* We only want IP packets */
-               if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
-                       continue;
-               }
+       /* We only want IP packets */
+       if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
+               return -1;
+       }
        
-               /* IP */
-               ip = (struct iphdr *)(eth+1);
-               /* We only want IPv4 packets */
-               if (ip->version != 4) {
-                       continue;
-               }
-               /* Dont look at fragments */
-               if ((ntohs(ip->frag_off)&0x1fff) != 0) {
-                       continue;
-               }
-               /* we only want TCP */
-               if (ip->protocol != IPPROTO_TCP) {
-                       continue;
-               }
-
-               /* We only want packets sent from the guy we tickled */
-               if (ip->saddr != dst->sin_addr.s_addr) {
-                       continue;
-               }
-               /* We only want packets sent to us */
-               if (ip->daddr != src->sin_addr.s_addr) {
-                       continue;
-               }
-
-               /* make sure its not a short packet */
-               if (offsetof(struct tcphdr, ack_seq) + 4 + 
-                   (ip->ihl*4) + sizeof(*eth) > ret) {
-                       continue;
-               }
-
-               /* TCP */
-               tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
-               
-               /* We only want replies from the port we tickled */
-               if (tcp->source != dst->sin_port) {
-                       continue;
-               }
-               if (tcp->dest != src->sin_port) {
-                       continue;
-               }
-
-               ctdb_sys_send_tcp(dst, src, tcp->ack_seq, tcp->seq, 1);
+       /* IP */
+       ip = (struct iphdr *)(eth+1);
 
-               close(s);
-               talloc_free(tmp_ctx);
+       /* We only want IPv4 packets */
+       if (ip->version != 4) {
+               return -1;
+       }
+       /* Dont look at fragments */
+       if ((ntohs(ip->frag_off)&0x1fff) != 0) {
+               return -1;
+       }
+       /* we only want TCP */
+       if (ip->protocol != IPPROTO_TCP) {
+               return -1;
+       }
 
-               return 0;
+       /* make sure its not a short packet */
+       if (offsetof(struct tcphdr, ack_seq) + 4 + 
+           (ip->ihl*4) + sizeof(*eth) > ret) {
+               return -1;
        }
 
-       close(s);
-       talloc_free(tmp_ctx);
-       DEBUG(0,(__location__ " timedout waiting for tickle ack reply\n"));
+       /* TCP */
+       tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
 
-       return -1;
+       /* tell the caller which one we've found */
+       src->sin_addr.s_addr = ip->saddr;
+       src->sin_port        = tcp->source;
+       dst->sin_addr.s_addr = ip->daddr;
+       dst->sin_port        = tcp->dest;
+       *ack_seq             = tcp->ack_seq;
+       *seq                 = tcp->seq;
+
+       return 0;
 }
+
+
index 7f0710c4006d817fc77c6f7f7dfdd969bb235060..5e917aa9908d2abdb8e5e8fa7510b4790d2e6800 100755 (executable)
@@ -70,8 +70,8 @@ case $cmd in
                        srcport=`echo $src | cut -d: -f2`
                        destip=`echo $dest | cut -d: -f1`
                        destport=`echo $dest | cut -d: -f2`
-                       ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 
-#                      ctdb killtcp $destip:$destport $srcip:$srcport >/dev/null 2>&1
+                       ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 
+#                      ctdb killtcp $destip:$destport $srcip:$srcport >/dev/null 2>&1
                done
        } > /dev/null 2>&1
 
@@ -84,8 +84,8 @@ case $cmd in
                        srcport=`echo $src | cut -d: -f2`
                        destip=`echo $dest | cut -d: -f1`
                        destport=`echo $dest | cut -d: -f2`
-                       ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 
-                       ctdb killtcp $destip:$destport $srcip:$srcport >/dev/null 2>&1
+                       ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 
+                       ctdb killtcp $destip:$destport $srcip:$srcport >/dev/null 2>&1
                done
        } > /dev/null 2>&1
        /bin/rm -f /etc/ctdb/state/nfs/restart
index 682d813028e96919d2a4cbdd6ecd03007526cbc0..a50aa3fe64fb184cb51399db2a57b391e289ba07 100644 (file)
@@ -1,6 +1,6 @@
 .\"     Title: ctdbd
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.72.0 <http://docbook.sf.net/>
+.\" Generator: DocBook XSL Stylesheets v1.71.0 <http://docbook.sf.net/>
 .\"      Date: 07/10/2007
 .\"    Manual: 
 .\"    Source: 
@@ -31,91 +31,91 @@ ctdbd is the main component in clustered Samba that provides a high\-awailabilit
 .SH "OPTIONS"
 .PP
 \-? \-\-help
-.RS 4
+.RS 3n
 Print some help text to the screen.
 .RE
 .PP
 \-\-usage
-.RS 4
+.RS 3n
 Print useage information to the screen.
 .RE
 .PP
 \-\-reclock=<filename>
-.RS 4
+.RS 3n
 This is the name of the lock file stored of the shared cluster filesystem that ctdbd uses to arbitrate which node has the role of recovery\-master. This file must be stored on shared storage.
 .RE
 .PP
 \-\-nlist=<filename>
-.RS 4
+.RS 3n
 This file contains a list of the private ip addresses of every node in the cluster. There is one line/ip address for each node. This file must be the same for all nodes in the cluster.
 .sp
 This file is usually /etc/ctdb/nodes .
 .RE
 .PP
 \-\-dbdir=<directory>
-.RS 4
+.RS 3n
 This is the directory on local storage where ctdbd keeps the local copy of the TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem.
 .sp
 This directory would usually be /var/ctdb .
 .RE
 .PP
 \-i \-\-interactive
-.RS 4
+.RS 3n
 By default ctdbd will detach itself from the shell and run in the background as a daemon. This option makes ctdbd to start in interactive mode.
 .RE
 .PP
 \-\-public_addresses=<filename>
-.RS 4
+.RS 3n
 When used with IP takeover this specifies a file containing the public ip addresses to use on the cluster. This file contains one entry for each node in the cluster.
 .sp
 This is usually the file /etc/ctdb/public_addresses
 .RE
 .PP
 \-\-public\-interface=<interface>
-.RS 4
+.RS 3n
 When used with IP takeover this option specifies which physical interface should be used to attach the public addresses to.
 .RE
 .PP
 \-\-event\-script=<filename>
-.RS 4
+.RS 3n
 This option is used to specify which events script that ctdbd will use to manage services when the cluster configuration changes.
 .sp
 This will normally be /etc/ctdb/events which is part of the ctdb distribution.
 .RE
 .PP
 \-\-logfile=<filename>
-.RS 4
+.RS 3n
 This is the file where ctdbd will write its log. This is usually /var/log/log.ctdb .
 .RE
 .PP
 \-\-listen=<address>
-.RS 4
+.RS 3n
 This specifies which ip address ctdb will bind to. By default ctdbd will bind to the first address it finds in the /etc/ctdb/nodes file and which is also present on the local system in which case you do not need to provide this option.
 .sp
 This option is only required when you want to run multiple ctdbd daemons/nodes on the same physical host in which case there would be multiple entries in /etc/ctdb/nodes what would match a local interface.
 .RE
 .PP
 \-\-transport=<STRING>
-.RS 4
+.RS 3n
 This option specifies which transport to use for ctdbd internode communications. The default is "tcp".
 .sp
 Suported transports are "tcp" and "infiniband".
 .RE
 .PP
 \-\-socket=<filename>
-.RS 4
+.RS 3n
 This specifies the name of the domain socket that ctdbd will create. This socket is used for local clients to attach to and communicate with the ctdbd daemon.
 .sp
 The default is /tmp/ctdb.socket . You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host.
 .RE
 .PP
 \-d \-\-debug=<DEBUGLEVEL>
-.RS 4
+.RS 3n
 This option sets the debuglevel on the ctdbd daemon which controls what will be written to the logfile. The default is 0 which will only log important events and errors. A larger number will provide additional logging.
 .RE
 .PP
 \-\-torture
-.RS 4
+.RS 3n
 This option is only used for development and testing of ctdbd. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly for failures.
 .sp
 You do NOT want to use this option unless you are developing and testing new functionality in ctdbd.
@@ -136,7 +136,7 @@ Since the private addresses are only available to the network when the correspon
       Example /etc/ctdb/nodes for a four node cluster:
       
 .sp
-.RS 4
+.RS 3n
 .nf
         10.1.1.1
         10.1.1.2
@@ -160,7 +160,7 @@ The list of public addresses also contain the netmask for that address. the reas
       Example /etc/ctdb/public_addresses for a four node cluster:
       
 .sp
-.RS 4
+.RS 3n
 .nf
         11.1.1.1/24
         11.1.1.2/24
@@ -192,7 +192,7 @@ ctdb(1), onnode(1)
 \fI\%http://ctdb.samba.org/\fR
 .SH "COPYRIGHT/LICENSE"
 .sp
-.RS 4
+.RS 3n
 .nf
 Copyright (C) Andrew Tridgell 2007
 Copyright (C) Ronnie sahlberg 2007
index 49d2fdc468ce965871553e37c8e6a77528e1e825..90b8be1113fb13ee2a1920dfda180caac8bff949 100644 (file)
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd</title><meta name="generator" content="DocBook XSL Stylesheets V1.72.0"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en"><a name="ctdbd.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd &#8212; The CTDB cluster daemon</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdbd</code> </p></div><div class="cmdsynopsis"><p><code class="command">ctdbd</code>  {--reclock=&lt;filename&gt;} {--nlist=&lt;filename&gt;} {--dbdir=&lt;directory&gt;} [-? --help] [--usage] [-i --interactive] [--public-addresses=&lt;filename&gt;] [--public-interface=&lt;interface&gt;] [--event-script=&lt;filename&gt;] [--logfile=&lt;filename&gt;] [--listen=&lt;address&gt;] [--transport=&lt;STRING&gt;] [--socket=&lt;filename&gt;] [-d --debug=&lt;INTEGER&gt;] [--torture]</p></div></div><div class="refsect1" lang="en"><a name="id2488930"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd</title><meta name="generator" content="DocBook XSL Stylesheets V1.71.0"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en"><a name="ctdbd.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd &#8212; The CTDB cluster daemon</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdbd</code> </p></div><div class="cmdsynopsis"><p><code class="command">ctdbd</code>  {--reclock=&lt;filename&gt;} {--nlist=&lt;filename&gt;} {--dbdir=&lt;directory&gt;} [-? --help] [--usage] [-i --interactive] [--public-addresses=&lt;filename&gt;] [--public-interface=&lt;interface&gt;] [--event-script=&lt;filename&gt;] [--logfile=&lt;filename&gt;] [--listen=&lt;address&gt;] [--transport=&lt;STRING&gt;] [--socket=&lt;filename&gt;] [-d --debug=&lt;INTEGER&gt;] [--torture]</p></div></div><div class="refsect1" lang="en"><a name="id2481068"></a><h2>DESCRIPTION</h2><p>
       ctdbd is the main ctdb daemon.
     </p><p>
       ctdbd provides a clustered version of the TDB database with automatic rebuild/recovery of the databases upon nodefailures.
@@ -8,7 +8,7 @@
       ctdbd provides monitoring of all nodes in the cluster and automatically reconfigures the cluster and recovers upon node failures.
     </p><p>
       ctdbd is the main component in clustered Samba that provides a high-awailability load-sharing CIFS server cluster.
-    </p></div><div class="refsect1" lang="en"><a name="id2488962"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">-? --help</span></dt><dd><p>
+    </p></div><div class="refsect1" lang="en"><a name="id2481100"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">-? --help</span></dt><dd><p>
             Print some help text to the screen.
           </p></dd><dt><span class="term">--usage</span></dt><dd><p>
             Print useage information to the screen.
             This option is only used for development and testing of ctdbd. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly for failures.
           </p><p>
             You do NOT want to use this option unless you are developing and testing new functionality in ctdbd.
-          </p></dd></dl></div></div><div class="refsect1" lang="en"><a name="id2490376"></a><h2>Private vs Public addresses</h2><p>
+          </p></dd></dl></div></div><div class="refsect1" lang="en"><a name="id2528438"></a><h2>Private vs Public addresses</h2><p>
       When used for ip takeover in a HA environment, each node in a ctdb 
       cluster has two ip addresses assigned to it. One private and one public.
-    </p><div class="refsect2" lang="en"><a name="id2490386"></a><h3>Private address</h3><p>
+    </p><div class="refsect2" lang="en"><a name="id2528448"></a><h3>Private address</h3><p>
         This is the physical ip address of the node which is configured in 
         linux and attached to a physical interface. This address uniquely
         identifies a physical node in the cluster and is the ip addresses
@@ -89,7 +89,7 @@
         10.1.1.2
         10.1.1.3
         10.1.1.4
-      </pre></div><div class="refsect2" lang="en"><a name="id2490432"></a><h3>Public address</h3><p>
+      </pre></div><div class="refsect2" lang="en"><a name="id2528495"></a><h3>Public address</h3><p>
         A public address on the other hand is not attached to an interface.
         This address is managed by ctdbd itself and is attached/detached to
         a physical node at runtime. You should NOT have this address configured
         In this example, if node 3 fails, its public address can be taken over 
         by node 2 since node 2 is on the same subnet as 3 but not by node 0 or 
         node 1 since node 0 and 1 are both on a different subnet from node 3.
-      </p></div></div><div class="refsect1" lang="en"><a name="id2536612"></a><h2>Node status</h2><p>
+      </p></div></div><div class="refsect1" lang="en"><a name="id2528564"></a><h2>Node status</h2><p>
       The current status of each node in the cluster can be viewed by the 
       'ctdb status' command.
     </p><p>
       investigated and require an administrative action to rectify. This node 
       does not perticipate in the CTDB cluster but can still be communicated 
       with. I.e. ctdb commands can be sent to it.
-    </p></div><div class="refsect1" lang="en"><a name="id2536669"></a><h2>SEE ALSO</h2><p>
+    </p></div><div class="refsect1" lang="en"><a name="id2528621"></a><h2>SEE ALSO</h2><p>
       ctdb(1), onnode(1)
       <a href="http://ctdb.samba.org/" target="_top">http://ctdb.samba.org/</a>
-    </p></div><div class="refsect1" lang="en"><a name="id2536682"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
+    </p></div><div class="refsect1" lang="en"><a name="id2528634"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
 Copyright (C) Andrew Tridgell 2007<br>
 Copyright (C) Ronnie sahlberg 2007<br>
 <br>
index be3b832832a6b008501fec9528ef059613553171..9c33747dcd6710b469c2fa13f24071444f008f02 100644 (file)
@@ -309,6 +309,7 @@ struct ctdb_context {
        struct ctdb_client_ip *client_ip_list;
        bool do_setsched;
        void *saved_scheduler_param;
+       struct ctdb_kill_tcp *killtcp;
 };
 
 struct ctdb_db_context {
@@ -408,6 +409,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS          = 0,
                    CTDB_CONTROL_GET_PUBLIC_IPS          = 51,
                    CTDB_CONTROL_MODIFY_FLAGS            = 52,
                    CTDB_CONTROL_GET_ALL_TUNABLES        = 53,
+                   CTDB_CONTROL_KILL_TCP                = 54,
 };
 
 /*
@@ -443,6 +445,14 @@ struct ctdb_control_tcp {
        struct sockaddr_in dest;
 };
 
+/*
+  struct for kill_tcp control
+ */
+struct ctdb_control_killtcp {
+       struct sockaddr_in src;
+       struct sockaddr_in dst;
+};
+
 /*
   struct for tcp_add and tcp_remove controls
  */
@@ -983,12 +993,10 @@ int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
 /* 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_send_tcp(const struct sockaddr_in *dest, 
+int ctdb_sys_send_tcp(int fd,
+                     const struct sockaddr_in *dest, 
                      const struct sockaddr_in *src,
                      uint32_t seq, uint32_t ack, int rst);
-int ctdb_sys_kill_tcp(struct event_context *ev,
-                     const struct sockaddr_in *dest, 
-                     const struct sockaddr_in *src);
 
 int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
 int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script);
@@ -999,6 +1007,7 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
 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);
+int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata);
 
 void ctdb_takeover_client_destructor_hook(struct ctdb_client *client);
 int ctdb_event_script(struct ctdb_context *ctdb, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
@@ -1035,4 +1044,15 @@ void ctdb_start_freeze(struct ctdb_context *ctdb);
 
 bool parse_ip_port(const char *s, struct sockaddr_in *ip);
 
+int ctdb_sys_open_capture_socket(void);
+int ctdb_sys_open_sending_socket(void);
+int ctdb_sys_read_tcp_packet(int s, struct sockaddr_in *src, struct sockaddr_in *dst,
+                            uint32_t *ack_seq, uint32_t *seq);
+
+int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, 
+                     struct timeval timeout, 
+                     uint32_t destnode,
+                     struct ctdb_control_killtcp *killtcp);
+
+
 #endif
index bbe07717ed830ee84e95742cf88bdf0bbc5220e6..b448fe014348ac794cb63d64766a139bc7b17a2c 100644 (file)
@@ -223,7 +223,8 @@ static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db,
   must be called with the chainlock held. This function releases the chainlock
 */
 static void ctdb_become_dmaster(struct ctdb_db_context *ctdb_db, 
-                               uint32_t reqid, TDB_DATA key, TDB_DATA data,
+                               struct ctdb_req_header *hdr,
+                               TDB_DATA key, TDB_DATA data,
                                uint64_t rsn)
 {
        struct ctdb_call_state *state;
@@ -242,18 +243,18 @@ static void ctdb_become_dmaster(struct ctdb_db_context *ctdb_db,
                return;
        }
 
-       state = ctdb_reqid_find(ctdb, reqid, struct ctdb_call_state);
+       state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
 
        if (state == NULL) {
-               DEBUG(0,("vnn %u Invalid reqid %u in ctdb_become_dmaster\n",
-                        ctdb->vnn, reqid));
+               DEBUG(0,("vnn %u Invalid reqid %u in ctdb_become_dmaster from node %u\n",
+                        ctdb->vnn, hdr->reqid, hdr->srcnode));
                ctdb_ltdb_unlock(ctdb_db, key);
                return;
        }
 
-       if (reqid != state->reqid) {
+       if (hdr->reqid != state->reqid) {
                /* we found a record  but it was the wrong one */
-               DEBUG(0, ("Dropped orphan in ctdb_become_dmaster with reqid:%u\n",reqid));
+               DEBUG(0, ("Dropped orphan in ctdb_become_dmaster with reqid:%u\n from node %u", hdr->reqid, hdr->srcnode));
                ctdb_ltdb_unlock(ctdb_db, key);
                return;
        }
@@ -334,7 +335,7 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
        /* check if the new dmaster is the lmaster, in which case we
           skip the dmaster reply */
        if (c->dmaster == ctdb->vnn) {
-               ctdb_become_dmaster(ctdb_db, hdr->reqid, key, data, c->rsn);
+               ctdb_become_dmaster(ctdb_db, hdr, key, data, c->rsn);
        } else {
                ctdb_send_dmaster_reply(ctdb_db, &header, key, data, c->dmaster, hdr->reqid);
                ctdb_ltdb_unlock(ctdb_db, key);
@@ -505,7 +506,7 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                return;
        }
 
-       ctdb_become_dmaster(ctdb_db, hdr->reqid, key, data, c->rsn);
+       ctdb_become_dmaster(ctdb_db, hdr, key, data, c->rsn);
 }
 
 
index 69848bb15cd4499329aa4b4a66a46540dec023d1..6d170156572a31e181da55468002648a99e3bbc8 100644 (file)
@@ -286,6 +286,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
                CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_node_modflags));
                return ctdb_control_modflags(ctdb, indata);
 
+       case CTDB_CONTROL_KILL_TCP: 
+               CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_killtcp));
+               return ctdb_control_kill_tcp(ctdb, indata);
+
        default:
                DEBUG(0,(__location__ " Unknown CTDB control opcode %u\n", opcode));
                return -1;
index 1480127327cd24f0b679aa88e02f5516f1ca74c0..4fd5b192db9cf51daa5d29e39bd504c4acad3ec0 100644 (file)
@@ -237,11 +237,13 @@ void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                   same generation instance as this node
                */
                if (ctdb->vnn_map->generation != hdr->generation) {
-                       DEBUG(0,(__location__ " ctdb request %u"
+                       DEBUG(0,(__location__ " ctdb operation %u"
+                               " request %u"
                                " length %u from node %u to %u had an"
                                " invalid generation id:%u while our"
                                " generation id is:%u\n", 
-                                hdr->reqid, hdr->length, 
+                                hdr->operation, hdr->reqid,
+                                hdr->length, 
                                 hdr->srcnode, hdr->destnode, 
                                 hdr->generation, ctdb->vnn_map->generation));
                        goto done;
index 42a23808ddb2d7501556374c0c5da298c5c2b11e..a4536e1c9dc53cace23c0a7c7528115c7d3bd8b0 100644 (file)
@@ -69,7 +69,7 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
 {
        struct ctdb_takeover_arp *arp = talloc_get_type(private_data, 
                                                        struct ctdb_takeover_arp);
-       int ret;
+       int s, ret;
        struct ctdb_tcp_list *tcp;
 
        ret = ctdb_sys_send_arp(&arp->sin, arp->ctdb->takeover.interface);
@@ -77,25 +77,32 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
                DEBUG(0,(__location__ " sending of arp failed (%s)\n", strerror(errno)));
        }
 
+       s = ctdb_sys_open_sending_socket();
+       if (s == -1) {
+               DEBUG(0,(__location__ " failed to open raw socket for sending tickles\n"));
+               return;
+       }
+
        for (tcp=arp->tcp_list;tcp;tcp=tcp->next) {
                DEBUG(2,("sending tcp tickle ack for %u->%s:%u\n",
                         (unsigned)ntohs(tcp->daddr.sin_port), 
                         inet_ntoa(tcp->saddr.sin_addr),
                         (unsigned)ntohs(tcp->saddr.sin_port)));
-               ret = ctdb_sys_send_tcp(&tcp->saddr, &tcp->daddr, 0, 0, 0);
+               ret = ctdb_sys_send_tcp(s, &tcp->saddr, &tcp->daddr, 0, 0, 0);
                if (ret != 0) {
                        DEBUG(0,(__location__ " Failed to send tcp tickle ack for %s\n",
                                 inet_ntoa(tcp->saddr.sin_addr)));
                }
        }
 
+       close(s);
        arp->count++;
 
        if (arp->count == CTDB_ARP_REPEAT) {
                talloc_free(arp);
                return;
        }
-       
+
        event_add_timed(arp->ctdb->ev, arp->ctdb->takeover.last_ctx, 
                        timeval_current_ofs(CTDB_ARP_INTERVAL, 0), 
                        ctdb_control_send_arp, arp);
@@ -679,6 +686,7 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
        return 0;
 }
 
+
 /*
   called by a daemon to inform us of a TCP connection that one of its
   clients managing that should tickled with an ACK when IP takeover is
@@ -795,12 +803,14 @@ void ctdb_release_all_ips(struct ctdb_context *ctdb)
 /*
   get list of public IPs
  */
-int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata)
+int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, 
+                                   struct ctdb_req_control *c, TDB_DATA *outdata)
 {
        int i, len;
        struct ctdb_all_public_ips *ips;
 
-       len = offsetof(struct ctdb_all_public_ips, ips) + ctdb->num_nodes*sizeof(struct ctdb_public_ip);
+       len = offsetof(struct ctdb_all_public_ips, ips) + 
+               ctdb->num_nodes*sizeof(struct ctdb_public_ip);
 
        ips = talloc_zero_size(outdata, len);
        CTDB_NO_MEMORY(ctdb, ips);
@@ -814,9 +824,233 @@ int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, struct ctdb_req_c
                ips->ips[i].takeover_vnn = ctdb->nodes[i]->takeover_vnn;
                ips->ips[i].sin.sin_family = AF_INET;
                if (ctdb->nodes[i]->public_address) {
-                       inet_aton(ctdb->nodes[i]->public_address, &ips->ips[i].sin.sin_addr);
+                       inet_aton(ctdb->nodes[i]->public_address, 
+                                 &ips->ips[i].sin.sin_addr);
+               }
+       }
+
+       return 0;
+}
+
+
+
+
+/*
+  list of tcp connections to kill
+ */
+struct ctdb_killtcp_connection {
+       struct ctdb_killtcp_connection *prev, *next;
+       struct ctdb_context *ctdb;
+       struct sockaddr_in src;
+       struct sockaddr_in dst;
+       int count;
+};
+
+/* 
+   structure containing the listening socket and the list of tcp connections
+   that the ctdb daemon is to kill
+*/
+struct ctdb_kill_tcp {
+       struct ctdb_context *ctdb;
+       int capture_fd;
+       int sending_fd;
+       struct fd_event *fde;
+       struct ctdb_killtcp_connection *connections;
+};
+
+/*
+  called when we get a read event on the raw socket
+ */
+static void capture_tcp_handler(struct event_context *ev, struct fd_event *fde, 
+                               uint16_t flags, void *private_data)
+{
+       struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+       struct sockaddr_in src, dst;
+       struct ctdb_killtcp_connection *conn;
+       uint32_t ack_seq, seq;
+
+       if (!(flags & EVENT_FD_READ)) {
+               return;
+       }
+
+       if (ctdb_sys_read_tcp_packet(killtcp->capture_fd, &src, &dst,
+                                    &ack_seq, &seq) != 0) {
+               /* probably a non-tcp ACK packet */
+               return;
+       }
+
+       /* loop over all connections and see if we find one that matches */
+       for (conn = killtcp->connections; conn; conn = conn->next) {
+               /* We only want packets sent from a guy we have tickled */
+               if (src.sin_addr.s_addr != conn->dst.sin_addr.s_addr) {
+                       continue;
+               }
+               /* We only want packets sent to us */
+               if (dst.sin_addr.s_addr != conn->src.sin_addr.s_addr) {
+                       continue;
+               }
+               /* We only want replies from a port we tickled */
+               if (src.sin_port != conn->dst.sin_port) {
+                       continue;
+               }
+               if (dst.sin_port != conn->src.sin_port) {
+                       continue;
+               }
+
+               /* This one has been tickled !
+                  now reset him and remove him from the list.
+                */
+               ctdb_sys_send_tcp(killtcp->sending_fd, &conn->dst, 
+                                 &conn->src, ack_seq, seq, 1);
+               talloc_free(conn);
+               break;
+       }
+}
+
+
+/* called every second until all sentenced connections have been reset
+ */
+static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct timed_event *te, 
+                                             struct timeval t, void *private_data)
+{
+       struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+       struct ctdb_killtcp_connection *conn, *next;
+
+       /* loop over all connections sending tickle ACKs */
+       for (conn = killtcp->connections; conn; conn = next) {
+               next = conn->next;
+               conn->count++;
+               if (conn->count > 5) {
+                       talloc_free(conn);
+                       continue;
                }
+               ctdb_sys_send_tcp(killtcp->sending_fd, &conn->dst, &conn->src, 0, 0, 0);
        }
 
+       /* If there are no more connections to kill we can remove the
+          entire killtcp structure
+        */
+       if (killtcp->connections == NULL) {
+               talloc_free(killtcp);
+               return;
+       }
+
+       /* try tickling them again in a seconds time
+        */
+       event_add_timed(killtcp->ctdb->ev, killtcp, timeval_current_ofs(1, 0), 
+                       ctdb_tickle_sentenced_connections, killtcp);
+}
+
+/*
+  destroy the killtcp structure
+ */
+static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
+{
+       if (killtcp->sending_fd != -1) {
+               close(killtcp->sending_fd);
+               killtcp->sending_fd = -1;
+       }
+       killtcp->ctdb->killtcp = NULL;
+       return 0;
+}
+
+/*
+  destroy a killtcp connection structure
+ */
+static int ctdb_killtcp_connection_destructor(struct ctdb_killtcp_connection *conn)
+{
+       DLIST_REMOVE(conn->ctdb->killtcp->connections, conn);
+       return 0;
+}
+
+/*
+  add a tcp socket to the list of connections we will kill on failover
+ */
+static int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, 
+                                      struct sockaddr_in *src, struct sockaddr_in *dst)
+{
+       struct ctdb_kill_tcp *killtcp = ctdb->killtcp;
+       struct ctdb_killtcp_connection *conn;
+       
+       /* If this is the first connection to kill we must allocate
+          a new structure
+        */
+       if (killtcp == NULL) {
+               killtcp = talloc(ctdb, struct ctdb_kill_tcp);
+               CTDB_NO_MEMORY(ctdb, killtcp);
+
+               killtcp->ctdb        = ctdb;
+               killtcp->capture_fd  = -1;
+               killtcp->sending_fd  = -1;
+               killtcp->connections = NULL;
+               ctdb->killtcp        = killtcp;
+               talloc_set_destructor(killtcp, ctdb_killtcp_destructor);
+       }
+
+       conn = talloc(killtcp, struct ctdb_killtcp_connection);
+       CTDB_NO_MEMORY(ctdb, conn);
+       conn->src   = *src;
+       conn->dst   = *dst;
+       conn->ctdb  = ctdb;
+       conn->count = 0;
+       talloc_set_destructor(conn, ctdb_killtcp_connection_destructor);
+       DLIST_ADD(killtcp->connections, conn);
+
+       /* 
+          If we dont have a socket to send from yet we must create it
+        */
+       if (killtcp->sending_fd == -1) {
+               killtcp->sending_fd = ctdb_sys_open_sending_socket();
+               if (killtcp->sending_fd == -1) {
+                       DEBUG(0,(__location__ " Failed to open sending socket for killtcp\n"));
+                       goto failed;
+               }
+       }
+
+       /* 
+          If we dont have a socket to listen on yet we must create it
+        */
+       if (killtcp->capture_fd == -1) {
+               killtcp->capture_fd = ctdb_sys_open_capture_socket();
+               if (killtcp->capture_fd == -1) {
+                       DEBUG(0,(__location__ " Failed to open capturing socket for killtcp\n"));
+                       goto failed;
+               }
+       }
+
+
+       if (killtcp->fde == NULL) {
+               killtcp->fde = event_add_fd(ctdb->ev, killtcp, killtcp->capture_fd, 
+                                           EVENT_FD_READ | EVENT_FD_AUTOCLOSE, 
+                                           capture_tcp_handler, killtcp);
+
+               /* We also need to set up some events to tickle all these connections
+                  until they are all reset
+               */
+               event_add_timed(ctdb->ev, killtcp, timeval_current_ofs(0, 0), 
+                               ctdb_tickle_sentenced_connections, killtcp);
+       }
+
+       /* tickle him once now */
+       ctdb_sys_send_tcp(killtcp->sending_fd, &conn->dst, &conn->src, 0, 0, 0);
+
+       return 0;
+
+failed:
+       talloc_free(ctdb->killtcp);
+       ctdb->killtcp = NULL;
+       return -1;
+}
+
+/*
+  called by a daemon to inform us of a TCP connection that one of its
+  clients managing that should reset when IP takeover is done
+ */
+int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+       struct ctdb_control_killtcp *killtcp = (struct ctdb_control_killtcp *)indata.dptr;
+
+       ctdb_killtcp_add_connection(ctdb, &killtcp->src, &killtcp->dst);
+
        return 0;
 }
index 2308261d00535eb0079063ed30bf2a1ac7ee5587..55609e4f3e58bd3e5486eaa56fa4ea7056ebe5d8 100644 (file)
@@ -307,32 +307,27 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
  */
 static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       int i, ret, numrst;
-       struct sockaddr_in src, dst;
+       int ret;
+       struct ctdb_control_killtcp killtcp;
 
-       if (argc < 3) {
+       if (argc < 2) {
                usage();
        }
 
-       if (!parse_ip_port(argv[0], &src)) {
+       if (!parse_ip_port(argv[0], &killtcp.src)) {
                printf("Bad IP:port '%s'\n", argv[0]);
                return -1;
        }
 
-       if (!parse_ip_port(argv[1], &dst)) {
+       if (!parse_ip_port(argv[1], &killtcp.dst)) {
                printf("Bad IP:port '%s'\n", argv[1]);
                return -1;
        }
 
-       numrst = strtoul(argv[2], NULL, 0);
-
-       for (i=0;i<numrst;i++) {
-               ret = ctdb_sys_kill_tcp(ctdb->ev, &src, &dst);
-
-               printf("ret:%d\n", ret);
-               if (ret==0) {
-                       return 0;
-               }
+       ret = ctdb_ctrl_killtcp(ctdb, TIMELIMIT(), options.vnn, &killtcp);
+       if (ret != 0) {
+               printf("Unable to killtcp from node %u\n", options.vnn);
+               return ret;
        }
 
        return -1;
@@ -343,7 +338,7 @@ static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
  */
 static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       int ret;
+       int s, ret;
        struct sockaddr_in src, dst;
 
        if (argc < 2) {
@@ -360,7 +355,14 @@ static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
                return -1;
        }
 
-       ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
+       s = ctdb_sys_open_sending_socket();
+       if (s == -1) {
+               printf("Failed to open socket for sending tickle\n");
+               return 0;
+       }
+
+       ret = ctdb_sys_send_tcp(s, &src, &dst, 0, 0, 0);
+       close(s);
        if (ret==0) {
                return 0;
        }
@@ -890,7 +892,7 @@ static const struct {
        { "recover",         control_recover,           true,  "force recovery" },
        { "freeze",          control_freeze,            true,  "freeze all databases" },
        { "thaw",            control_thaw,              true,  "thaw all databases" },
-       { "killtcp",         kill_tcp,                  false, "kill a tcp connection. Try <num> times.", "<srcip:port> <dstip:port> <num>" },
+       { "killtcp",         kill_tcp,                  false, "kill a tcp connection.", "<srcip:port> <dstip:port>" },
        { "tickle",          tickle_tcp,                false, "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
 };