6 * This file should be rewritten to avoid the use of a bitmap. Our
7 * buffer routines can cope with being handed blocks in an arbitrary
8 * order, duplicate blocks, etc. This code could be substantially
9 * simplified by taking advantage of these features.
13 #define SLAM_PORT 10000
14 #define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
15 #define SLAM_MULTICAST_PORT 10000
16 #define SLAM_LOCAL_PORT 10000
18 /* Set the timeout intervals to at least 1 second so
19 * on a 100Mbit ethernet can receive 10000 packets
22 * The only case that is likely to trigger all of the nodes
23 * firing a nack packet is a slow server. The odds of this
24 * happening could be reduced being slightly smarter and utilizing
25 * the multicast channels for nacks. But that only improves the odds
26 * it doesn't improve the worst case. So unless this proves to be
27 * a common case having the control data going unicast should increase
28 * the odds of the data not being dropped.
30 * When doing exponential backoff we increase just the timeout
31 * interval and not the base to optimize for throughput. This is only
32 * expected to happen when the server is down. So having some nodes
33 * pinging immediately should get the transmission restarted quickly after a
34 * server restart. The host nic won't be to baddly swamped because of
35 * the random distribution of the nodes.
38 #define SLAM_INITIAL_MIN_TIMEOUT (TICKS_PER_SEC/3)
39 #define SLAM_INITIAL_TIMEOUT_INTERVAL (TICKS_PER_SEC)
40 #define SLAM_BASE_MIN_TIMEOUT (2*TICKS_PER_SEC)
41 #define SLAM_BASE_TIMEOUT_INTERVAL (4*TICKS_PER_SEC)
42 #define SLAM_BACKOFF_LIMIT 5
43 #define SLAM_MAX_RETRIES 20
45 /*** Packets Formats ***
53 * Status Request Packet
69 #define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
70 #define MIN_HDR (1 + 1 + 1) /* transactino, total size, block size */
72 #define MAX_SLAM_REQUEST MAX_HDR
73 #define MIN_SLAM_REQUEST MIN_HDR
75 #define MIN_SLAM_DATA (MIN_HDR + 1)
77 static struct slam_nack
{
80 unsigned char data
[ETH_MAX_MTU
-
81 (sizeof(struct iphdr
) + sizeof(struct udphdr
))];
85 unsigned char hdr
[MAX_HDR
];
86 unsigned long hdr_len
;
87 unsigned long block_size
;
88 unsigned long total_bytes
;
89 unsigned long total_packets
;
91 unsigned long received_packets
;
93 struct buffer
*buffer
;
95 unsigned char *bitmap
;
99 static void init_slam_state(void)
101 state
.hdr_len
= sizeof(state
.hdr
);
102 memset(state
.hdr
, 0, state
.hdr_len
);
103 state
.block_size
= 0;
104 state
.total_packets
= 0;
106 state
.received_packets
= 0;
113 struct sockaddr_in server
;
114 struct sockaddr_in local
;
115 struct sockaddr_in multicast
;
117 struct buffer
*buffer
;
120 #define SLAM_TIMEOUT 0
121 #define SLAM_REQUEST 1
123 static int await_slam(int ival __unused
, void *ptr
,
124 unsigned short ptype __unused
, struct iphdr
*ip
,
125 struct udphdr
*udp
, struct tcphdr
*tcp __unused
)
127 struct slam_info
*info
= ptr
;
131 /* I can receive two kinds of packets here, a multicast data packet,
132 * or a unicast request for information
134 /* Check for a data request packet */
135 if ((ip
->dest
.s_addr
== arptable
[ARP_CLIENT
].ipaddr
.s_addr
) &&
136 (ntohs(udp
->dest
) == info
->local
.sin_port
) &&
139 sizeof(struct iphdr
) +
140 sizeof(struct udphdr
) +
144 /* Check for a multicast data packet */
145 if ((ip
->dest
.s_addr
== info
->multicast
.sin_addr
.s_addr
) &&
146 (ntohs(udp
->dest
) == info
->multicast
.sin_port
) &&
149 sizeof(struct iphdr
) +
150 sizeof(struct udphdr
) +
156 printf("dest: %@ port: %d len: %d\n",
157 ip
->dest
.s_addr
, ntohs(udp
->dest
), nic
.packetlen
);
163 static int slam_encode(
164 unsigned char **ptr
, unsigned char *end
, unsigned long value
)
166 unsigned char *data
= *ptr
;
168 bytes
= sizeof(value
);
169 while ((bytes
> 0) && ((0xff & (value
>> ((bytes
-1)<<3))) == 0)) {
175 if (data
+ bytes
>= end
) {
178 if ((0xe0 & (value
>> ((bytes
-1)<<3))) == 0) {
179 /* packed together */
180 *data
= (bytes
<< 5) | (value
>> ((bytes
-1)<<3));
183 *data
= (bytes
<< 5);
188 *(data
++) = 0xff & (value
>> ((bytes
-1)<<3));
195 static int slam_skip(unsigned char **ptr
, unsigned char *end
)
201 bytes
= ((**ptr
) >> 5) & 7;
205 if (*ptr
+ bytes
>= end
) {
213 static unsigned long slam_decode(unsigned char **ptr
, unsigned char *end
,
221 bytes
= ((**ptr
) >> 5) & 7;
222 if ((bytes
== 0) || (bytes
> sizeof(unsigned long))) {
226 if ((*ptr
) + bytes
>= end
) {
229 value
= (**ptr
) & 0x1f;
242 static long slam_sleep_interval(int exp
)
247 range
= SLAM_BASE_TIMEOUT_INTERVAL
;
249 divisor
= RAND_MAX
/SLAM_INITIAL_TIMEOUT_INTERVAL
;
251 if (exp
> SLAM_BACKOFF_LIMIT
)
252 exp
= SLAM_BACKOFF_LIMIT
;
253 divisor
= RAND_MAX
/(range
<< exp
);
255 interval
= random()/divisor
;
257 interval
+= SLAM_INITIAL_MIN_TIMEOUT
;
259 interval
+= SLAM_BASE_MIN_TIMEOUT
;
265 static unsigned char *reinit_slam_state(
266 unsigned char *header
, unsigned char *end
)
268 unsigned long total_bytes
;
269 unsigned long block_size
;
271 unsigned long bitmap_len
;
272 unsigned long max_packet_len
;
282 err
= slam_skip(&data
, end
); /* transaction id */
283 total_bytes
= slam_decode(&data
, end
, &err
);
284 block_size
= slam_decode(&data
, end
, &err
);
286 printf("ALERT: slam size out of range\n");
289 state
.block_size
= block_size
;
290 state
.total_bytes
= total_bytes
;
291 state
.total_packets
= (total_bytes
+ block_size
- 1)/block_size
;
292 state
.hdr_len
= data
- header
;
293 state
.received_packets
= 0;
296 slam_encode(&data
, &state
.hdr
[sizeof(state
.hdr
)], state
.total_packets
);
297 max_packet_len
= data
- state
.hdr
;
298 memcpy(state
.hdr
, header
, state
.hdr_len
);
301 printf("block_size: %ld\n", block_size
);
302 printf("total_bytes: %ld\n", total_bytes
);
303 printf("total_packets: %ld\n", state
.total_packets
);
304 printf("hdr_len: %ld\n", state
.hdr_len
);
305 printf("max_packet_len: %ld\n", max_packet_len
);
308 if (state
.block_size
> ETH_MAX_MTU
- (
309 sizeof(struct iphdr
) + sizeof(struct udphdr
) +
310 state
.hdr_len
+ max_packet_len
)) {
311 printf("ALERT: slam blocksize to large\n");
314 bitmap_len
= (state
.total_packets
+ 1 + 7)/8;
315 state
.image
= phys_to_virt ( state
.buffer
->addr
);
316 /* We don't use the buffer routines properly yet; fake it */
317 state
.buffer
->fill
= total_bytes
;
318 state
.bitmap
= state
.image
+ total_bytes
;
319 if ((unsigned long)state
.image
< 1024*1024) {
320 printf("ALERT: slam filesize to large for available memory\n");
323 memset(state
.bitmap
, 0, bitmap_len
);
325 return header
+ state
.hdr_len
;
328 static int slam_recv_data(unsigned char *data
)
330 unsigned long packet
;
331 unsigned long data_len
;
334 udp
= (struct udphdr
*)&nic
.packet
[ETH_HLEN
+ sizeof(struct iphdr
)];
336 packet
= slam_decode(&data
, &nic
.packet
[nic
.packetlen
], &err
);
337 if (err
|| (packet
> state
.total_packets
)) {
338 printf("ALERT: Invalid packet number\n");
341 /* Compute the expected data length */
342 if (packet
!= state
.total_packets
-1) {
343 data_len
= state
.block_size
;
345 data_len
= state
.total_bytes
% state
.block_size
;
347 /* If the packet size is wrong drop the packet and then continue */
348 if (ntohs(udp
->len
) != (data_len
+ (data
- (unsigned char*)udp
))) {
349 printf("ALERT: udp packet is not the correct size\n");
352 if (nic
.packetlen
< data_len
+ (data
- nic
.packet
)) {
353 printf("ALERT: Ethernet packet shorter than data_len\n");
356 if (data_len
> state
.block_size
) {
357 data_len
= state
.block_size
;
359 if (((state
.bitmap
[packet
>> 3] >> (packet
& 7)) & 1) == 0) {
360 /* Non duplicate packet */
361 state
.bitmap
[packet
>> 3] |= (1 << (packet
& 7));
362 memcpy(state
.image
+ (packet
*state
.block_size
), data
, data_len
);
363 state
.received_packets
++;
372 static void transmit_nack(unsigned char *ptr
, struct slam_info
*info
)
375 /* Ensure the packet is null terminated */
377 nack_len
= ptr
- (unsigned char *)&nack
;
378 build_udp_hdr(info
->server
.sin_addr
.s_addr
, info
->local
.sin_port
,
379 info
->server
.sin_port
, 1, nack_len
, &nack
);
380 ip_transmit(nack_len
, &nack
);
381 #if defined(MDEBUG) && 0
382 printf("Sent NACK to %@ bytes: %d have:%ld/%ld\n",
383 info
->server_ip
, nack_len
,
384 state
.received_packets
, state
.total_packets
);
388 static void slam_send_nack(struct slam_info
*info
)
390 unsigned char *ptr
, *end
;
391 /* Either I timed out or I was explicitly
392 * asked for a request packet
395 /* Reserve space for the trailling null */
396 end
= &nack
.data
[sizeof(nack
.data
) -1];
398 slam_encode(&ptr
, end
, 0);
399 slam_encode(&ptr
, end
, 1);
402 /* Walk the bitmap */
408 /* Compute the last bit and store an inverted trailer */
409 max
= state
.total_packets
;
410 value
= ((state
.bitmap
[(max
-1) >> 3] >> ((max
-1) & 7) ) & 1);
412 state
.bitmap
[max
>> 3] &= ~(1 << (max
& 7));
413 state
.bitmap
[max
>> 3] |= value
<< (max
& 7);
416 last
= 1; /* Start with the received packets */
417 for(i
= 0; i
<= max
; i
++) {
418 value
= (state
.bitmap
[i
>>3] >> (i
& 7)) & 1;
422 if (slam_encode(&ptr
, end
, len
))
430 transmit_nack(ptr
, info
);
433 static void slam_send_disconnect(struct slam_info
*info
)
435 if (info
->sent_nack
) {
436 /* A disconnect is a packet with just the null terminator */
437 transmit_nack(&nack
.data
[0], info
);
443 static int proto_slam(struct slam_info
*info
)
449 state
.buffer
= info
->buffer
;
453 /* Arp for my server */
454 if (arptable
[ARP_SERVER
].ipaddr
.s_addr
!= info
->server
.sin_addr
.s_addr
) {
455 arptable
[ARP_SERVER
].ipaddr
.s_addr
= info
->server
.sin_addr
.s_addr
;
456 memset(arptable
[ARP_SERVER
].node
, 0, ETH_ALEN
);
458 /* If I'm running over multicast join the multicast group */
459 join_group(IGMP_SERVER
, info
->multicast
.sin_addr
.s_addr
);
461 unsigned char *header
;
466 timeout
= slam_sleep_interval(retry
);
467 type
= await_reply(await_slam
, 0, info
, timeout
);
468 /* Compute the timeout for next time */
469 if (type
== SLAM_TIMEOUT
) {
470 /* If I timeouted recompute the next timeout */
471 if (retry
++ > SLAM_MAX_RETRIES
) {
477 if ((type
== SLAM_DATA
) || (type
== SLAM_REQUEST
)) {
478 /* Check the incomming packet and reinit the data
479 * structures if necessary.
481 header
= &nic
.packet
[ETH_HLEN
+
482 sizeof(struct iphdr
) + sizeof(struct udphdr
)];
483 data
= header
+ state
.hdr_len
;
484 if (memcmp(state
.hdr
, header
, state
.hdr_len
) != 0) {
485 /* Something is fishy reset the transaction */
486 data
= reinit_slam_state(header
, &nic
.packet
[nic
.packetlen
]);
492 if (type
== SLAM_DATA
) {
493 if (!slam_recv_data(data
)) {
496 if (state
.received_packets
== state
.total_packets
) {
497 /* We are done get out */
501 if ((type
== SLAM_TIMEOUT
) || (type
== SLAM_REQUEST
)) {
502 /* Either I timed out or I was explicitly
503 * asked by a request packet
505 slam_send_nack(info
);
508 slam_send_disconnect(info
);
510 /* Leave the multicast group */
511 leave_group(IGMP_SERVER
);
512 /* FIXME don't overwrite myself */
513 /* load file to correct location */
517 static int url_slam ( char *url __unused
, struct sockaddr_in
*server
,
518 char *file
, struct buffer
*buffer
) {
519 struct slam_info info
;
520 /* Set the defaults */
521 info
.server
= *server
;
522 info
.multicast
.sin_addr
.s_addr
= htonl(SLAM_MULTICAST_IP
);
523 info
.multicast
.sin_port
= SLAM_MULTICAST_PORT
;
524 info
.local
.sin_addr
.s_addr
= arptable
[ARP_CLIENT
].ipaddr
.s_addr
;
525 info
.local
.sin_port
= SLAM_LOCAL_PORT
;
526 info
.buffer
= buffer
;
529 printf("\nBad url\n");
532 return proto_slam(&info
);
535 struct protocol slam_protocol __protocol
= {
537 .default_port
= SLAM_PORT
,