wccp.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 "comm.h"
15 #include "comm/Connection.h"
16 #include "comm/Loops.h"
17 #include "event.h"
18 #include "fatal.h"
19 #include "SquidConfig.h"
20 #include "wccp.h"
21 
22 #define WCCP_PORT 2048
23 #define WCCP_REVISION 0
24 #define WCCP_ACTIVE_CACHES 32
25 #define WCCP_HASH_SIZE 32
26 #define WCCP_BUCKETS 256
27 #define WCCP_CACHE_LEN 4
28 
29 #define WCCP_HERE_I_AM 7
30 #define WCCP_I_SEE_YOU 8
31 #define WCCP_ASSIGN_BUCKET 9
32 
34  int type;
35  int version;
36  int revision;
38  int reserved;
39  int id;
40 };
41 
43  struct in_addr ip_addr; // WCCP on-the-wire in 32-bit IPv4-only.
44  int revision;
46  int reserved;
47 };
48 
50  int32_t type;
51  int32_t version;
52  int32_t change;
53  int32_t id;
54  int32_t number;
55 
57 };
58 
60  int type;
61  int id;
62  int number;
63 };
64 
65 static int theWccpConnection = -1;
66 
68 
70 static int last_change;
71 static int last_id;
73 static unsigned int number_caches;
74 
76 
78 static int wccpLowestIP(void);
80 static void wccpAssignBuckets(void);
81 
82 /*
83  * The functions used during startup:
84  * wccpInit
85  * wccpConnectionOpen
86  * wccpConnectionShutdown
87  * wccpConnectionClose
88  */
89 
90 void
91 wccpInit(void)
92 {
93  debugs(80, 5, "wccpInit: Called");
94  memset(&wccp_here_i_am, '\0', sizeof(wccp_here_i_am));
98  last_change = 0;
99  last_id = 0;
101  number_caches = 0;
102 
103  if (!Config.Wccp.router.isAnyAddr())
104  if (!eventFind(wccpHereIam, nullptr))
105  eventAdd("wccpHereIam", wccpHereIam, nullptr, 5.0, 1);
106 }
107 
108 void
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 (connect(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 (getsockname(theWccpConnection, (struct sockaddr*)&local, &slen))
155  fatal("Unable to getsockname on WCCP out socket");
156 
157  local_ip = local;
158 }
159 
160 void
162 {
163  if (theWccpConnection > -1) {
164  debugs(80, DBG_IMPORTANT, "FD " << theWccpConnection << " Closing WCCPv1 socket");
166  theWccpConnection = -1;
167  }
168 }
169 
170 /*
171  * Functions for handling the requests.
172  */
173 
174 /*
175  * Accept the UDP packet
176  */
177 static void
178 wccpHandleUdp(int sock, void *)
179 {
180  Ip::Address from;
181  int len;
182 
183  debugs(80, 6, "wccpHandleUdp: Called.");
184 
185  Comm::SetSelect(sock, COMM_SELECT_READ, wccpHandleUdp, nullptr, 0);
186 
187  memset(&wccp_i_see_you, '\0', sizeof(wccp_i_see_you));
188 
189  len = comm_udp_recvfrom(sock,
190  (void *) &wccp_i_see_you,
191  sizeof(wccp_i_see_you),
192  0,
193  from);
194  debugs(80, 3, "wccpHandleUdp: " << len << " bytes WCCP pkt from " << from <<
195  ": type=" <<
196  (unsigned) ntohl(wccp_i_see_you.type) << ", version=" <<
197  (unsigned) ntohl(wccp_i_see_you.version) << ", change=" <<
198  (unsigned) ntohl(wccp_i_see_you.change) << ", id=" <<
199  (unsigned) ntohl(wccp_i_see_you.id) << ", number=" <<
200  (unsigned) ntohl(wccp_i_see_you.number));
201 
202  if (len < 0)
203  return;
204 
205  if (from != Config.Wccp.router)
206  return;
207 
208  if ((unsigned) ntohl(wccp_i_see_you.version) != (unsigned) Config.Wccp.version)
209  return;
210 
211  if (ntohl(wccp_i_see_you.type) != WCCP_I_SEE_YOU)
212  return;
213 
215  debugs(80, DBG_IMPORTANT, "Ignoring WCCP_I_SEE_YOU from " <<
216  from << " with number of caches set to " <<
217  (int) ntohl(wccp_i_see_you.number));
218 
219  return;
220  }
221 
223 
224  if ((0 == last_change) && (number_caches == (unsigned) ntohl(wccp_i_see_you.number))) {
226  /*
227  * After a WCCP_ASSIGN_BUCKET message, the router should
228  * update the change value. If not, maybe the route didn't
229  * receive our WCCP_ASSIGN_BUCKET message, so send it again.
230  *
231  * Don't update change here. Instead, fall through to
232  * the next block to call wccpAssignBuckets() again.
233  */
234  (void) 0;
235  } else {
237  return;
238  }
239  }
240 
243 
247  }
248  }
249 }
250 
251 static int
253 {
254  unsigned int loop;
255  int found = 0;
256 
257  /*
258  * We sanity checked wccp_i_see_you.number back in wccpHandleUdp()
259  */
260 
261  for (loop = 0; loop < (unsigned) ntohl(wccp_i_see_you.number); ++loop) {
262  assert(loop < WCCP_ACTIVE_CACHES);
263 
265  return 0;
266 
268  found = 1;
269  }
270 
271  return found;
272 }
273 
274 static void
275 wccpHereIam(void *)
276 {
277  debugs(80, 6, "wccpHereIam: Called");
278 
280  double interval = 10.0; // TODO: make this configurable, possibly negotiate with the router.
281  ssize_t sent = comm_udp_send(theWccpConnection, &wccp_here_i_am, sizeof(wccp_here_i_am), 0);
282 
283  // if we failed to send the whole lot, try again at a shorter interval (20%)
284  if (sent != sizeof(wccp_here_i_am)) {
285  int xerrno = errno;
286  debugs(80, 2, "ERROR: failed to send WCCP HERE_I_AM packet: " << xstrerr(xerrno));
287  interval = 2.0;
288  }
289 
290  if (!eventFind(wccpHereIam, nullptr))
291  eventAdd("wccpHereIam", wccpHereIam, nullptr, interval, 1);
292 }
293 
294 static void
296 {
297 
298  struct wccp_assign_bucket_t *wccp_assign_bucket;
299  int wab_len;
300  char *buckets;
301  int buckets_per_cache;
302  unsigned int loop;
303  int bucket = 0;
304  int *caches;
305  int cache_len;
306  char *buf;
307 
308  debugs(80, 6, "wccpAssignBuckets: Called");
310 
311  assert(number_caches > 0);
313 
314  wab_len = sizeof(struct wccp_assign_bucket_t);
315 
316  cache_len = WCCP_CACHE_LEN * number_caches;
317 
318  buf = (char *)xmalloc(wab_len +
319  WCCP_BUCKETS +
320  cache_len);
321 
322  wccp_assign_bucket = (struct wccp_assign_bucket_t *) buf;
323 
324  caches = (int *) (buf + wab_len);
325 
326  buckets = buf + wab_len + cache_len;
327 
328  memset(wccp_assign_bucket, '\0', sizeof(*wccp_assign_bucket));
329 
330  memset(buckets, 0xFF, WCCP_BUCKETS);
331 
332  buckets_per_cache = WCCP_BUCKETS / number_caches;
333 
334  for (loop = 0; loop < number_caches; ++loop) {
335  int i;
336  memcpy(&caches[loop],
338  sizeof(*caches));
339 
340  for (i = 0; i < buckets_per_cache; ++i) {
341  assert(bucket < WCCP_BUCKETS);
342  buckets[bucket] = loop;
343  ++bucket;
344  }
345  }
346 
347  while (bucket < WCCP_BUCKETS) {
348  buckets[bucket] = number_caches - 1;
349  ++bucket;
350  }
351 
352  wccp_assign_bucket->type = htonl(WCCP_ASSIGN_BUCKET);
353  wccp_assign_bucket->id = wccp_i_see_you.id;
354  wccp_assign_bucket->number = wccp_i_see_you.number;
355 
357  buf,
358  wab_len + WCCP_BUCKETS + cache_len,
359  0);
360  last_change = 0;
361  xfree(buf);
362 }
363 
364 #endif /* USE_WCCP */
365 
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:27
#define WCCP_HASH_SIZE
Definition: wccp.cc:25
#define WCCP_REVISION
Definition: wccp.cc:23
#define DBG_CRITICAL
Definition: Stream.h:37
#define xmalloc
int32_t number
Definition: wccp.cc:54
int32_t change
Definition: wccp.cc:52
#define WCCP_ASSIGN_BUCKET
Definition: wccp.cc:31
bool isAnyAddr() const
Definition: Address.cc:190
static int last_assign_buckets_change
Definition: wccp.cc:72
Definition: wccp.cc:42
ssize_t comm_udp_send(int s, const void *buf, size_t len, int flags)
Definition: comm.cc:146
static struct wccp_here_i_am_t wccp_here_i_am
Definition: wccp.cc:67
static Ip::Address local_ip
Definition: wccp.cc:75
#define comm_close(x)
Definition: comm.h:36
#define WCCP_PORT
Definition: wccp.cc:22
#define WCCP_HERE_I_AM
Definition: wccp.cc:29
int reserved
Definition: wccp.cc:38
#define WCCP_BUCKETS
Definition: wccp.cc:26
static int theWccpConnection
Definition: wccp.cc:65
int socklen_t
Definition: types.h:137
#define COMM_NONBLOCKING
Definition: Connection.h:46
char hash[WCCP_HASH_SIZE]
Definition: wccp.cc:45
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
Definition: comm.cc:257
static int last_id
Definition: wccp.cc:71
void wccpInit(void)
Definition: wccp.cc:91
Ip::Address router
Definition: SquidConfig.h:162
int revision
Definition: wccp.cc:36
char hash[WCCP_HASH_SIZE]
Definition: wccp.cc:37
struct SquidConfig::@87 Wccp
static struct tok * buckets[HASHSIZE]
Definition: parse.c:219
unsigned short port() const
Definition: Address.cc:798
static void wccpAssignBuckets(void)
Definition: wccp.cc:295
#define assert(EX)
Definition: assert.h:17
int32_t type
Definition: wccp.cc:50
static EVH wccpHereIam
Definition: wccp.cc:79
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:56
#define WCCP_I_SEE_YOU
Definition: wccp.cc:30
int32_t id
Definition: wccp.cc:53
static int wccpLowestIP(void)
Definition: wccp.cc:252
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:73
#define WCCP_ACTIVE_CACHES
Definition: wccp.cc:24
static struct wccp_i_see_you_t wccp_i_see_you
Definition: wccp.cc:69
#define DBG_IMPORTANT
Definition: Stream.h:38
int reserved
Definition: wccp.cc:46
struct in_addr ip_addr
Definition: wccp.cc:43
void wccpConnectionOpen(void)
Definition: wccp.cc:109
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from)
Definition: comm.cc:126
int32_t version
Definition: wccp.cc:51
void getSockAddr(struct sockaddr_storage &addr, const int family) const
Definition: Address.cc:944
int revision
Definition: wccp.cc:44
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void wccpConnectionClose(void)
Definition: wccp.cc:161
static PF wccpHandleUdp
Definition: wccp.cc:77
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:70
void PF(int, void *)
Definition: forward.h:18
class SquidConfig Config
Definition: SquidConfig.cc:12

 

Introduction

Documentation

Support

Miscellaneous