You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

slam.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #include "etherboot.h"
  2. #include "proto.h"
  3. #include "nic.h"
  4. /*
  5. * IMPORTANT
  6. *
  7. * This file should be rewritten to avoid the use of a bitmap. Our
  8. * buffer routines can cope with being handed blocks in an arbitrary
  9. * order, duplicate blocks, etc. This code could be substantially
  10. * simplified by taking advantage of these features.
  11. *
  12. */
  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
  17. /* Set the timeout intervals to at least 1 second so
  18. * on a 100Mbit ethernet can receive 10000 packets
  19. * in one second.
  20. *
  21. * The only case that is likely to trigger all of the nodes
  22. * firing a nack packet is a slow server. The odds of this
  23. * happening could be reduced being slightly smarter and utilizing
  24. * the multicast channels for nacks. But that only improves the odds
  25. * it doesn't improve the worst case. So unless this proves to be
  26. * a common case having the control data going unicast should increase
  27. * the odds of the data not being dropped.
  28. *
  29. * When doing exponential backoff we increase just the timeout
  30. * interval and not the base to optimize for throughput. This is only
  31. * expected to happen when the server is down. So having some nodes
  32. * pinging immediately should get the transmission restarted quickly after a
  33. * server restart. The host nic won't be to baddly swamped because of
  34. * the random distribution of the nodes.
  35. *
  36. */
  37. #define SLAM_INITIAL_MIN_TIMEOUT (TICKS_PER_SEC/3)
  38. #define SLAM_INITIAL_TIMEOUT_INTERVAL (TICKS_PER_SEC)
  39. #define SLAM_BASE_MIN_TIMEOUT (2*TICKS_PER_SEC)
  40. #define SLAM_BASE_TIMEOUT_INTERVAL (4*TICKS_PER_SEC)
  41. #define SLAM_BACKOFF_LIMIT 5
  42. #define SLAM_MAX_RETRIES 20
  43. /*** Packets Formats ***
  44. * Data Packet:
  45. * transaction
  46. * total bytes
  47. * block size
  48. * packet #
  49. * data
  50. *
  51. * Status Request Packet
  52. * transaction
  53. * total bytes
  54. * block size
  55. *
  56. * Status Packet
  57. * received packets
  58. * requested packets
  59. * received packets
  60. * requested packets
  61. * ...
  62. * received packets
  63. * requested packtes
  64. * 0
  65. */
  66. #define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
  67. #define MIN_HDR (1 + 1 + 1) /* transactino, total size, block size */
  68. #define MAX_SLAM_REQUEST MAX_HDR
  69. #define MIN_SLAM_REQUEST MIN_HDR
  70. #define MIN_SLAM_DATA (MIN_HDR + 1)
  71. static struct slam_nack {
  72. struct iphdr ip;
  73. struct udphdr udp;
  74. unsigned char data[ETH_MAX_MTU -
  75. (sizeof(struct iphdr) + sizeof(struct udphdr))];
  76. } nack;
  77. struct slam_state {
  78. unsigned char hdr[MAX_HDR];
  79. unsigned long hdr_len;
  80. unsigned long block_size;
  81. unsigned long total_bytes;
  82. unsigned long total_packets;
  83. unsigned long received_packets;
  84. struct buffer *buffer;
  85. unsigned char *image;
  86. unsigned char *bitmap;
  87. } state;
  88. static void init_slam_state(void)
  89. {
  90. state.hdr_len = sizeof(state.hdr);
  91. memset(state.hdr, 0, state.hdr_len);
  92. state.block_size = 0;
  93. state.total_packets = 0;
  94. state.received_packets = 0;
  95. state.image = 0;
  96. state.bitmap = 0;
  97. }
  98. struct slam_info {
  99. struct sockaddr_in server;
  100. struct sockaddr_in local;
  101. struct sockaddr_in multicast;
  102. int sent_nack;
  103. struct buffer *buffer;
  104. };
  105. #define SLAM_TIMEOUT 0
  106. #define SLAM_REQUEST 1
  107. #define SLAM_DATA 2
  108. static int await_slam(int ival __unused, void *ptr,
  109. unsigned short ptype __unused, struct iphdr *ip,
  110. struct udphdr *udp, struct tcphdr *tcp __unused)
  111. {
  112. struct slam_info *info = ptr;
  113. if (!udp) {
  114. return 0;
  115. }
  116. /* I can receive two kinds of packets here, a multicast data packet,
  117. * or a unicast request for information
  118. */
  119. /* Check for a data request packet */
  120. if ((ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) &&
  121. (ntohs(udp->dest) == info->local.sin_port) &&
  122. (nic.packetlen >=
  123. ETH_HLEN +
  124. sizeof(struct iphdr) +
  125. sizeof(struct udphdr) +
  126. MIN_SLAM_REQUEST)) {
  127. return SLAM_REQUEST;
  128. }
  129. /* Check for a multicast data packet */
  130. if ((ip->dest.s_addr == info->multicast.sin_addr.s_addr) &&
  131. (ntohs(udp->dest) == info->multicast.sin_port) &&
  132. (nic.packetlen >=
  133. ETH_HLEN +
  134. sizeof(struct iphdr) +
  135. sizeof(struct udphdr) +
  136. MIN_SLAM_DATA)) {
  137. return SLAM_DATA;
  138. }
  139. #if 0
  140. printf("#");
  141. printf("dest: %@ port: %d len: %d\n",
  142. ip->dest.s_addr, ntohs(udp->dest), nic.packetlen);
  143. #endif
  144. return 0;
  145. }
  146. static int slam_encode(
  147. unsigned char **ptr, unsigned char *end, unsigned long value)
  148. {
  149. unsigned char *data = *ptr;
  150. int bytes;
  151. bytes = sizeof(value);
  152. while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) {
  153. bytes--;
  154. }
  155. if (bytes <= 0) {
  156. bytes = 1;
  157. }
  158. if (data + bytes >= end) {
  159. return -1;
  160. }
  161. if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) {
  162. /* packed together */
  163. *data = (bytes << 5) | (value >> ((bytes -1)<<3));
  164. } else {
  165. bytes++;
  166. *data = (bytes << 5);
  167. }
  168. bytes--;
  169. data++;
  170. while(bytes) {
  171. *(data++) = 0xff & (value >> ((bytes -1)<<3));
  172. bytes--;
  173. }
  174. *ptr = data;
  175. return 0;
  176. }
  177. static int slam_skip(unsigned char **ptr, unsigned char *end)
  178. {
  179. int bytes;
  180. if (*ptr >= end) {
  181. return -1;
  182. }
  183. bytes = ((**ptr) >> 5) & 7;
  184. if (bytes == 0) {
  185. return -1;
  186. }
  187. if (*ptr + bytes >= end) {
  188. return -1;
  189. }
  190. (*ptr) += bytes;
  191. return 0;
  192. }
  193. static unsigned long slam_decode(unsigned char **ptr, unsigned char *end,
  194. int *err)
  195. {
  196. unsigned long value;
  197. unsigned bytes;
  198. if (*ptr >= end) {
  199. *err = -1;
  200. }
  201. bytes = ((**ptr) >> 5) & 7;
  202. if ((bytes == 0) || (bytes > sizeof(unsigned long))) {
  203. *err = -1;
  204. return 0;
  205. }
  206. if ((*ptr) + bytes >= end) {
  207. *err = -1;
  208. }
  209. value = (**ptr) & 0x1f;
  210. bytes--;
  211. (*ptr)++;
  212. while(bytes) {
  213. value <<= 8;
  214. value |= **ptr;
  215. (*ptr)++;
  216. bytes--;
  217. }
  218. return value;
  219. }
  220. static long slam_sleep_interval(int exp)
  221. {
  222. long range;
  223. long divisor;
  224. long interval;
  225. range = SLAM_BASE_TIMEOUT_INTERVAL;
  226. if (exp < 0) {
  227. divisor = RAND_MAX/SLAM_INITIAL_TIMEOUT_INTERVAL;
  228. } else {
  229. if (exp > SLAM_BACKOFF_LIMIT)
  230. exp = SLAM_BACKOFF_LIMIT;
  231. divisor = RAND_MAX/(range << exp);
  232. }
  233. interval = random()/divisor;
  234. if (exp < 0) {
  235. interval += SLAM_INITIAL_MIN_TIMEOUT;
  236. } else {
  237. interval += SLAM_BASE_MIN_TIMEOUT;
  238. }
  239. return interval;
  240. }
  241. static unsigned char *reinit_slam_state(
  242. unsigned char *header, unsigned char *end)
  243. {
  244. unsigned long total_bytes;
  245. unsigned long block_size;
  246. unsigned long bitmap_len;
  247. unsigned long max_packet_len;
  248. unsigned char *data;
  249. int err;
  250. #if 0
  251. printf("reinit\n");
  252. #endif
  253. data = header;
  254. state.hdr_len = 0;
  255. err = slam_skip(&data, end); /* transaction id */
  256. total_bytes = slam_decode(&data, end, &err);
  257. block_size = slam_decode(&data, end, &err);
  258. if (err) {
  259. printf("ALERT: slam size out of range\n");
  260. return 0;
  261. }
  262. state.block_size = block_size;
  263. state.total_bytes = total_bytes;
  264. state.total_packets = (total_bytes + block_size - 1)/block_size;
  265. state.hdr_len = data - header;
  266. state.received_packets = 0;
  267. data = state.hdr;
  268. slam_encode(&data, &state.hdr[sizeof(state.hdr)], state.total_packets);
  269. max_packet_len = data - state.hdr;
  270. memcpy(state.hdr, header, state.hdr_len);
  271. #if 0
  272. printf("block_size: %ld\n", block_size);
  273. printf("total_bytes: %ld\n", total_bytes);
  274. printf("total_packets: %ld\n", state.total_packets);
  275. printf("hdr_len: %ld\n", state.hdr_len);
  276. printf("max_packet_len: %ld\n", max_packet_len);
  277. #endif
  278. if (state.block_size > ETH_MAX_MTU - (
  279. sizeof(struct iphdr) + sizeof(struct udphdr) +
  280. state.hdr_len + max_packet_len)) {
  281. printf("ALERT: slam blocksize to large\n");
  282. return 0;
  283. }
  284. bitmap_len = (state.total_packets + 1 + 7)/8;
  285. state.image = phys_to_virt ( state.buffer->addr );
  286. /* We don't use the buffer routines properly yet; fake it */
  287. state.buffer->fill = total_bytes;
  288. state.bitmap = state.image + total_bytes;
  289. if ((unsigned long)state.image < 1024*1024) {
  290. printf("ALERT: slam filesize to large for available memory\n");
  291. return 0;
  292. }
  293. memset(state.bitmap, 0, bitmap_len);
  294. return header + state.hdr_len;
  295. }
  296. static int slam_recv_data(unsigned char *data)
  297. {
  298. unsigned long packet;
  299. unsigned long data_len;
  300. int err;
  301. struct udphdr *udp;
  302. udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
  303. err = 0;
  304. packet = slam_decode(&data, &nic.packet[nic.packetlen], &err);
  305. if (err || (packet > state.total_packets)) {
  306. printf("ALERT: Invalid packet number\n");
  307. return 0;
  308. }
  309. /* Compute the expected data length */
  310. if (packet != state.total_packets -1) {
  311. data_len = state.block_size;
  312. } else {
  313. data_len = state.total_bytes % state.block_size;
  314. }
  315. /* If the packet size is wrong drop the packet and then continue */
  316. if (ntohs(udp->len) != (data_len + (data - (unsigned char*)udp))) {
  317. printf("ALERT: udp packet is not the correct size\n");
  318. return 1;
  319. }
  320. if (nic.packetlen < data_len + (data - nic.packet)) {
  321. printf("ALERT: Ethernet packet shorter than data_len\n");
  322. return 1;
  323. }
  324. if (data_len > state.block_size) {
  325. data_len = state.block_size;
  326. }
  327. if (((state.bitmap[packet >> 3] >> (packet & 7)) & 1) == 0) {
  328. /* Non duplicate packet */
  329. state.bitmap[packet >> 3] |= (1 << (packet & 7));
  330. memcpy(state.image + (packet*state.block_size), data, data_len);
  331. state.received_packets++;
  332. } else {
  333. #ifdef MDEBUG
  334. printf("<DUP>\n");
  335. #endif
  336. }
  337. return 1;
  338. }
  339. static void transmit_nack(unsigned char *ptr, struct slam_info *info)
  340. {
  341. int nack_len;
  342. /* Ensure the packet is null terminated */
  343. *ptr++ = 0;
  344. nack_len = ptr - (unsigned char *)&nack;
  345. build_udp_hdr(info->server.sin_addr.s_addr, info->local.sin_port,
  346. info->server.sin_port, 1, nack_len, &nack);
  347. ip_transmit(nack_len, &nack);
  348. #if defined(MDEBUG) && 0
  349. printf("Sent NACK to %@ bytes: %d have:%ld/%ld\n",
  350. info->server_ip, nack_len,
  351. state.received_packets, state.total_packets);
  352. #endif
  353. }
  354. static void slam_send_nack(struct slam_info *info)
  355. {
  356. unsigned char *ptr, *end;
  357. /* Either I timed out or I was explicitly
  358. * asked for a request packet
  359. */
  360. ptr = &nack.data[0];
  361. /* Reserve space for the trailling null */
  362. end = &nack.data[sizeof(nack.data) -1];
  363. if (!state.bitmap) {
  364. slam_encode(&ptr, end, 0);
  365. slam_encode(&ptr, end, 1);
  366. }
  367. else {
  368. /* Walk the bitmap */
  369. unsigned long i;
  370. unsigned long len;
  371. unsigned long max;
  372. int value;
  373. int last;
  374. /* Compute the last bit and store an inverted trailer */
  375. max = state.total_packets;
  376. value = ((state.bitmap[(max -1) >> 3] >> ((max -1) & 7) ) & 1);
  377. value = !value;
  378. state.bitmap[max >> 3] &= ~(1 << (max & 7));
  379. state.bitmap[max >> 3] |= value << (max & 7);
  380. len = 0;
  381. last = 1; /* Start with the received packets */
  382. for(i = 0; i <= max; i++) {
  383. value = (state.bitmap[i>>3] >> (i & 7)) & 1;
  384. if (value == last) {
  385. len++;
  386. } else {
  387. if (slam_encode(&ptr, end, len))
  388. break;
  389. last = value;
  390. len = 1;
  391. }
  392. }
  393. }
  394. info->sent_nack = 1;
  395. transmit_nack(ptr, info);
  396. }
  397. static void slam_send_disconnect(struct slam_info *info)
  398. {
  399. if (info->sent_nack) {
  400. /* A disconnect is a packet with just the null terminator */
  401. transmit_nack(&nack.data[0], info);
  402. }
  403. info->sent_nack = 0;
  404. }
  405. static int proto_slam(struct slam_info *info)
  406. {
  407. int retry;
  408. long timeout;
  409. init_slam_state();
  410. state.buffer = info->buffer;
  411. retry = -1;
  412. rx_qdrain();
  413. /* Arp for my server */
  414. if (arptable[ARP_SERVER].ipaddr.s_addr != info->server.sin_addr.s_addr) {
  415. arptable[ARP_SERVER].ipaddr.s_addr = info->server.sin_addr.s_addr;
  416. memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);
  417. }
  418. /* If I'm running over multicast join the multicast group */
  419. join_group(IGMP_SERVER, info->multicast.sin_addr.s_addr);
  420. for(;;) {
  421. unsigned char *header;
  422. unsigned char *data;
  423. int type;
  424. header = data = 0;
  425. timeout = slam_sleep_interval(retry);
  426. type = await_reply(await_slam, 0, info, timeout);
  427. /* Compute the timeout for next time */
  428. if (type == SLAM_TIMEOUT) {
  429. /* If I timeouted recompute the next timeout */
  430. if (retry++ > SLAM_MAX_RETRIES) {
  431. return 0;
  432. }
  433. } else {
  434. retry = 0;
  435. }
  436. if ((type == SLAM_DATA) || (type == SLAM_REQUEST)) {
  437. /* Check the incomming packet and reinit the data
  438. * structures if necessary.
  439. */
  440. header = &nic.packet[ETH_HLEN +
  441. sizeof(struct iphdr) + sizeof(struct udphdr)];
  442. data = header + state.hdr_len;
  443. if (memcmp(state.hdr, header, state.hdr_len) != 0) {
  444. /* Something is fishy reset the transaction */
  445. data = reinit_slam_state(header, &nic.packet[nic.packetlen]);
  446. if (!data) {
  447. return 0;
  448. }
  449. }
  450. }
  451. if (type == SLAM_DATA) {
  452. if (!slam_recv_data(data)) {
  453. return 0;
  454. }
  455. if (state.received_packets == state.total_packets) {
  456. /* We are done get out */
  457. break;
  458. }
  459. }
  460. if ((type == SLAM_TIMEOUT) || (type == SLAM_REQUEST)) {
  461. /* Either I timed out or I was explicitly
  462. * asked by a request packet
  463. */
  464. slam_send_nack(info);
  465. }
  466. }
  467. slam_send_disconnect(info);
  468. /* Leave the multicast group */
  469. leave_group(IGMP_SERVER);
  470. /* FIXME don't overwrite myself */
  471. /* load file to correct location */
  472. return 1;
  473. }
  474. static int url_slam ( char *url __unused, struct sockaddr_in *server,
  475. char *file, struct buffer *buffer ) {
  476. struct slam_info info;
  477. /* Set the defaults */
  478. info.server = *server;
  479. info.multicast.sin_addr.s_addr = htonl(SLAM_MULTICAST_IP);
  480. info.multicast.sin_port = SLAM_MULTICAST_PORT;
  481. info.local.sin_addr.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
  482. info.local.sin_port = SLAM_LOCAL_PORT;
  483. info.buffer = buffer;
  484. info.sent_nack = 0;
  485. if (file[0]) {
  486. printf("\nBad url\n");
  487. return 0;
  488. }
  489. return proto_slam(&info);
  490. }
  491. struct protocol slam_protocol __protocol = {
  492. .name = "x-slam",
  493. .default_port = SLAM_PORT,
  494. .load = url_slam,
  495. };