iPXE
peerdisc.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <ipxe/xfer.h>
33 #include <ipxe/iobuf.h>
34 #include <ipxe/open.h>
35 #include <ipxe/tcpip.h>
36 #include <ipxe/uuid.h>
37 #include <ipxe/base16.h>
38 #include <ipxe/netdevice.h>
39 #include <ipxe/timer.h>
40 #include <ipxe/fault.h>
41 #include <ipxe/settings.h>
42 #include <ipxe/pccrd.h>
43 #include <ipxe/peerdisc.h>
44 
45 /** @file
46  *
47  * Peer Content Caching and Retrieval (PeerDist) protocol peer discovery
48  *
49  */
50 
51 /** List of discovery segments */
52 static LIST_HEAD ( peerdisc_segments );
53 
54 /** Number of repeated discovery attempts */
55 #define PEERDISC_REPEAT_COUNT 2
56 
57 /** Time between repeated discovery attempts */
58 #define PEERDISC_REPEAT_TIMEOUT ( 1 * TICKS_PER_SEC )
59 
60 /** Default discovery timeout (in seconds) */
61 #define PEERDISC_DEFAULT_TIMEOUT_SECS 2
62 
63 /** Recommended discovery timeout (in seconds)
64  *
65  * We reduce the recommended discovery timeout whenever a segment
66  * fails to discover any peers, and restore the default value whenever
67  * a valid discovery reply is received. We continue to send discovery
68  * requests even if the recommended timeout is reduced to zero.
69  *
70  * This strategy is intended to minimise discovery delays when no
71  * peers are available on the network, while allowing downloads to
72  * quickly switch back to using PeerDist acceleration if new peers
73  * become available.
74  */
76 
77 /** Most recently discovered peer (for any block) */
78 static char *peerdisc_recent;
79 
80 /** Hosted cache server */
81 static char *peerhost;
82 
83 static struct peerdisc_segment * peerdisc_find ( const char *id );
84 static int peerdisc_discovered ( struct peerdisc_segment *segment,
85  const char *location );
86 
87 /******************************************************************************
88  *
89  * Statistics reporting
90  *
91  ******************************************************************************
92  */
93 
94 /**
95  * Report peer discovery statistics
96  *
97  * @v intf Interface
98  * @v peer Selected peer (or NULL)
99  * @v peers List of available peers
100  */
101 void peerdisc_stat ( struct interface *intf, struct peerdisc_peer *peer,
102  struct list_head *peers ) {
103  struct interface *dest;
104  peerdisc_stat_TYPE ( void * ) *op =
106  void *object = intf_object ( dest );
107 
108  if ( op ) {
109  op ( object, peer, peers );
110  } else {
111  /* Default is to do nothing */
112  }
113 
114  intf_put ( dest );
115 }
116 
117 /******************************************************************************
118  *
119  * Discovery sockets
120  *
121  ******************************************************************************
122  */
123 
124 /**
125  * Open all PeerDist discovery sockets
126  *
127  * @ret rc Return status code
128  */
129 static int peerdisc_socket_open ( void ) {
130  struct peerdisc_socket *socket;
131  int rc;
132 
133  /* Open each socket */
135  if ( ( rc = xfer_open_socket ( &socket->xfer, SOCK_DGRAM,
136  &socket->address.sa,
137  NULL ) ) != 0 ) {
138  DBGC ( socket, "PEERDISC %s could not open socket: "
139  "%s\n", socket->name, strerror ( rc ) );
140  goto err;
141  }
142  }
143 
144  return 0;
145 
146  err:
148  intf_restart ( &socket->xfer, rc );
149  return rc;
150 }
151 
152 /**
153  * Attempt to transmit PeerDist discovery requests on all sockets
154  *
155  * @v uuid Message UUID string
156  * @v id Segment identifier string
157  */
158 static void peerdisc_socket_tx ( const char *uuid, const char *id ) {
159  struct peerdisc_socket *socket;
160  struct net_device *netdev;
161  struct xfer_metadata meta;
162  union {
163  struct sockaddr sa;
164  struct sockaddr_tcpip st;
165  } address;
166  char *request;
167  size_t len;
168  int rc;
169 
170  /* Construct discovery request */
172  if ( ! request )
173  goto err_request;
174  len = strlen ( request );
175 
176  /* Initialise data transfer metadata */
177  memset ( &meta, 0, sizeof ( meta ) );
178  meta.dest = &address.sa;
179 
180  /* Send message on each socket */
182 
183  /* Initialise socket address */
184  memcpy ( &address.sa, &socket->address.sa,
185  sizeof ( address.sa ) );
186 
187  /* Send message on each open network device */
188  for_each_netdev ( netdev ) {
189 
190  /* Skip unopened network devices */
191  if ( ! netdev_is_open ( netdev ) )
192  continue;
193  address.st.st_scope_id = netdev->scope_id;
194 
195  /* Discard request (for test purposes) if applicable */
196  if ( inject_fault ( PEERDISC_DISCARD_RATE ) )
197  continue;
198 
199  /* Transmit request */
200  if ( ( rc = xfer_deliver_raw_meta ( &socket->xfer,
201  request, len,
202  &meta ) ) != 0 ) {
203  DBGC ( socket, "PEERDISC %s could not transmit "
204  "via %s: %s\n", socket->name,
205  netdev->name, strerror ( rc ) );
206  /* Contine to try other net devices/sockets */
207  continue;
208  }
209  }
210  }
211 
212  free ( request );
213  err_request:
214  return;
215 }
216 
217 /**
218  * Handle received PeerDist discovery reply
219  *
220  * @v socket PeerDist discovery socket
221  * @v iobuf I/O buffer
222  * @v meta Data transfer metadata
223  * @ret rc Return status code
224  */
225 static int peerdisc_socket_rx ( struct peerdisc_socket *socket,
226  struct io_buffer *iobuf,
227  struct xfer_metadata *meta __unused ) {
228  struct peerdist_discovery_reply reply;
229  struct peerdisc_segment *segment;
230  char *id;
231  char *location;
232  int rc;
233 
234  /* Discard reply (for test purposes) if applicable */
235  if ( ( rc = inject_fault ( PEERDISC_DISCARD_RATE ) ) != 0 )
236  goto err;
237 
238  /* Parse reply */
239  if ( ( rc = peerdist_discovery_reply ( iobuf->data, iob_len ( iobuf ),
240  &reply ) ) != 0 ) {
241  DBGC ( socket, "PEERDISC %s could not parse reply: %s\n",
242  socket->name, strerror ( rc ) );
243  DBGC_HDA ( socket, 0, iobuf->data, iob_len ( iobuf ) );
244  goto err;
245  }
246 
247  /* Any kind of discovery reply indicates that there are active
248  * peers on a local network, so restore the recommended
249  * discovery timeout to its default value for future requests.
250  */
252  DBGC ( socket, "PEERDISC %s restoring timeout to %d seconds\n",
254  }
256 
257  /* Iterate over segment IDs */
258  for ( id = reply.ids ; *id ; id += ( strlen ( id ) + 1 /* NUL */ ) ) {
259 
260  /* Find corresponding segment */
261  segment = peerdisc_find ( id );
262  if ( ! segment ) {
263  DBGC ( socket, "PEERDISC %s ignoring reply for %s\n",
264  socket->name, id );
265  continue;
266  }
267 
268  /* Report all discovered peer locations */
269  for ( location = reply.locations ; *location ;
270  location += ( strlen ( location ) + 1 /* NUL */ ) ) {
271 
272  /* Report discovered peer location */
273  if ( ( rc = peerdisc_discovered ( segment,
274  location ) ) != 0 )
275  goto err;
276  }
277  }
278 
279  err:
280  free_iob ( iobuf );
281  return rc;
282 }
283 
284 /**
285  * Close all PeerDist discovery sockets
286  *
287  * @v rc Reason for close
288  */
289 static void peerdisc_socket_close ( int rc ) {
290  struct peerdisc_socket *socket;
291 
292  /* Close all sockets */
294  intf_restart ( &socket->xfer, rc );
295 }
296 
297 /** PeerDist discovery socket interface operations */
300 };
301 
302 /** PeerDist discovery socket interface descriptor */
305 
306 /** PeerDist discovery IPv4 socket */
307 struct peerdisc_socket peerdisc_socket_ipv4 __peerdisc_socket = {
308  .name = "IPv4",
309  .address = {
310  .sin = {
311  .sin_family = AF_INET,
312  .sin_port = htons ( PEERDIST_DISCOVERY_PORT ),
313  .sin_addr.s_addr = htonl ( PEERDIST_DISCOVERY_IPV4 ),
314  },
315  },
316  .xfer = INTF_INIT ( peerdisc_socket_desc ),
317 };
318 
319 /** PeerDist discovery IPv6 socket */
320 struct peerdisc_socket peerdisc_socket_ipv6 __peerdisc_socket = {
321  .name = "IPv6",
322  .address = {
323  .sin6 = {
324  .sin6_family = AF_INET6,
325  .sin6_port = htons ( PEERDIST_DISCOVERY_PORT ),
326  .sin6_addr.s6_addr = PEERDIST_DISCOVERY_IPV6,
327  },
328  },
329  .xfer = INTF_INIT ( peerdisc_socket_desc ),
330 };
331 
332 /******************************************************************************
333  *
334  * Discovery segments
335  *
336  ******************************************************************************
337  */
338 
339 /**
340  * Free PeerDist discovery segment
341  *
342  * @v refcnt Reference count
343  */
344 static void peerdisc_free ( struct refcnt *refcnt ) {
345  struct peerdisc_segment *segment =
347  struct peerdisc_peer *peer;
348  struct peerdisc_peer *tmp;
349 
350  /* Free all discovered peers */
351  list_for_each_entry_safe ( peer, tmp, &segment->peers, list ) {
352  list_del ( &peer->list );
353  free ( peer );
354  }
355 
356  /* Free segment */
357  free ( segment );
358 }
359 
360 /**
361  * Find PeerDist discovery segment
362  *
363  * @v id Segment ID
364  * @ret segment PeerDist discovery segment, or NULL if not found
365  */
366 static struct peerdisc_segment * peerdisc_find ( const char *id ) {
367  struct peerdisc_segment *segment;
368 
369  /* Look for a matching segment */
370  list_for_each_entry ( segment, &peerdisc_segments, list ) {
371  if ( strcmp ( id, segment->id ) == 0 )
372  return segment;
373  }
374 
375  return NULL;
376 }
377 
378 /**
379  * Add discovered PeerDist peer
380  *
381  * @v segment PeerDist discovery segment
382  * @v location Peer location
383  * @ret rc Return status code
384  */
386  const char *location ) {
387  struct peerdisc_peer *peer;
388  struct peerdisc_client *peerdisc;
389  struct peerdisc_client *tmp;
390  char *recent;
391 
392  /* Ignore duplicate peers */
393  list_for_each_entry ( peer, &segment->peers, list ) {
394  if ( strcmp ( peer->location, location ) == 0 ) {
395  DBGC2 ( segment, "PEERDISC %p duplicate %s\n",
396  segment, location );
397  return 0;
398  }
399  }
400  DBGC2 ( segment, "PEERDISC %p discovered %s\n", segment, location );
401 
402  /* Allocate and initialise structure */
403  peer = zalloc ( sizeof ( *peer ) + strlen ( location ) + 1 /* NUL */ );
404  if ( ! peer )
405  return -ENOMEM;
406  strcpy ( peer->location, location );
407 
408  /* Add to end of list of peers */
409  list_add_tail ( &peer->list, &segment->peers );
410 
411  /* Record as most recently discovered peer */
412  if ( location != peerdisc_recent ) {
413  recent = strdup ( location );
414  if ( recent ) {
415  free ( peerdisc_recent );
416  peerdisc_recent = recent;
417  }
418  }
419 
420  /* Notify all clients */
421  list_for_each_entry_safe ( peerdisc, tmp, &segment->clients, list )
422  peerdisc->op->discovered ( peerdisc );
423 
424  return 0;
425 }
426 
427 /**
428  * Handle discovery timer expiry
429  *
430  * @v timer Discovery timer
431  * @v over Failure indicator
432  */
433 static void peerdisc_expired ( struct retry_timer *timer, int over __unused ) {
434  struct peerdisc_segment *segment =
436 
437  /* Attempt to transmit discovery requests */
438  peerdisc_socket_tx ( segment->uuid, segment->id );
439 
440  /* Schedule next transmission, if applicable */
441  if ( timer->count < PEERDISC_REPEAT_COUNT )
443 }
444 
445 /**
446  * Create PeerDist discovery segment
447  *
448  * @v id Segment ID
449  * @ret segment PeerDist discovery segment, or NULL on error
450  */
451 static struct peerdisc_segment * peerdisc_create ( const char *id ) {
452  struct peerdisc_segment *segment;
453  union {
454  union uuid uuid;
455  uint32_t dword[ sizeof ( union uuid ) / sizeof ( uint32_t ) ];
456  } random_uuid;
457  size_t uuid_len;
458  size_t id_len;
459  const char *uuid;
460  char *uuid_copy;
461  char *id_copy;
462  unsigned int i;
463  int rc;
464 
465  /* Generate a random message UUID. This does not require high
466  * quality randomness.
467  */
468  for ( i = 0 ; i < ( sizeof ( random_uuid.dword ) /
469  sizeof ( random_uuid.dword[0] ) ) ; i++ )
470  random_uuid.dword[i] = random();
471  uuid = uuid_ntoa ( &random_uuid.uuid );
472 
473  /* Calculate string lengths */
474  id_len = ( strlen ( id ) + 1 /* NUL */ );
475  uuid_len = ( strlen ( uuid ) + 1 /* NUL */ );
476 
477  /* Allocate and initialise structure */
478  segment = zalloc ( sizeof ( *segment ) + id_len + uuid_len );
479  if ( ! segment )
480  goto err_alloc;
481  id_copy = ( ( ( void * ) segment ) + sizeof ( *segment ) );
482  memcpy ( id_copy, id, id_len );
483  uuid_copy = ( ( ( void * ) id_copy ) + id_len );
484  memcpy ( uuid_copy, uuid, uuid_len );
485  ref_init ( &segment->refcnt, peerdisc_free );
486  segment->id = id_copy;
487  segment->uuid = uuid_copy;
488  INIT_LIST_HEAD ( &segment->peers );
489  INIT_LIST_HEAD ( &segment->clients );
490  timer_init ( &segment->timer, peerdisc_expired, &segment->refcnt );
491 
492  /* Add hosted cache server or initiate discovery */
493  if ( peerhost ) {
494 
495  /* Add hosted cache server to list of peers */
496  if ( ( rc = peerdisc_discovered ( segment, peerhost ) ) != 0 )
497  goto err_peerhost;
498 
499  } else {
500 
501  /* Add most recently discovered peer to list of peers
502  *
503  * This is a performance optimisation: we assume that
504  * the most recently discovered peer for any block has
505  * a high probability of also having a copy of the
506  * next block that we attempt to discover.
507  */
508  if ( peerdisc_recent )
510 
511  /* Start discovery timer */
512  start_timer_nodelay ( &segment->timer );
513  DBGC2 ( segment, "PEERDISC %p discovering %s\n",
514  segment, segment->id );
515  }
516 
517  /* Add to list of segments, transfer reference to list, and return */
518  list_add_tail ( &segment->list, &peerdisc_segments );
519  return segment;
520 
521  err_peerhost:
522  ref_put ( &segment->refcnt );
523  err_alloc:
524  return NULL;
525 }
526 
527 /**
528  * Destroy PeerDist discovery segment
529  *
530  * @v segment PeerDist discovery segment
531  */
532 static void peerdisc_destroy ( struct peerdisc_segment *segment ) {
533 
534  /* Sanity check */
535  assert ( list_empty ( &segment->clients ) );
536 
537  /* Stop timer */
538  stop_timer ( &segment->timer );
539 
540  /* Remove from list of segments and drop list's reference */
541  list_del ( &segment->list );
542  ref_put ( &segment->refcnt );
543 }
544 
545 /******************************************************************************
546  *
547  * Discovery clients
548  *
549  ******************************************************************************
550  */
551 
552 /**
553  * Open PeerDist discovery client
554  *
555  * @v peerdisc PeerDist discovery client
556  * @v id Segment ID
557  * @v len Length of segment ID
558  * @ret rc Return status code
559  */
560 int peerdisc_open ( struct peerdisc_client *peerdisc, const void *id,
561  size_t len ) {
562  struct peerdisc_segment *segment;
563  char id_string[ base16_encoded_len ( len ) + 1 /* NUL */ ];
564  char *id_chr;
565  int rc;
566 
567  /* Construct ID string */
568  base16_encode ( id, len, id_string, sizeof ( id_string ) );
569  for ( id_chr = id_string ; *id_chr ; id_chr++ )
570  *id_chr = toupper ( *id_chr );
571 
572  /* Sanity check */
573  assert ( peerdisc->segment == NULL );
574 
575  /* Open socket if this is the first segment */
576  if ( list_empty ( &peerdisc_segments ) &&
577  ( ( rc = peerdisc_socket_open() ) != 0 ) )
578  return rc;
579 
580  /* Find or create segment */
581  if ( ! ( ( segment = peerdisc_find ( id_string ) ) ||
582  ( segment = peerdisc_create ( id_string ) ) ) )
583  return -ENOMEM;
584 
585  /* Add to list of clients */
586  ref_get ( &segment->refcnt );
587  peerdisc->segment = segment;
588  list_add_tail ( &peerdisc->list, &segment->clients );
589 
590  return 0;
591 }
592 
593 /**
594  * Close PeerDist discovery client
595  *
596  * @v peerdisc PeerDist discovery client
597  */
598 void peerdisc_close ( struct peerdisc_client *peerdisc ) {
599  struct peerdisc_segment *segment = peerdisc->segment;
600 
601  /* Ignore if discovery is already closed */
602  if ( ! segment )
603  return;
604 
605  /* If no peers were discovered, reduce the recommended
606  * discovery timeout to minimise delays on future requests.
607  */
608  if ( list_empty ( &segment->peers ) && peerdisc_timeout_secs ) {
610  DBGC ( segment, "PEERDISC %p reducing timeout to %d "
611  "seconds\n", peerdisc, peerdisc_timeout_secs );
612  }
613 
614  /* Remove from list of clients */
615  peerdisc->segment = NULL;
616  list_del ( &peerdisc->list );
617  ref_put ( &segment->refcnt );
618 
619  /* If this was the last clients, destroy the segment */
620  if ( list_empty ( &segment->clients ) )
622 
623  /* If there are no more segments, close the socket */
624  if ( list_empty ( &peerdisc_segments ) )
625  peerdisc_socket_close ( 0 );
626 }
627 
628 /******************************************************************************
629  *
630  * Settings
631  *
632  ******************************************************************************
633  */
634 
635 /** PeerDist hosted cache server setting */
636 const struct setting peerhost_setting __setting ( SETTING_MISC, peerhost ) = {
637  .name = "peerhost",
638  .description = "PeerDist hosted cache",
639  .type = &setting_type_string,
640 };
641 
642 /**
643  * Apply PeerDist discovery settings
644  *
645  * @ret rc Return status code
646  */
647 static int apply_peerdisc_settings ( void ) {
648 
649  /* Free any existing hosted cache server */
650  free ( peerhost );
651  peerhost = NULL;
652 
653  /* Fetch hosted cache server */
654  fetch_string_setting_copy ( NULL, &peerhost_setting, &peerhost );
655  if ( peerhost ) {
656  DBGC ( &peerhost, "PEERDISC using hosted cache %s\n",
657  peerhost );
658  }
659 
660  return 0;
661 }
662 
663 /** PeerDist discovery settings applicator */
664 struct settings_applicator peerdisc_applicator __settings_applicator = {
666 };
struct list_head peers
List of discovered peers.
Definition: peerdisc.h:64
An object interface operation.
Definition: interface.h:18
uint16_t segment
Code segment.
Definition: librm.h:138
TCP/IP socket address.
Definition: tcpip.h:76
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
Definition: interface.c:344
Data transfer metadata.
Definition: xfer.h:23
#define AF_INET6
IPv6 Internet addresses.
Definition: socket.h:65
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition: retry.h:100
int xfer_deliver_raw_meta(struct interface *intf, const void *data, size_t len, struct xfer_metadata *meta)
Deliver datagram as raw data.
Definition: xfer.c:269
static void peerdisc_socket_tx(const char *uuid, const char *id)
Attempt to transmit PeerDist discovery requests on all sockets.
Definition: peerdisc.c:158
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:65
Error codes.
A universally unique ID.
Definition: uuid.h:16
int xfer_open_socket(struct interface *intf, int semantics, struct sockaddr *peer, struct sockaddr *local)
Open socket.
Definition: open.c:143
static void peerdisc_socket_close(int rc)
Close all PeerDist discovery sockets.
Definition: peerdisc.c:289
A PeerDist discovery socket.
Definition: peerdisc.h:23
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
uint64_t address
Base address.
Definition: ena.h:24
#define INTF_INIT(descriptor)
Initialise a static object interface.
Definition: interface.h:218
#define SOCK_DGRAM
Definition: socket.h:30
A PeerDist discovery segment.
Definition: peerdisc.h:43
#define PEERDIST_DISCOVERY_IPV4
PeerDist discovery IPv4 address (239.255.255.250)
Definition: pccrd.h:17
#define DBGC(...)
Definition: compiler.h:505
A retry timer.
Definition: retry.h:22
const struct setting peerhost_setting __setting(SETTING_MISC, peerhost)
PeerDist hosted cache server setting.
Universally unique IDs.
A settings applicator.
Definition: settings.h:252
static struct interface_operation peerdisc_socket_operations[]
PeerDist discovery socket interface operations.
Definition: peerdisc.c:298
iPXE timers
#define SETTING_MISC
Miscellaneous settings.
Definition: settings.h:81
#define PEERDISC_SOCKETS
PeerDist discovery socket table.
Definition: peerdisc.h:37
static char * peerdisc_recent
Most recently discovered peer (for any block)
Definition: peerdisc.c:78
static void peerdisc_free(struct refcnt *refcnt)
Free PeerDist discovery segment.
Definition: peerdisc.c:344
struct list_head list
List of clients.
Definition: peerdisc.h:84
Character types.
Peer Content Caching and Retrieval (PeerDist) protocol peer discovery.
#define htonl(value)
Definition: byteswap.h:134
#define PEERDISC_DISCARD_RATE
Definition: fault.h:22
unsigned int scope_id
Scope ID.
Definition: netdevice.h:361
FILE_SECBOOT(PERMITTED)
static struct peerdisc_segment * peerdisc_find(const char *id)
Find PeerDist discovery segment.
Definition: peerdisc.c:366
void * intf_object(struct interface *intf)
Get pointer to object containing object interface.
Definition: interface.c:160
A doubly-linked list entry (or list head)
Definition: list.h:19
Data transfer interfaces.
struct interface * intf
Original interface.
Definition: interface.h:159
A reference counter.
Definition: refcnt.h:27
A timer.
Definition: timer.h:29
const char * name
Name.
Definition: settings.h:29
struct sockaddr_tcpip st
Definition: syslog.c:58
void peerdisc_stat(struct interface *intf, struct peerdisc_peer *peer, struct list_head *peers)
Report peer discovery statistics.
Definition: peerdisc.c:101
#define list_empty(list)
Test whether a list is empty.
Definition: list.h:137
static size_t base16_encoded_len(size_t raw_len)
Calculate length of base16-encoded data.
Definition: base16.h:25
static int toupper(int character)
Convert character to upper case.
Definition: ctype.h:121
unsigned long tmp
Definition: linux_pci.h:65
struct interface xfer
Data transfer interface.
Definition: peerdisc.h:27
#define list_del(list)
Delete an entry from a list.
Definition: list.h:120
#define ENOMEM
Not enough space.
Definition: errno.h:535
void(* discovered)(struct peerdisc_client *peerdisc)
New peers have been discovered.
Definition: peerdisc.h:95
char * peerdist_discovery_request(const char *uuid, const char *id)
Construct discovery request.
Definition: pccrd.c:107
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int netdev_is_open(struct net_device *netdev)
Check whether or not network device is open.
Definition: netdevice.h:662
struct sockaddr sa
Definition: peerdisc.h:30
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
A PeerDist discovery client.
Definition: peerdisc.h:80
An object interface.
Definition: interface.h:125
int peerdisc_open(struct peerdisc_client *peerdisc, const void *id, size_t len)
Open PeerDist discovery client.
Definition: peerdisc.c:560
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:432
uint8_t uuid[16]
UUID.
Definition: smbios.h:23
#define DBGC_HDA(...)
Definition: compiler.h:506
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition: list.h:94
ring len
Length.
Definition: dwmac.h:231
Peer Content Caching and Retrieval: Discovery Protocol [MS-PCCRD].
A PeerDist discovery reply.
Definition: pccrd.h:31
static struct net_device * netdev
Definition: gdbudp.c:52
struct sockaddr sa
Definition: syslog.c:57
Transport-network layer interface.
char * strcpy(char *dest, const char *src)
Copy string.
Definition: string.c:347
int fetch_string_setting_copy(struct settings *settings, const struct setting *setting, char **data)
Fetch value of string setting.
Definition: settings.c:874
char * locations
List of peer locations.
Definition: pccrd.h:41
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition: list.h:459
uint8_t id
Request identifier.
Definition: ena.h:12
static char * peerhost
Hosted cache server.
Definition: peerdisc.c:81
struct settings_applicator peerdisc_applicator __settings_applicator
PeerDist discovery settings applicator.
Definition: peerdisc.c:664
Configuration settings.
Generalized socket address structure.
Definition: socket.h:97
An object interface descriptor.
Definition: interface.h:56
uint8_t id_string[24]
ID string.
Definition: eltorito.h:24
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
#define for_each_netdev(netdev)
Iterate over all network devices.
Definition: netdevice.h:547
#define ref_get(refcnt)
Get additional reference to object.
Definition: refcnt.h:93
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
#define PEERDISC_REPEAT_TIMEOUT
Time between repeated discovery attempts.
Definition: peerdisc.c:58
#define PEERDIST_DISCOVERY_IPV6
PeerDist discovery IPv6 address (ff02::c)
Definition: pccrd.h:21
static int peerdisc_socket_rx(struct peerdisc_socket *socket, struct io_buffer *iobuf, struct xfer_metadata *meta __unused)
Handle received PeerDist discovery reply.
Definition: peerdisc.c:225
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:33
char * strdup(const char *src)
Duplicate string.
Definition: string.c:394
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
A network device.
Definition: netdevice.h:353
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:32
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:195
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
Data transfer interface opening.
static void peerdisc_expired(struct retry_timer *timer, int over __unused)
Handle discovery timer expiry.
Definition: peerdisc.c:433
char * ids
List of segment ID strings.
Definition: pccrd.h:36
unsigned int uint32_t
Definition: stdint.h:12
const char * uuid_ntoa(const union uuid *uuid)
Convert UUID to printable string.
Definition: uuid.c:46
struct peerdisc_segment * segment
Discovery segment.
Definition: peerdisc.h:82
static struct interface_descriptor peerdisc_socket_desc
PeerDist discovery socket interface descriptor.
Definition: peerdisc.c:303
static struct peerdisc_segment * peerdisc_create(const char *id)
Create PeerDist discovery segment.
Definition: peerdisc.c:451
A setting.
Definition: settings.h:24
Network device management.
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition: retry.c:65
static LIST_HEAD(peerdisc_segments)
List of discovery segments.
static uint16_t struct vmbus_xfer_pages_operations * op
Definition: netvsc.h:327
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition: list.h:46
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:81
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition: retry.c:118
struct list_head list
List of segments.
Definition: peerdisc.h:47
#define PEERDISC_REPEAT_COUNT
Number of repeated discovery attempts.
Definition: peerdisc.c:55
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:363
#define peerdisc_stat_TYPE(object_type)
Definition: peerdisc.h:115
#define DBGC2(...)
Definition: compiler.h:522
static void peerdisc_destroy(struct peerdisc_segment *segment)
Destroy PeerDist discovery segment.
Definition: peerdisc.c:532
int strcmp(const char *first, const char *second)
Compare strings.
Definition: string.c:174
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void * data
Start of data.
Definition: iobuf.h:53
void intf_put(struct interface *intf)
Decrement reference count on an object interface.
Definition: interface.c:150
u8 request[0]
List of IEs requested.
Definition: ieee80211.h:16
static int peerdisc_discovered(struct peerdisc_segment *segment, const char *location)
Add discovered PeerDist peer.
Definition: peerdisc.c:385
struct peerdisc_socket peerdisc_socket_ipv4 __peerdisc_socket
PeerDist discovery IPv4 socket.
Definition: peerdisc.c:307
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" return dest
Definition: string.h:151
int(* apply)(void)
Apply updated settings.
Definition: settings.h:257
static int apply_peerdisc_settings(void)
Apply PeerDist discovery settings.
Definition: peerdisc.c:647
struct peerdisc_client_operations * op
Operations.
Definition: peerdisc.h:86
Fault injection.
struct mschapv2_challenge peer
Peer challenge.
Definition: mschapv2.h:12
const char * name
Name.
Definition: peerdisc.h:25
uint8_t meta
Metadata flags.
Definition: ena.h:14
#define PEERDISC_DEFAULT_TIMEOUT_SECS
Default discovery timeout (in seconds)
Definition: peerdisc.c:61
struct list_head list
List of peers.
Definition: peerdisc.h:74
#define PEERDIST_DISCOVERY_PORT
PeerDist discovery port.
Definition: pccrd.h:14
#define for_each_table_entry_continue_reverse(pointer, table)
Iterate through all remaining entries within a linker table in reverse order.
Definition: tables.h:470
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
static int peerdisc_socket_open(void)
Open all PeerDist discovery sockets.
Definition: peerdisc.c:129
#define htons(value)
Definition: byteswap.h:136
union peerdisc_socket::@655 address
Socket address.
#define intf_get_dest_op(intf, type, dest)
Get object interface destination and operation method.
Definition: interface.h:270
unsigned long int dword
Definition: smc9000.h:40
#define AF_INET
IPv4 Internet addresses.
Definition: socket.h:64
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:107
void * memset(void *dest, int character, size_t len) __nonnull
void peerdisc_close(struct peerdisc_client *peerdisc)
Close PeerDist discovery client.
Definition: peerdisc.c:598
unsigned int peerdisc_timeout_secs
Recommended discovery timeout (in seconds)
Definition: peerdisc.c:75
Base16 encoding.
A persistent I/O buffer.
Definition: iobuf.h:38
A PeerDist discovery peer.
Definition: peerdisc.h:72