Do not install iptables rules, they should stay active after shutdown
[strongswan.git] / src / charon / plugins / ha / ha_kernel.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "ha_kernel.h"
17
18 typedef u_int32_t u32;
19 typedef u_int8_t u8;
20
21 #include <linux/jhash.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 #define CLUSTERIP_DIR "/proc/net/ipt_CLUSTERIP"
30
31 typedef struct private_ha_kernel_t private_ha_kernel_t;
32
33 /**
34 * Private data of an ha_kernel_t object.
35 */
36 struct private_ha_kernel_t {
37
38 /**
39 * Public ha_kernel_t interface.
40 */
41 ha_kernel_t public;
42
43 /**
44 * Init value for jhash
45 */
46 u_int initval;
47
48 /**
49 * Total number of ClusterIP segments
50 */
51 u_int count;
52 };
53
54 /**
55 * Implementation of ha_kernel_t.in_segment
56 */
57 static bool in_segment(private_ha_kernel_t *this, host_t *host, u_int segment)
58 {
59 if (host->get_family(host) == AF_INET)
60 {
61 unsigned long hash;
62 u_int32_t addr;
63
64 addr = *(u_int32_t*)host->get_address(host).ptr;
65 hash = jhash_1word(ntohl(addr), this->initval);
66
67 if ((((u_int64_t)hash * this->count) >> 32) + 1 == segment)
68 {
69 return TRUE;
70 }
71 }
72 return FALSE;
73 }
74
75 /**
76 * Activate/Deactivate a segment for a given clusterip file
77 */
78 static void enable_disable(private_ha_kernel_t *this, u_int segment,
79 char *file, bool enable)
80 {
81 char cmd[8];
82 int fd;
83
84 snprintf(cmd, sizeof(cmd), "%c%d\n", enable ? '+' : '-', segment);
85
86 fd = open(file, O_WRONLY);
87 if (fd == -1)
88 {
89 DBG1(DBG_CFG, "opening CLUSTERIP file '%s' failed: %s",
90 file, strerror(errno));
91 return;
92 }
93 if (write(fd, cmd, strlen(cmd) == -1))
94 {
95 DBG1(DBG_CFG, "writing to CLUSTERIP file '%s' failed: %s",
96 file, strerror(errno));
97 }
98 close(fd);
99 }
100
101 /**
102 * Get the currenlty active segments in the kernel for a clusterip file
103 */
104 static segment_mask_t get_active(private_ha_kernel_t *this, char *file)
105 {
106 char buf[256];
107 segment_mask_t mask = 0;
108 ssize_t len;
109 int fd;
110
111 fd = open(file, O_RDONLY);
112 if (fd == -1)
113 {
114 DBG1(DBG_CFG, "opening CLUSTERIP file '%s' failed: %s",
115 file, strerror(errno));
116 return 0;
117 }
118 len = read(fd, buf, sizeof(buf)-1);
119 if (len == -1)
120 {
121 DBG1(DBG_CFG, "reading from CLUSTERIP file '%s' failed: %s",
122 file, strerror(errno));
123 }
124 else
125 {
126 enumerator_t *enumerator;
127 u_int segment;
128 char *token;
129
130 buf[len] = '\0';
131 enumerator = enumerator_create_token(buf, ",", " ");
132 while (enumerator->enumerate(enumerator, &token))
133 {
134 segment = atoi(token);
135 if (segment)
136 {
137 mask |= SEGMENTS_BIT(segment);
138 }
139 }
140 enumerator->destroy(enumerator);
141 }
142 return mask;
143 }
144
145 /**
146 * Implementation of ha_kernel_t.activate
147 */
148 static void activate(private_ha_kernel_t *this, u_int segment)
149 {
150 enumerator_t *enumerator;
151 char *file;
152
153 enumerator = enumerator_create_directory(CLUSTERIP_DIR);
154 while (enumerator->enumerate(enumerator, NULL, &file, NULL))
155 {
156 enable_disable(this, segment, file, TRUE);
157 }
158 enumerator->destroy(enumerator);
159 }
160
161 /**
162 * Implementation of ha_kernel_t.deactivate
163 */
164 static void deactivate(private_ha_kernel_t *this, u_int segment)
165 {
166 enumerator_t *enumerator;
167 char *file;
168
169 enumerator = enumerator_create_directory(CLUSTERIP_DIR);
170 while (enumerator->enumerate(enumerator, NULL, &file, NULL))
171 {
172 enable_disable(this, segment, file, FALSE);
173 }
174 enumerator->destroy(enumerator);
175 }
176
177 /**
178 * Enable all not-yet enabled segments on all clusterip addresses
179 */
180 static void activate_all(private_ha_kernel_t *this)
181 {
182 enumerator_t *enumerator;
183 segment_mask_t active;
184 char *file;
185 int i;
186
187 enumerator = enumerator_create_directory(CLUSTERIP_DIR);
188 while (enumerator->enumerate(enumerator, NULL, &file, NULL))
189 {
190 active = get_active(this, file);
191 for (i = 1; i <= this->count; i++)
192 {
193 if (!(active & SEGMENTS_BIT(i)))
194 {
195 enable_disable(this, i, file, TRUE);
196 }
197 }
198 }
199 enumerator->destroy(enumerator);
200 }
201
202 /**
203 * Implementation of ha_kernel_t.destroy.
204 */
205 static void destroy(private_ha_kernel_t *this)
206 {
207 free(this);
208 }
209
210 /**
211 * See header
212 */
213 ha_kernel_t *ha_kernel_create(u_int count)
214 {
215 private_ha_kernel_t *this = malloc_thing(private_ha_kernel_t);
216
217 this->public.in_segment = (bool(*)(ha_kernel_t*, host_t *host, u_int segment))in_segment;
218 this->public.activate = (void(*)(ha_kernel_t*, u_int segment))activate;
219 this->public.deactivate = (void(*)(ha_kernel_t*, u_int segment))deactivate;
220 this->public.destroy = (void(*)(ha_kernel_t*))destroy;
221
222 this->initval = 0;
223 this->count = count;
224
225 activate_all(this);
226
227 return &this->public;
228 }
229