]> git.ipfire.org Git - thirdparty/squid.git/blame - src/wccp.cc
Sync store meta assignments with Squid-2.
[thirdparty/squid.git] / src / wccp.cc
CommitLineData
320e9f36 1
2/*
76dc4ca3 3 * $Id: wccp.cc,v 1.44 2007/08/08 14:47:41 rousskov Exp $
320e9f36 4 *
7e3ce7b9 5 * DEBUG: section 80 WCCP Support
320e9f36 6 * AUTHOR: Glenn Chisholm
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
320e9f36 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
320e9f36 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
2b6662ba 24 *
320e9f36 25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
2b6662ba 29 *
320e9f36 30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35#include "squid.h"
063dc1eb 36#include "comm.h"
a553a5a3 37#include "event.h"
320e9f36 38
eb824054 39#if USE_WCCP
40
320e9f36 41#define WCCP_PORT 2048
320e9f36 42#define WCCP_REVISION 0
320e9f36 43#define WCCP_ACTIVE_CACHES 32
44#define WCCP_HASH_SIZE 32
45#define WCCP_BUCKETS 256
7e3ce7b9 46#define WCCP_CACHE_LEN 4
320e9f36 47
48#define WCCP_HERE_I_AM 7
49#define WCCP_I_SEE_YOU 8
50#define WCCP_ASSIGN_BUCKET 9
51
62e76326 52struct wccp_here_i_am_t
53{
320e9f36 54 int type;
55 int version;
56 int revision;
57 char hash[WCCP_HASH_SIZE];
58 int reserved;
59 int id;
60};
61
62e76326 62struct wccp_cache_entry_t
63{
64
ddfcbc22 65 struct IN_ADDR ip_addr;
320e9f36 66 int revision;
ede4c165 67 char hash[WCCP_HASH_SIZE];
320e9f36 68 int reserved;
69};
70
62e76326 71struct wccp_i_see_you_t
72{
320e9f36 73 int type;
74 int version;
75 int change;
76 int id;
77 int number;
62e76326 78
320e9f36 79 struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES];
80};
81
62e76326 82struct wccp_assign_bucket_t
83{
f6308664 84 int type;
85 int id;
86 int number;
320e9f36 87};
88
0b0cfcf2 89static int theWccpConnection = -1;
62e76326 90
320e9f36 91static struct wccp_here_i_am_t wccp_here_i_am;
62e76326 92
b5b86e2c 93static struct wccp_i_see_you_t wccp_i_see_you;
eccaff9c 94static int last_change;
95static int last_id;
1addf64a 96static int last_assign_buckets_change;
908b22c4 97static unsigned int number_caches;
62e76326 98
ddfcbc22 99static struct IN_ADDR local_ip;
b5b86e2c 100
1f38f50a 101static PF wccpHandleUdp;
102static int wccpLowestIP(void);
103static EVH wccpHereIam;
7e3ce7b9 104static void wccpAssignBuckets(void);
320e9f36 105
320e9f36 106/*
107 * The functions used during startup:
108 * wccpInit
109 * wccpConnectionOpen
110 * wccpConnectionShutdown
111 * wccpConnectionClose
112 */
113
114void
115wccpInit(void)
116{
bf8fe701 117 debugs(80, 5, "wccpInit: Called");
320e9f36 118 memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
119 wccp_here_i_am.type = htonl(WCCP_HERE_I_AM);
d20b1cd0 120 wccp_here_i_am.version = htonl(Config.Wccp.version);
f6308664 121 wccp_here_i_am.revision = htonl(WCCP_REVISION);
eccaff9c 122 last_change = 0;
123 last_id = 0;
1addf64a 124 last_assign_buckets_change = 0;
eccaff9c 125 number_caches = 0;
62e76326 126
1f38f50a 127 if (Config.Wccp.router.s_addr != any_addr.s_addr)
62e76326 128 if (!eventFind(wccpHereIam, NULL))
129 eventAdd("wccpHereIam", wccpHereIam, NULL, 5.0, 1);
320e9f36 130}
131
132void
133wccpConnectionOpen(void)
134{
135 u_short port = WCCP_PORT;
62e76326 136
b5b86e2c 137 struct sockaddr_in router, local;
908b22c4 138 socklen_t local_len, router_len;
bf8fe701 139 debugs(80, 5, "wccpConnectionOpen: Called");
62e76326 140
1f38f50a 141 if (Config.Wccp.router.s_addr == any_addr.s_addr) {
76dc4ca3 142 debugs(80, 2, "WCCPv1 disabled.");
62e76326 143 return;
1f38f50a 144 }
62e76326 145
0b0cfcf2 146 theWccpConnection = comm_open(SOCK_DGRAM,
147 IPPROTO_UDP,
148 Config.Wccp.address,
149 port,
150 COMM_NONBLOCKING,
151 "WCCP Socket");
62e76326 152
0b0cfcf2 153 if (theWccpConnection < 0)
62e76326 154 fatal("Cannot open WCCP Port");
155
0b0cfcf2 156 commSetSelect(theWccpConnection,
62e76326 157 COMM_SELECT_READ,
158 wccpHandleUdp,
159 NULL,
160 0);
161
76dc4ca3 162 debugs(80, 1, "Accepting WCCPv1 messages on port " << port << ", FD " << theWccpConnection << ".");
62e76326 163
62e76326 164
b5b86e2c 165 router_len = sizeof(router);
0b0cfcf2 166
b5b86e2c 167 memset(&router, '\0', router_len);
0b0cfcf2 168
b5b86e2c 169 router.sin_family = AF_INET;
0b0cfcf2 170
1f38f50a 171 router.sin_port = htons(port);
0b0cfcf2 172
ede4c165 173 router.sin_addr = Config.Wccp.router;
62e76326 174
0b0cfcf2 175 if (connect(theWccpConnection, (struct sockaddr *) &router, router_len))
62e76326 176 fatal("Unable to connect WCCP out socket");
177
ede4c165 178 local_len = sizeof(local);
62e76326 179
b5b86e2c 180 memset(&local, '\0', local_len);
62e76326 181
0b0cfcf2 182 if (getsockname(theWccpConnection, (struct sockaddr *) &local, &local_len))
62e76326 183 fatal("Unable to getsockname on WCCP out socket");
184
1f38f50a 185 local_ip.s_addr = local.sin_addr.s_addr;
320e9f36 186}
187
320e9f36 188
189void
190wccpConnectionClose(void)
191{
0b0cfcf2 192 if (theWccpConnection > -1) {
76dc4ca3 193 debugs(80, 1, "FD " << theWccpConnection << " Closing WCCPv1 socket");
0b0cfcf2 194 comm_close(theWccpConnection);
195 theWccpConnection = -1;
320e9f36 196 }
197}
198
62e76326 199/*
320e9f36 200 * Functions for handling the requests.
201 */
202
62e76326 203/*
320e9f36 204 * Accept the UDP packet
f6308664 205 */
1f38f50a 206static void
320e9f36 207wccpHandleUdp(int sock, void *not_used)
f6308664 208{
62e76326 209
320e9f36 210 struct sockaddr_in from;
f6308664 211 socklen_t from_len;
47ac1af3 212 int len;
320e9f36 213
bf8fe701 214 debugs(80, 6, "wccpHandleUdp: Called.");
f6308664 215
320e9f36 216 commSetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, NULL, 0);
62e76326 217
320e9f36 218 from_len = sizeof(struct sockaddr_in);
219 memset(&from, '\0', from_len);
b5b86e2c 220 memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
f6308664 221
7d21986b 222 len = comm_udp_recvfrom(sock,
62e76326 223 (void *) &wccp_i_see_you,
1205909e 224 sizeof(wccp_i_see_you),
62e76326 225 0,
226
227 (struct sockaddr *) &from,
228 &from_len);
bf8fe701 229 debugs(80, 3, "wccpHandleUdp: " << len << " bytes WCCP pkt from " <<
230 inet_ntoa(from.sin_addr) << ": type=" <<
231 (unsigned) ntohl(wccp_i_see_you.type) << ", version=" <<
232 (unsigned) ntohl(wccp_i_see_you.version) << ", change=" <<
233 (unsigned) ntohl(wccp_i_see_you.change) << ", id=" <<
234 (unsigned) ntohl(wccp_i_see_you.id) << ", number=" <<
235 (unsigned) ntohl(wccp_i_see_you.number));
62e76326 236
b5b86e2c 237 if (len < 0)
62e76326 238 return;
239
ede4c165 240 if (Config.Wccp.router.s_addr != from.sin_addr.s_addr)
62e76326 241 return;
242
e4049756 243 if ((unsigned) ntohl(wccp_i_see_you.version) != (unsigned) Config.Wccp.version)
62e76326 244 return;
245
b5b86e2c 246 if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
62e76326 247 return;
248
0b0cfcf2 249 if (ntohl(wccp_i_see_you.number) > WCCP_ACTIVE_CACHES) {
bf8fe701 250 debugs(80, 1, "Ignoring WCCP_I_SEE_YOU from " <<
251 inet_ntoa(from.sin_addr) << " with number of caches set to " <<
252 (int) ntohl(wccp_i_see_you.number));
253
eedab643 254 return;
255 }
256
eccaff9c 257 last_id = wccp_i_see_you.id;
eedab643 258
eccaff9c 259 if ((0 == last_change) && (number_caches == (unsigned) ntohl(wccp_i_see_you.number))) {
62e76326 260 if (last_assign_buckets_change == wccp_i_see_you.change) {
261 /*
262 * After a WCCP_ASSIGN_BUCKET message, the router should
263 * update the change value. If not, maybe the route didn't
264 * receive our WCCP_ASSIGN_BUCKET message, so send it again.
265 *
266 * Don't update change here. Instead, fall through to
267 * the next block to call wccpAssignBuckets() again.
268 */
269 (void) 0;
270 } else {
eccaff9c 271 last_change = wccp_i_see_you.change;
62e76326 272 return;
273 }
b5b86e2c 274 }
62e76326 275
eccaff9c 276 if (last_change != wccp_i_see_you.change) {
277 last_change = wccp_i_see_you.change;
62e76326 278
279 if (wccpLowestIP() && wccp_i_see_you.number) {
eccaff9c 280 last_assign_buckets_change = last_change;
62e76326 281 wccpAssignBuckets();
282 }
b5b86e2c 283 }
284}
f6308664 285
1f38f50a 286static int
287wccpLowestIP(void)
b5b86e2c 288{
908b22c4 289 unsigned int loop;
eccaff9c 290 int found = 0;
62e76326 291
eedab643 292 /*
293 * We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
294 */
295
e4049756 296 for (loop = 0; loop < (unsigned) ntohl(wccp_i_see_you.number); loop++) {
eedab643 297 assert(loop < WCCP_ACTIVE_CACHES);
298
62e76326 299 if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr < local_ip.s_addr)
300 return 0;
eccaff9c 301
302 if (wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr == local_ip.s_addr)
303 found = 1;
f6308664 304 }
62e76326 305
eccaff9c 306 return found;
f6308664 307}
320e9f36 308
1f38f50a 309static void
320e9f36 310wccpHereIam(void *voidnotused)
311{
bf8fe701 312 debugs(80, 6, "wccpHereIam: Called");
320e9f36 313
eccaff9c 314 wccp_here_i_am.id = last_id;
0b0cfcf2 315 comm_udp_send(theWccpConnection,
62e76326 316 &wccp_here_i_am,
317 sizeof(wccp_here_i_am),
318 0);
320e9f36 319
1f38f50a 320 if (!eventFind(wccpHereIam, NULL))
62e76326 321 eventAdd("wccpHereIam", wccpHereIam, NULL, 10.0, 1);
320e9f36 322}
323
1f38f50a 324static void
7e3ce7b9 325wccpAssignBuckets(void)
320e9f36 326{
62e76326 327
7e3ce7b9 328 struct wccp_assign_bucket_t *wccp_assign_bucket;
329 int wab_len;
330 char *buckets;
9bc73deb 331 int buckets_per_cache;
908b22c4 332 unsigned int loop;
1f38f50a 333 int bucket = 0;
334 int *caches;
7e3ce7b9 335 int cache_len;
1f38f50a 336 char *buf;
320e9f36 337
bf8fe701 338 debugs(80, 6, "wccpAssignBuckets: Called");
b5b86e2c 339 number_caches = ntohl(wccp_i_see_you.number);
62e76326 340
eedab643 341 assert(number_caches > 0);
342 assert(number_caches <= WCCP_ACTIVE_CACHES);
62e76326 343
7e3ce7b9 344 wab_len = sizeof(struct wccp_assign_bucket_t);
62e76326 345
7e3ce7b9 346 cache_len = WCCP_CACHE_LEN * number_caches;
347
908b22c4 348 buf = (char *)xmalloc(wab_len +
62e76326 349 WCCP_BUCKETS +
350 cache_len);
351
7e3ce7b9 352 wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
62e76326 353
7e3ce7b9 354 caches = (int *) (buf + wab_len);
62e76326 355
7e3ce7b9 356 buckets = buf + wab_len + cache_len;
357
358 memset(wccp_assign_bucket, '\0', sizeof(wccp_assign_bucket));
62e76326 359
7e3ce7b9 360 memset(buckets, 0xFF, WCCP_BUCKETS);
320e9f36 361
9bc73deb 362 buckets_per_cache = WCCP_BUCKETS / number_caches;
62e76326 363
f6308664 364 for (loop = 0; loop < number_caches; loop++) {
62e76326 365 int i;
366 xmemcpy(&caches[loop],
367 &wccp_i_see_you.wccp_cache_entry[loop].ip_addr.s_addr,
368 sizeof(*caches));
369
370 for (i = 0; i < buckets_per_cache; i++) {
371 assert(bucket < WCCP_BUCKETS);
372 buckets[bucket++] = loop;
373 }
320e9f36 374 }
62e76326 375
994f613f 376 while (bucket < WCCP_BUCKETS) {
62e76326 377 buckets[bucket++] = number_caches - 1;
994f613f 378 }
62e76326 379
7e3ce7b9 380 wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
381 wccp_assign_bucket->id = wccp_i_see_you.id;
382 wccp_assign_bucket->number = wccp_i_see_you.number;
383
0b0cfcf2 384 comm_udp_send(theWccpConnection,
62e76326 385 buf,
386 wab_len + WCCP_BUCKETS + cache_len,
387 0);
eccaff9c 388 last_change = 0;
1f38f50a 389 xfree(buf);
320e9f36 390}
eb824054 391
392#endif /* USE_WCCP */