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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors