6f9985bc15d4221e45e28a06ce289aa7f67f636a
[strongswan.git] / src / charon / plugins / ha_sync / ha_sync_segments.c
1 /*
2 * Copyright (C) 2008 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 * $Id$
16 */
17
18 #include "ha_sync_segments.h"
19
20 #include <utils/linked_list.h>
21
22 typedef u_int32_t u32;
23 typedef u_int8_t u8;
24
25 #include <linux/jhash.h>
26
27 #define MAX_SEGMENTS 16
28
29 typedef struct private_ha_sync_segments_t private_ha_sync_segments_t;
30
31 /**
32 * Private data of an ha_sync_segments_t object.
33 */
34 struct private_ha_sync_segments_t {
35
36 /**
37 * Public ha_sync_segments_t interface.
38 */
39 ha_sync_segments_t public;
40
41 /**
42 * Init value for jhash
43 */
44 u_int initval;
45
46 /**
47 * Total number of ClusterIP segments
48 */
49 u_int segment_count;
50
51 /**
52 * mask of active segments
53 */
54 u_int16_t active;
55 };
56
57 /**
58 * Check if a host address is in the CLUSTERIP segment
59 */
60 static bool in_segment(private_ha_sync_segments_t *this,
61 host_t *host, u_int segment)
62 {
63 if (host->get_family(host) == AF_INET)
64 {
65 unsigned long hash;
66 u_int32_t addr;
67
68 addr = *(u_int32_t*)host->get_address(host).ptr;
69 hash = jhash_1word(ntohl(addr), this->initval);
70
71 if ((((u_int64_t)hash * this->segment_count) >> 32) + 1 == segment)
72 {
73 return TRUE;
74 }
75 }
76 return FALSE;
77 }
78
79 /**
80 * Log currently active segments
81 */
82 static void log_segments(private_ha_sync_segments_t *this, bool activated,
83 u_int segment)
84 {
85 char buf[64], *pos = buf;
86 int i;
87 bool first = TRUE;
88
89 for (i = 0; i < this->segment_count; i++)
90 {
91 if (this->active & 0x01 << i)
92 {
93 if (first)
94 {
95 first = FALSE;
96 }
97 else
98 {
99 pos += snprintf(pos, buf + sizeof(buf) - pos, ",");
100 }
101 pos += snprintf(pos, buf + sizeof(buf) - pos, "%d", i+1);
102 }
103 }
104 DBG1(DBG_CFG, "HA sync segments %d %sactivated, now active: %s",
105 segment, activated ? "" : "de", buf);
106 }
107
108 /**
109 * Implementation of ha_sync_segments_t.activate
110 */
111 static void activate(private_ha_sync_segments_t *this, u_int segment)
112 {
113 ike_sa_t *ike_sa;
114 enumerator_t *enumerator;
115 u_int16_t mask = 0x01 << (segment - 1);
116
117 DBG1(DBG_CFG, "activating segment %d", segment);
118
119 if (segment > 0 && segment <= this->segment_count && !(this->active & mask))
120 {
121 this->active |= mask;
122
123 enumerator = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
124 while (enumerator->enumerate(enumerator, &ike_sa))
125 {
126 if (ike_sa->get_state(ike_sa) == IKE_PASSIVE &&
127 in_segment(this, ike_sa->get_other_host(ike_sa), segment))
128 {
129 ike_sa->set_state(ike_sa, IKE_ESTABLISHED);
130 }
131 }
132 enumerator->destroy(enumerator);
133
134 log_segments(this, TRUE, segment);
135 }
136 }
137
138 /**
139 * Implementation of ha_sync_segments_t.deactivate
140 */
141 static void deactivate(private_ha_sync_segments_t *this, u_int segment)
142 {
143 ike_sa_t *ike_sa;
144 enumerator_t *enumerator;
145 u_int16_t mask = 0x01 << (segment - 1);
146
147 if (segment > 0 && segment <= this->segment_count && (this->active & mask))
148 {
149 this->active &= ~mask;
150
151 enumerator = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
152 while (enumerator->enumerate(enumerator, &ike_sa))
153 {
154 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
155 in_segment(this, ike_sa->get_other_host(ike_sa), segment))
156 {
157 ike_sa->set_state(ike_sa, IKE_PASSIVE);
158 }
159 }
160 enumerator->destroy(enumerator);
161
162 log_segments(this, FALSE, segment);
163 }
164 }
165
166 /**
167 * Implementation of ha_sync_segments_t.destroy.
168 */
169 static void destroy(private_ha_sync_segments_t *this)
170 {
171 free(this);
172 }
173
174 /**
175 * See header
176 */
177 ha_sync_segments_t *ha_sync_segments_create()
178 {
179 private_ha_sync_segments_t *this = malloc_thing(private_ha_sync_segments_t);
180 enumerator_t *enumerator;
181 u_int segment;
182 char *str;
183
184 this->public.activate = (void(*)(ha_sync_segments_t*, u_int segment))activate;
185 this->public.deactivate = (void(*)(ha_sync_segments_t*, u_int segment))deactivate;
186 this->public.destroy = (void(*)(ha_sync_segments_t*))destroy;
187
188 this->initval = 0;
189 this->active = 0;
190 this->segment_count = lib->settings->get_int(lib->settings,
191 "charon.plugins.ha_sync.segment_count", 1);
192 this->segment_count = min(this->segment_count, MAX_SEGMENTS);
193 str = lib->settings->get_str(lib->settings,
194 "charon.plugins.ha_sync.active_segments", "1");
195 enumerator = enumerator_create_token(str, ",", " ");
196 while (enumerator->enumerate(enumerator, &str))
197 {
198 segment = atoi(str);
199 if (segment && segment < MAX_SEGMENTS)
200 {
201 this->active |= 0x01 << (segment - 1);
202 }
203 }
204 enumerator->destroy(enumerator);
205
206 return &this->public;
207 }
208