wccp.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 80 WCCP Support */
10 
11 #include "squid.h"
12 
13 #if USE_WCCP
14 #include "base/RunnersRegistry.h"
15 #include "comm.h"
16 #include "comm/Connection.h"
17 #include "comm/Loops.h"
18 #include "compat/socket.h"
19 #include "event.h"
20 #include "fatal.h"
21 #include "SquidConfig.h"
22 #include "tools.h"
23 
24 #define WCCP_PORT 2048
25 #define WCCP_REVISION 0
26 #define WCCP_ACTIVE_CACHES 32
27 #define WCCP_HASH_SIZE 32
28 #define WCCP_BUCKETS 256
29 #define WCCP_CACHE_LEN 4
30 
31 #define WCCP_HERE_I_AM 7
32 #define WCCP_I_SEE_YOU 8
33 #define WCCP_ASSIGN_BUCKET 9
34 
36  int type;
37  int version;
38  int revision;
40  int reserved;
41  int id;
42 };
43 
45  struct in_addr ip_addr; // WCCP on-the-wire in 32-bit IPv4-only.
46  int revision;
48  int reserved;
49 };
50 
52  int32_t type;
53  int32_t version;
54  int32_t change;
55  int32_t id;
56  int32_t number;
57 
59 };
60 
62  int type;
63  int id;
64  int number;
65 };
66 
67 static int theWccpConnection = -1;
68 
70 
72 static int last_change;
73 static int last_id;
75 static unsigned int number_caches;
76 
78 
80 static int wccpLowestIP(void);
82 static void wccpAssignBuckets(void);
83 
84 static void
85 wccpInit(void)
86 {
87  if (!IamPrimaryProcess())
88  return;
89 
90  debugs(80, 5, "wccpInit: Called");
91  memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
95  last_change = 0;
96  last_id = 0;
98  number_caches = 0;
99 
100  if (!Config.Wccp.router.isAnyAddr())
101  if (!eventFind(wccpHereIam, nullptr))
102  eventAdd("wccpHereIam", wccpHereIam, nullptr, 5.0, 1);
103 }
104 
105 static void
107 {
108  if (!IamPrimaryProcess())
109  return;
110 
111  debugs(80, 5, "wccpConnectionOpen: Called");
112 
113  if (Config.Wccp.router.isAnyAddr()) {
114  debugs(80, 2, "WCCPv1 disabled.");
115  return;
116  }
117 
118  if ( !Config.Wccp.router.setIPv4() ) {
119  debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Router " << Config.Wccp.router << " is not an IPv4 address.");
120  return;
121  }
122 
123  if ( !Config.Wccp.address.setIPv4() ) {
124  debugs(80, DBG_CRITICAL, "WCCPv1 Disabled. Local address " << Config.Wccp.address << " is not an IPv4 address.");
125  return;
126  }
127 
130 
132  IPPROTO_UDP,
135  "WCCP Socket");
136 
137  if (theWccpConnection < 0)
138  fatal("Cannot open WCCP Port");
139 
141 
142  debugs(80, DBG_IMPORTANT, "Accepting WCCPv1 messages on " << Config.Wccp.address << ", FD " << theWccpConnection << ".");
143 
144  // Sadly WCCP only does IPv4
145 
146  struct sockaddr_in router;
147  Config.Wccp.router.getSockAddr(router);
148  if (xconnect(theWccpConnection, (struct sockaddr*)&router, sizeof(router)))
149  fatal("Unable to connect WCCP out socket");
150 
151  struct sockaddr_in local;
152  memset(&local, '\0', sizeof(local));
153  socklen_t slen = sizeof(local);
154  if (xgetsockname(theWccpConnection, (struct sockaddr*)&local, &slen))
155  fatal("Unable to getsockname on WCCP out socket");
156 
157  local_ip = local;
158 }
159 
160 static void
162 {
163  if (!IamPrimaryProcess())
164  return;
165 
166  if (theWccpConnection > -1) {
167  debugs(80, DBG_IMPORTANT, "FD " << theWccpConnection << " Closing WCCPv1 socket");
169  theWccpConnection = -1;
170  }
171 }
172 
173 class WccpRr : public RegisteredRunner
174 {
175 public:
176  void useConfig() override { wccpInit(); wccpConnectionOpen(); }
177  void startReconfigure() override { wccpConnectionClose(); }
178  void syncConfig() override { wccpConnectionOpen(); }
179  void startShutdown() override { wccpConnectionClose(); }
180 };
182 
183 /*
184  * Functions for handling the requests.
185  */
186 
187 /*
188  * Accept the UDP packet
189  */
190 static void
191 wccpHandleUdp(int sock, void *)
192 {
193  Ip::Address from;
194  int len;
195 
196  debugs(80, 6, "wccpHandleUdp: Called.");
197 
198  Comm::SetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, nullptr, 0);
199 
200  memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
201 
202  len = comm_udp_recvfrom(sock,
203  (void *) &wccp_i_see_you,
204  sizeof(wccp_i_see_you),
205  0,
206  from);
207  debugs(80, 3, "wccpHandleUdp: " << len << " bytes WCCP pkt from " << from <<
208  ": type=" <<
209  (unsigned) ntohl(wccp_i_see_you.type) << ", version=" <<
210  (unsigned) ntohl(wccp_i_see_you.version) << ", change=" <<
211  (unsigned) ntohl(wccp_i_see_you.change) << ", id=" <<
212  (unsigned) ntohl(wccp_i_see_you.id) << ", number=" <<
213  (unsigned) ntohl(wccp_i_see_you.number));
214 
215  if (len < 0)
216  return;
217 
218  if (from != Config.Wccp.router)
219  return;
220 
221  if ((unsigned) ntohl(wccp_i_see_you.version) != (unsigned) Config.Wccp.version)
222  return;
223 
224  if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
225  return;
226 
228  debugs(80, DBG_IMPORTANT, "Ignoring WCCP_I_SEE_YOU from " <<
229  from << " with number of caches set to " <<
230  (int) ntohl(wccp_i_see_you.number));
231 
232  return;
233  }
234 
236 
237  if ((0 == last_change) && (number_caches == (unsigned) ntohl(wccp_i_see_you.number))) {
239  /*
240  * After a WCCP_ASSIGN_BUCKET message, the router should
241  * update the change value. If not, maybe the route didn't
242  * receive our WCCP_ASSIGN_BUCKET message, so send it again.
243  *
244  * Don't update change here. Instead, fall through to
245  * the next block to call wccpAssignBuckets() again.
246  */
247  (void) 0;
248  } else {
250  return;
251  }
252  }
253 
256 
260  }
261  }
262 }
263 
264 static int
266 {
267  unsigned int loop;
268  int found = 0;
269 
270  /*
271  * We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
272  */
273 
274  for (loop = 0; loop < (unsigned) ntohl(wccp_i_see_you.number); ++loop) {
275  assert(loop < WCCP_ACTIVE_CACHES);
276 
278  return 0;
279 
281  found = 1;
282  }
283 
284  return found;
285 }
286 
287 static void
288 wccpHereIam(void *)
289 {
290  debugs(80, 6, "wccpHereIam: Called");
291 
293  double interval = 10.0; // TODO: make this configurable, possibly negotiate with the router.
294  ssize_t sent = comm_udp_send(theWccpConnection, &wccp_here_i_am, sizeof(wccp_here_i_am), 0);
295 
296  // if we failed to send the whole lot, try again at a shorter interval (20%)
297  if (sent != sizeof(wccp_here_i_am)) {
298  int xerrno = errno;
299  debugs(80, 2, "ERROR: failed to send WCCP HERE_I_AM packet: " << xstrerr(xerrno));
300  interval = 2.0;
301  }
302 
303  if (!eventFind(wccpHereIam, nullptr))
304  eventAdd("wccpHereIam", wccpHereIam, nullptr, interval, 1);
305 }
306 
307 static void
309 {
310 
311  struct wccp_assign_bucket_t *wccp_assign_bucket;
312  int wab_len;
313  char *buckets;
314  int buckets_per_cache;
315  unsigned int loop;
316  int bucket = 0;
317  int *caches;
318  int cache_len;
319  char *buf;
320 
321  debugs(80, 6, "wccpAssignBuckets: Called");
323 
324  assert(number_caches > 0);
326 
327  wab_len = sizeof(struct wccp_assign_bucket_t);
328 
329  cache_len = WCCP_CACHE_LEN * number_caches;
330 
331  buf = (char *)xmalloc(wab_len +
332  WCCP_BUCKETS +
333  cache_len);
334 
335  wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
336 
337  caches = (int *) (buf + wab_len);
338 
339  buckets = buf + wab_len + cache_len;
340 
341  memset(wccp_assign_bucket, '\0', sizeof(*wccp_assign_bucket));
342 
343  memset(buckets, 0xFF, WCCP_BUCKETS);
344 
345  buckets_per_cache = WCCP_BUCKETS / number_caches;
346 
347  for (loop = 0; loop < number_caches; ++loop) {
348  int i;
349  memcpy(&caches[loop],
351  sizeof(*caches));
352 
353  for (i = 0; i < buckets_per_cache; ++i) {
354  assert(bucket < WCCP_BUCKETS);
355  buckets[bucket] = loop;
356  ++bucket;
357  }
358  }
359 
360  while (bucket < WCCP_BUCKETS) {
361  buckets[bucket] = number_caches - 1;
362  ++bucket;
363  }
364 
365  wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
366  wccp_assign_bucket->id = wccp_i_see_you.id;
367  wccp_assign_bucket->number = wccp_i_see_you.number;
368 
370  buf,
371  wab_len + WCCP_BUCKETS + cache_len,
372  0);
373  last_change = 0;
374  xfree(buf);
375 }
376 
377 #endif /* USE_WCCP */
378 
void startShutdown() override
Definition: wccp.cc:179
void fatal(const char *message)
Definition: fatal.cc:28
const char * xstrerr(int error)
Definition: xstrerror.cc:83
int eventFind(EVH *func, void *arg)
Definition: event.cc:145
#define WCCP_CACHE_LEN
Definition: wccp.cc:29
#define WCCP_HASH_SIZE
Definition: wccp.cc:27
#define WCCP_REVISION
Definition: wccp.cc:25
#define DBG_CRITICAL
Definition: Stream.h:37
#define xmalloc
struct SquidConfig::@80 Wccp
int32_t number
Definition: wccp.cc:56
int32_t change
Definition: wccp.cc:54
#define WCCP_ASSIGN_BUCKET
Definition: wccp.cc:33
bool isAnyAddr() const
Definition: Address.cc:190
static int last_assign_buckets_change
Definition: wccp.cc:74
Definition: wccp.cc:44
ssize_t comm_udp_send(int s, const void *buf, size_t len, int flags)
Definition: comm.cc:148
static struct wccp_here_i_am_t wccp_here_i_am
Definition: wccp.cc:69
static Ip::Address local_ip
Definition: wccp.cc:77
#define comm_close(x)
Definition: comm.h:36
#define WCCP_PORT
Definition: wccp.cc:24
#define WCCP_HERE_I_AM
Definition: wccp.cc:31
int reserved
Definition: wccp.cc:40
#define WCCP_BUCKETS
Definition: wccp.cc:28
static int theWccpConnection
Definition: wccp.cc:67
int socklen_t
Definition: types.h:137
Definition: wccp.cc:173
#define COMM_NONBLOCKING
Definition: Connection.h:46
static void wccpInit(void)
Definition: wccp.cc:85
char hash[WCCP_HASH_SIZE]
Definition: wccp.cc:47
static void wccpConnectionOpen(void)
Definition: wccp.cc:106
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
Definition: comm.cc:259
static int last_id
Definition: wccp.cc:73
int xgetsockname(int socketFd, struct sockaddr *sa, socklen_t *saLength)
POSIX getsockname(2) equivalent.
Definition: socket.h:80
Ip::Address router
Definition: SquidConfig.h:162
int revision
Definition: wccp.cc:38
char hash[WCCP_HASH_SIZE]
Definition: wccp.cc:39
static struct tok * buckets[HASHSIZE]
Definition: parse.c:219
unsigned short port() const
Definition: Address.cc:790
static void wccpAssignBuckets(void)
Definition: wccp.cc:308
static void wccpConnectionClose(void)
Definition: wccp.cc:161
#define assert(EX)
Definition: assert.h:17
int32_t type
Definition: wccp.cc:52
static EVH wccpHereIam
Definition: wccp.cc:81
bool setIPv4()
Definition: Address.cc:244
#define COMM_SELECT_READ
Definition: defines.h:24
#define xfree
void EVH(void *)
Definition: event.h:18
struct wccp_cache_entry_t wccp_cache_entry[WCCP_ACTIVE_CACHES]
Definition: wccp.cc:58
#define WCCP_I_SEE_YOU
Definition: wccp.cc:32
int32_t id
Definition: wccp.cc:55
DefineRunnerRegistrator(WccpRr)
static int wccpLowestIP(void)
Definition: wccp.cc:265
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:220
Ip::Address address
Definition: SquidConfig.h:163
static unsigned int number_caches
Definition: wccp.cc:75
#define WCCP_ACTIVE_CACHES
Definition: wccp.cc:26
static struct wccp_i_see_you_t wccp_i_see_you
Definition: wccp.cc:71
#define DBG_IMPORTANT
Definition: Stream.h:38
int reserved
Definition: wccp.cc:48
struct in_addr ip_addr
Definition: wccp.cc:45
void syncConfig() override
Definition: wccp.cc:178
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from)
Definition: comm.cc:128
int32_t version
Definition: wccp.cc:53
void getSockAddr(struct sockaddr_storage &addr, const int family) const
Definition: Address.cc:936
int revision
Definition: wccp.cc:46
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
int xconnect(int socketFd, const struct sockaddr *sa, socklen_t saLength)
POSIX connect(2) equivalent.
Definition: socket.h:74
static PF wccpHandleUdp
Definition: wccp.cc:79
void startReconfigure() override
Definition: wccp.cc:177
void useConfig() override
Definition: wccp.cc:176
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
static int last_change
Definition: wccp.cc:72
void PF(int, void *)
Definition: forward.h:18
class SquidConfig Config
Definition: SquidConfig.cc:12
bool IamPrimaryProcess()
Definition: tools.cc:709

 

Introduction

Documentation

Support

Miscellaneous