]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/common/v2_0/tests/nc6_test_slave.c
Initial revision
[karo-tx-redboot.git] / packages / net / common / v2_0 / tests / nc6_test_slave.c
1 //==========================================================================
2 //
3 //      tests/nc6_test_slave.c
4 //
5 //      Network characterizations test (slave portion) IPv4+IPv6 aware
6 //
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 //
12 // Portions of this software may have been derived from OpenBSD or other sources,
13 // and are covered by the appropriate copyright disclaimers included herein.
14 //
15 // -------------------------------------------
16 //
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
20 //
21 // Author(s):    gthomas
22 // Contributors: gthomas
23 // Date:         2000-01-10
24 // Purpose:      
25 // Description:  
26 //              
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32 // Network characterization test code - slave portion
33
34 #include "nc_test_framework.h"
35 #include <math.h>
36
37 #ifdef __ECOS
38 #undef __linux
39 #ifndef CYGPKG_LIBC_STDIO
40 #define perror(s) diag_printf(#s ": %s\n", strerror(errno))
41 #endif
42 #define STACK_SIZE               (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
43 #define MAX_LOAD_THREAD_LEVEL    20
44 #define MIN_LOAD_THREAD_LEVEL    0
45 #define NUM_LOAD_THREADS         10
46 #define IDLE_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY+3
47 #define LOAD_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-1
48 #define MAIN_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-2
49 #define DESIRED_BACKGROUND_LOAD  20
50 static char         main_thread_stack[CYGHWR_NET_DRIVERS][STACK_SIZE];
51 static cyg_thread   main_thread_data[CYGHWR_NET_DRIVERS];
52 static cyg_handle_t main_thread_handle[CYGHWR_NET_DRIVERS];
53 static char         idle_thread_stack[STACK_SIZE];
54 static cyg_thread   idle_thread_data;
55 static cyg_handle_t idle_thread_handle;
56 static cyg_sem_t    idle_thread_sem;
57 volatile static long long    idle_thread_count;
58 static cyg_tick_count_t idle_thread_start_time;
59 static cyg_tick_count_t idle_thread_stop_time;
60 static char         load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE];
61 static cyg_thread   load_thread_data[NUM_LOAD_THREADS];
62 static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS];
63 static cyg_sem_t    load_thread_sem[NUM_LOAD_THREADS];
64 static long         load_thread_level;
65 static void calibrate_load(int load);
66 static void start_load(int load);
67 static void do_some_random_computation(int p);
68 #define abs(n) ((n) < 0 ? -(n) : (n))
69 #endif
70
71 #ifdef __ECOS
72 #define test_param_t cyg_addrword_t
73 #ifdef CYGDBG_NET_TIMING_STATS
74 extern void show_net_times(void);
75 #endif
76 extern void cyg_kmem_print_stats(void);
77 #else
78 #define test_param_t int
79 #endif
80
81 #ifdef __ECOS
82 #ifdef CYGPKG_NET_INET6
83 #define __INET6
84 #endif
85 #else
86 #define __INET6
87 #endif
88
89 #define MAX_BUF 8192
90 static unsigned char in_buf[MAX_BUF], out_buf[MAX_BUF];
91
92 #ifdef __ECOS
93 extern void
94 cyg_test_exit(void);
95 #else
96 void
97 cyg_test_exit(void)
98 {
99     test_printf("... Done\n");
100     exit(1);
101 }
102
103 static void
104 show_net_times(void)
105 {
106 }
107 #endif
108
109 #ifdef __ECOS
110 static void
111 test_delay(int ticks)
112 {
113     cyg_thread_delay(ticks);
114 }
115
116 #else
117
118 static void
119 test_delay(int ticks)
120 {
121     usleep(ticks * 10000);
122 }
123 #endif
124
125 void
126 pexit(char *s)
127 {
128     perror(s);
129 #ifdef CYGDBG_NET_TIMING_STATS
130     show_net_times();
131 #endif
132 #ifdef __ECOS
133     cyg_kmem_print_stats();
134 #endif
135     cyg_test_exit();
136 }
137
138 static int
139 sa_len(struct sockaddr *sa)
140 {
141     switch (sa->sa_family) {
142     case AF_INET:
143         return sizeof(struct sockaddr_in);
144 #ifdef __INET6
145     case AF_INET6:
146         return sizeof(struct sockaddr_in6);
147 #endif
148     default:
149         test_printf("Unknown socket type: %d\n", sa->sa_family);
150         return sizeof(struct sockaddr_storage);
151     }
152 }
153
154 //
155 // Generic UDP test
156 //
157
158 static void
159 do_udp_test(int s1, struct nc_request *req, struct sockaddr *master)
160 {
161     int i, s, td_len, seq, seq_errors, lost;
162     struct sockaddr_storage test_chan_slave, test_chan_master;
163     fd_set fds;
164     struct timeval timeout;
165     struct nc_test_results results;
166     struct nc_test_data *tdp;
167     int nsent, nrecvd;
168     int need_recv, need_send;
169
170     need_recv = true;  need_send = true;
171     switch (ntohl(req->type)) {
172     case NC_REQUEST_UDP_SEND:
173         need_recv = false;
174         need_send = true;
175         break;
176     case NC_REQUEST_UDP_RECV:
177         need_recv = true;
178         need_send = false;
179         break;
180     case NC_REQUEST_UDP_ECHO:
181         break;
182     }
183
184     s = socket(master->sa_family, SOCK_DGRAM, 0);
185     if (s < 0) {
186         pexit("datagram socket");
187     }
188
189     memset((char *)&test_chan_slave, 0, sizeof(test_chan_slave));
190     memcpy(&test_chan_master, master, sizeof(*master));
191 #ifndef __linux
192     ((struct sockaddr *)&test_chan_slave)->sa_len = master->sa_len;
193 #endif
194     ((struct sockaddr *)&test_chan_slave)->sa_family = master->sa_family;
195     switch (master->sa_family) {
196     case AF_INET:
197         ((struct sockaddr_in *)&test_chan_slave)->sin_addr.s_addr = htonl(INADDR_ANY);
198         ((struct sockaddr_in *)&test_chan_slave)->sin_port = htons(ntohl(req->slave_port));
199         ((struct sockaddr_in *)&test_chan_master)->sin_port = htons(ntohl(req->master_port));
200         break;
201 #ifdef __INET6
202     case AF_INET6:
203         ((struct sockaddr_in6 *)&test_chan_slave)->sin6_addr = in6addr_any;
204         ((struct sockaddr_in6 *)&test_chan_slave)->sin6_port = htons(ntohl(req->slave_port));
205         ((struct sockaddr_in6 *)&test_chan_master)->sin6_port = htons(ntohl(req->master_port));
206         break;
207 #endif
208     default:
209         pexit("strange UDP sockaddr");
210     }
211     
212     if (bind(s, (struct sockaddr *) &test_chan_slave, 
213              sa_len((struct sockaddr *)&test_chan_slave)) < 0) {
214         perror("bind UDP slave");
215         close(s);
216     }
217
218     nsent = 0;  nrecvd = 0;  seq = 0;  seq_errors = 0;  lost = 0;
219     for (i = 0;  i < ntohl(req->nbufs);  i++) {
220         if (need_recv) {
221             FD_ZERO(&fds);
222             FD_SET(s, &fds);
223             timeout.tv_sec = NC_TEST_TIMEOUT;
224             timeout.tv_usec = 0;
225             if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
226                 test_printf("recvfrom timeout, expecting seq #%d\n", seq);            
227                 if (++lost > MAX_ERRORS) {
228                     test_printf("... giving up\n");
229                     break;
230                 }
231             } else {
232                 nrecvd++;
233                 tdp = (struct nc_test_data *)in_buf;
234                 td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
235                 if (recvfrom(s, tdp, td_len, 0, 0, 0) < 0) {
236                     perror("recvfrom UDP data");
237                     close(s);
238                     return;
239                 }
240                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
241                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
242                     if (ntohl(tdp->seq) != seq) {
243                         test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
244                                     ntohl(tdp->seq), seq);
245                         seq = ntohl(tdp->seq);
246                         seq_errors++;
247                     }
248                 } else {
249                     test_printf("Bad data packet - key: %x/%x, seq: %d\n",
250                                 ntohl(tdp->key1), ntohl(tdp->key2),
251                                 ntohl(tdp->seq));
252                 }
253             }
254         }
255         if (need_send) {
256             tdp = (struct nc_test_data *)out_buf;
257             tdp->key1 = htonl(NC_TEST_DATA_KEY1);
258             tdp->key2 = htonl(NC_TEST_DATA_KEY2);
259             tdp->seq = htonl(seq);
260             td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
261             tdp->len = htonl(td_len);
262             if (sendto(s, tdp, td_len, 0, 
263                        (struct sockaddr *)&test_chan_master, sa_len(master)) < 0) {
264                 perror("sendto UDP data");
265                 if (errno == ENOBUFS) {
266                     // Saturated the system
267                     test_delay(10);   // Time for 200 500 byte 10-baseT packets 
268                 } else {
269                     // What else to do?
270                     close(s);
271                     return;
272                 }
273             } else {
274                 nsent++;
275             }
276         }
277         seq++;
278     }
279     results.key1 = htonl(NC_TEST_RESULT_KEY1);
280     results.key2 = htonl(NC_TEST_RESULT_KEY2);
281     results.seq = req->seq;
282     results.nsent = htonl(nsent);
283     results.nrecvd = htonl(nrecvd);
284     if (sendto(s, &results, sizeof(results), 0, 
285                (struct sockaddr *)&test_chan_master, sa_len(master)) < 0) {
286         perror("sendto UDP results");
287     }
288     close(s);
289 }
290
291 //
292 // Read data from a stream, accounting for the fact that packet 'boundaries'
293 // are not preserved.  This can also timeout (which would probably wreck the
294 // data boundaries).
295 //
296
297 int
298 do_read(int fd, void *buf, int buflen)
299 {
300     char *p = (char *)buf;
301     int len = buflen;
302     int res;
303     while (len) {
304         res = read(fd, p, len);
305         if (res < 0) {
306             perror("read");
307         } else {
308             len -= res;
309             p += res;
310             if (res == 0) {
311                 break;
312             }
313         }
314     }
315     return (buflen - len);
316 }
317
318 //
319 // Generic TCP test
320 //
321
322 static void
323 do_tcp_test(int s1, struct nc_request *req, struct sockaddr *master)
324 {
325     int i, s, len, td_len, seq, seq_errors, lost, test_chan, res;
326     struct sockaddr_storage test_chan_slave, test_chan_master;
327     struct nc_test_results results;
328     struct nc_test_data *tdp;
329     int nsent, nrecvd;
330     int need_recv, need_send;
331     int one = 1;
332     char addr_buf[256];
333     static int slave_tcp_port[2] = {-1, -1};
334     int which_port = 0;
335
336     need_recv = true;  need_send = true;
337     switch (ntohl(req->type)) {
338     case NC_REQUEST_TCP_SEND:
339         need_recv = false;
340         need_send = true;
341         break;
342     case NC_REQUEST_TCP_RECV:
343         need_recv = true;
344         need_send = false;
345         break;
346     case NC_REQUEST_TCP_ECHO:
347         break;
348     }
349
350     switch (master->sa_family) {
351     case AF_INET:
352         which_port = 0;
353         break;
354 #ifdef __INET6
355     case AF_INET6:
356         which_port = 1;
357         break;
358 #endif
359     default:
360         pexit("unknown TCP family");
361     }
362     if (slave_tcp_port[which_port] < 0) {
363         test_printf("TCP - listen on %s/%d\n", which_port ? "IPv6" : "IPv4",
364                     ntohl(req->slave_port));
365         s = socket(master->sa_family, SOCK_STREAM, 0);
366         if (s < 0) {
367             pexit("datagram socket");
368         }
369
370         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
371             perror("setsockopt SO_REUSEADDR");
372             return;
373         }
374 #ifdef SO_REUSEPORT
375         if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
376             perror("setsockopt SO_REUSEPORT");
377             return;
378         }
379 #endif
380         memset((char *)&test_chan_slave, 0, sizeof(test_chan_slave));
381 #ifndef __linux
382         ((struct sockaddr *)&test_chan_slave)->sa_len = master->sa_len;
383 #endif
384         ((struct sockaddr *)&test_chan_slave)->sa_family = master->sa_family;
385         switch (master->sa_family) {
386         case AF_INET:
387             ((struct sockaddr_in *)&test_chan_slave)->sin_addr.s_addr = htonl(INADDR_ANY);
388             ((struct sockaddr_in *)&test_chan_slave)->sin_port = htons(ntohl(req->slave_port));
389             break;
390 #ifdef __INET6
391         case AF_INET6:
392             ((struct sockaddr_in6 *)&test_chan_slave)->sin6_addr = in6addr_any;
393             ((struct sockaddr_in6 *)&test_chan_slave)->sin6_port = htons(ntohl(req->slave_port));
394             break;
395 #endif
396         default:
397             pexit("strange TCP sockaddr");
398         }
399     
400         if (bind(s, (struct sockaddr *)&test_chan_slave, sa_len(master)) < 0) {
401             perror("bind");
402             close(s);
403         }
404         listen(s, SOMAXCONN);
405         slave_tcp_port[which_port] = s;
406     }
407
408     s = slave_tcp_port[which_port];
409     len = sizeof(test_chan_master);
410     if ((test_chan = accept(s, (struct sockaddr *)&test_chan_master, &len)) < 0) {
411         pexit("accept");
412     }
413     len = sizeof(test_chan_master);
414     getpeername(test_chan, (struct sockaddr *)&test_chan_master, &len);
415 #ifdef __ECOS
416     _inet_ntop((struct sockaddr *)&test_chan_master, addr_buf, sizeof(addr_buf));
417     test_printf("connection from %s(%d)\n", addr_buf, 
418                 _inet_port((struct sockaddr *)&test_chan_master));
419 #endif
420
421     nsent = 0;  nrecvd = 0;  seq = 0;  seq_errors = 0;  lost = 0;
422     for (i = 0;  i < ntohl(req->nbufs);  i++) {
423         if (need_recv) {
424             tdp = (struct nc_test_data *)in_buf;
425             td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
426             res = do_read(test_chan, tdp, td_len);
427             if (res != td_len) {
428                 test_printf("recvfrom timeout, expecting seq #%d\n", seq);            
429                 if (++lost > MAX_ERRORS) {
430                     test_printf("... giving up\n");
431                     break;
432                 }
433             } else {
434                 nrecvd++;
435                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
436                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
437                     if (ntohl(tdp->seq) != seq) {
438                         test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
439                                     ntohl(tdp->seq), seq);
440                         seq = ntohl(tdp->seq);
441                         seq_errors++;
442                     }
443                 } else {
444                     test_printf("Bad data packet - key: %x/%x, seq: %d\n",
445                                 ntohl(tdp->key1), ntohl(tdp->key2),
446                                 ntohl(tdp->seq));
447                 }
448             }
449         }
450         if (need_send) {
451             tdp = (struct nc_test_data *)out_buf;
452             tdp->key1 = htonl(NC_TEST_DATA_KEY1);
453             tdp->key2 = htonl(NC_TEST_DATA_KEY2);
454             tdp->seq = htonl(seq);
455             td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
456             tdp->len = htonl(td_len);
457             if (write(test_chan, tdp, td_len) != td_len) {
458                 perror("write");
459                 if (errno == ENOBUFS) {
460                     // Saturated the system
461                     test_delay(25);
462                 } else {
463                     // What else to do?
464                     close(test_chan);
465                     return;
466                 }
467             } else {
468                 nsent++;
469             }
470         }
471         seq++;
472     }
473     results.key1 = htonl(NC_TEST_RESULT_KEY1);
474     results.key2 = htonl(NC_TEST_RESULT_KEY2);
475     results.seq = req->seq;
476     results.nsent = htonl(nsent);
477     results.nrecvd = htonl(nrecvd);
478     if (write(test_chan, &results, sizeof(results)) != sizeof(results)) {
479         perror("write");
480     }
481     close(test_chan);
482 }
483
484 #define MAXSOCK 16  // Max # sockets to listen on
485
486 static int
487 waitfor(int *socks, int len, int last_sock)
488 {
489     fd_set src_fds;
490     int i, s, num;
491
492     // Wait for some activity on one of the ports
493     FD_ZERO(&src_fds);
494     for (s = 0;  s < len;  s++) {
495         FD_SET(socks[s], &src_fds);
496     }
497     num = select(last_sock+1, &src_fds, 0, 0, 0);
498     if (num > 0) {
499         for (i = 0;  i < len; i++) {
500             s = socks[i];
501             if (FD_ISSET(s, &src_fds)) {
502                 return s;  // Return first available socket
503             }
504         }
505         pexit("select, but no socket!");
506     } else {
507         pexit("select");
508     }
509     return 0;
510 }
511
512 //
513 // Protocol driver for testing slave.
514 //
515 // This function is the main routine running here, handling requests sent from
516 // the master and providing various responses.
517 //
518 static void
519 nc_slave(test_param_t param)
520 {
521     int sock_indx, s, err, last_sock, socks[MAXSOCK], masterlen;
522     struct sockaddr_storage master;
523     struct nc_request req;
524     struct nc_reply reply;
525     int done = false;
526     struct addrinfo *ai, *addrs, hints;
527     char addr_buf[256];
528
529     test_printf("Start test for eth%d\n", param);
530     bzero(&hints, sizeof(hints));
531     hints.ai_family = PF_UNSPEC;
532     hints.ai_socktype = SOCK_DGRAM;
533     hints.ai_flags = AI_PASSIVE;
534     if ((err = getaddrinfo(NULL, _string(NC_SLAVE_PORT), &hints, &addrs)) != EAI_NONE) {
535         test_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
536         pexit("getaddrinfo");
537     }
538     // Prepare a socket for each connection type
539     sock_indx = 0;  last_sock = -1;
540     ai = addrs;
541     while (ai) {
542 #ifdef __ECOS
543         _inet_ntop(ai->ai_addr, addr_buf, sizeof(addr_buf));
544         test_printf("Family: %d, Socket: %d, Addr: %s\n", ai->ai_family, ai->ai_socktype, addr_buf);
545 #else
546         test_printf("Family: %d, Socket: %d\n", ai->ai_family, ai->ai_socktype);
547 #endif
548 #ifdef __linux
549 // This code is very sensitive on Linux
550         s = socket(ai->ai_family, ai->ai_socktype, 0);
551         if (s < 0) {
552             test_printf("Can't bind socket\n");
553 //            pexit("dgram socket");
554         } else {
555             if(bind(s, ai->ai_addr, sa_len(ai->ai_addr)) < 0) {
556                 test_printf("Failed to bind family: %d\n", ai->ai_family);
557 //            pexit("bind server error");
558             } else {
559                 socks[sock_indx++] = s;
560                 if (sock_indx >= MAXSOCK) {
561                     pexit("Too many address types");
562                 }
563             }
564         }
565 #else
566         s = socket(ai->ai_family, ai->ai_socktype, 0);
567         if (s < 0) {
568             pexit("dgram socket");
569         }
570         if(bind(s, ai->ai_addr, sa_len(ai->ai_addr)) < 0) {
571             test_printf("Failed to bind family: %d\n", ai->ai_family);
572             pexit("bind server error");
573         }
574         socks[sock_indx++] = s;
575         if (sock_indx >= MAXSOCK) {
576             pexit("Too many address types");
577         }
578 #endif
579         ai = ai->ai_next;
580         if (s > last_sock) last_sock = s;
581     }
582     while (!done && (s = waitfor(socks, sock_indx, last_sock))) {
583         // Data is available from socket 's'
584         masterlen = sizeof(master);
585         if (recvfrom(s, &req, sizeof(req), 0, (struct sockaddr *)&master, &masterlen) < 0) {
586             pexit("recvfrom service");
587         }
588 #if 0
589         _inet_ntop((struct sockaddr *)&master, addr_buf, sizeof(addr_buf));
590         test_printf("Request %d %s(%d)\n", ntohl(req.type), addr_buf, 
591                     (struct sockaddr *)_inet_port(&master));
592 #endif
593         reply.response = htonl(NC_REPLY_ACK);
594         reply.seq = req.seq;
595         switch (ntohl(req.type)) {
596         case NC_REQUEST_DISCONNECT:
597             done = true;
598             test_printf("Master has issued disconnect - I quit!\n");
599             break;
600         case NC_REQUEST_UDP_SEND:
601             test_printf("UDP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
602             break;
603         case NC_REQUEST_UDP_RECV:
604             test_printf("UDP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
605             break;
606         case NC_REQUEST_UDP_ECHO:
607             test_printf("UDP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
608             break;
609         case NC_REQUEST_TCP_SEND:
610             test_printf("TCP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
611             break;
612         case NC_REQUEST_TCP_RECV:
613             test_printf("TCP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
614             break;
615         case NC_REQUEST_TCP_ECHO:
616             test_printf("TCP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
617             break;
618 #ifdef __ECOS
619         case NC_REQUEST_SET_LOAD:
620             start_load(ntohl(req.nbufs));
621             break;
622         case NC_REQUEST_START_IDLE:
623             test_printf("Start IDLE thread\n");
624             idle_thread_count = 0;
625             idle_thread_start_time = cyg_current_time();
626             cyg_semaphore_post(&idle_thread_sem);
627             break;
628         case NC_REQUEST_STOP_IDLE:
629             cyg_semaphore_wait(&idle_thread_sem);
630             idle_thread_stop_time = cyg_current_time();
631             test_printf("Stop IDLE thread\n");
632             reply.misc.idle_results.elapsed_time = htonl(idle_thread_stop_time - idle_thread_start_time);
633             reply.misc.idle_results.count[0] = htonl(idle_thread_count >> 32);
634             reply.misc.idle_results.count[1] = htonl((long)idle_thread_count);
635             break;
636 #endif
637         default:
638             test_printf("Unrecognized request: %d\n", ntohl(req.type));
639             reply.response = htonl(NC_REPLY_NAK);
640             reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST);
641             break;
642         }
643         if (sendto(s, &reply, sizeof(reply), 0, (struct sockaddr *)&master, masterlen) < 0) {
644             pexit("sendto");
645         }
646         if (reply.response == ntohl(NC_REPLY_NAK)) {
647             continue;
648         }
649         switch (ntohl(req.type)) {
650         case NC_REQUEST_UDP_SEND:
651         case NC_REQUEST_UDP_RECV:
652         case NC_REQUEST_UDP_ECHO:
653             do_udp_test(s, &req, (struct sockaddr *)&master);
654             break;
655         case NC_REQUEST_TCP_SEND:
656         case NC_REQUEST_TCP_RECV:
657         case NC_REQUEST_TCP_ECHO:
658             do_tcp_test(s, &req, (struct sockaddr *)&master);
659             break;
660         case NC_REQUEST_START_IDLE:
661         case NC_REQUEST_STOP_IDLE:
662         case NC_REQUEST_SET_LOAD:
663         default:
664             break;
665         }
666 //        cyg_kmem_print_stats();
667     }
668 }
669
670 void
671 net_test(test_param_t param)
672 {
673 //    int i;
674     if (param == 0) {
675         test_printf("Start Network Characterization - SLAVE\n");
676 #ifdef __ECOS
677         init_all_network_interfaces();
678         calibrate_load(DESIRED_BACKGROUND_LOAD);
679 #if 0
680 // I can see what this is trying to do, but I get "bind: Address already in
681 // use" errors from the 2nd interface - and the parameter is not used
682 // anyway, so one thread does quite well enough (but only tests one i/f at
683 // once).
684
685 // Comment in the 'int i' above too.
686         for (i = 1;  i < CYGHWR_NET_DRIVERS;  i++) {
687             cyg_thread_resume(main_thread_handle[i]);   // Start other threads
688         }
689 #endif
690 #endif
691     }
692     nc_slave(param);
693 #ifdef CYGDBG_NET_TIMING_STATS
694     show_net_times();
695 #endif
696     cyg_test_exit();
697 }
698
699 #ifdef __ECOS
700
701 //
702 // This function is called to calibrate the "background load" which can be
703 // applied during testing.  It will be called before any commands from the
704 // host are managed.
705 //
706 static void
707 calibrate_load(int desired_load)
708 {
709     long long no_load_idle, load_idle;
710     int percent_load;
711     int high, low;
712
713     // Set limits
714     high = MAX_LOAD_THREAD_LEVEL;
715     low = MIN_LOAD_THREAD_LEVEL;
716
717     // Compute the "no load" idle value
718     idle_thread_count = 0;
719     cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
720     cyg_thread_delay(1*100);               // Pause for one second
721     cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
722     no_load_idle = idle_thread_count;
723     diag_printf("No load = %d\n", (int)idle_thread_count);
724
725     // First ensure that the HIGH level is indeed higher
726     while (true) {
727         load_thread_level = high;
728         start_load(desired_load);              // Start up a given load
729         idle_thread_count = 0;
730         cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
731         cyg_thread_delay(1*100);               // Pause for one second
732         cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
733         load_idle = idle_thread_count;
734         start_load(0);                         // Shut down background load
735         percent_load = 100 - ((load_idle * 100) / no_load_idle);
736         diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level, 
737                     (int)idle_thread_count, percent_load);
738         if ( percent_load > desired_load )
739             break; // HIGH level is indeed higher
740         low = load_thread_level; // known to be lower
741         high *= 2; // else double it and try again
742     }
743
744     // Now chop down to the level required
745     while (true) {
746         load_thread_level = (high + low) / 2;
747         start_load(desired_load);              // Start up a given load
748         idle_thread_count = 0;
749         cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
750         cyg_thread_delay(1*100);               // Pause for one second
751         cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
752         load_idle = idle_thread_count;
753         start_load(0);                         // Shut down background load
754         percent_load = 100 - ((load_idle * 100) / no_load_idle);
755         diag_printf("Load[%d] = %d => %d%%\n", load_thread_level, 
756                     (int)idle_thread_count, percent_load);
757         if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break;
758         if (percent_load < desired_load) {
759             low = load_thread_level;
760         } else {            
761             high = load_thread_level;
762         }
763     }
764
765     // Now we are within a few percent of the target; scale the load
766     // factor to get a better fit, and test it, print the answer.
767     load_thread_level *= desired_load;
768     load_thread_level /= percent_load;
769     start_load(desired_load);              // Start up a given load
770     idle_thread_count = 0;
771     cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
772     cyg_thread_delay(1*100);               // Pause for one second
773     cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
774     load_idle = idle_thread_count;
775     start_load(0);                         // Shut down background load
776     percent_load = 100 - ((load_idle * 100) / no_load_idle);
777     diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, 
778                 (int)idle_thread_count, percent_load);
779 //    no_load_idle_count_1_second = no_load_idle;
780 }
781
782 //
783 // This function is called to set up a load level of 'load' percent (given
784 // as a whole number, e.g. start_load(20) would mean initiate a background
785 // load of 20%, leaving the cpu 80% idle).
786 //
787 static void
788 start_load(int load)
789 {
790     static int prev_load = 0;
791     int i;
792     test_printf("Set background load = %d%%\n", load);
793     if (load == 0) {
794         if (prev_load == 0) return;  // Nothing out there to stop
795         for (i = 0;  i < prev_load/10;  i++) {
796             cyg_semaphore_wait(&load_thread_sem[i]);
797         }
798         prev_load = 0;
799     } else {
800         for (i = 0;  i < load/10;  i++) {
801             cyg_semaphore_post(&load_thread_sem[i]);
802         }
803         prev_load = load;
804     }
805 }
806
807 //
808 // These thread(s) do some amount of "background" computing.  This is used
809 // to simulate a given load level.  They need to be run at a higher priority 
810 // than the network code itself.
811 //
812 // Like the "idle" thread, they run as long as their "switch" (aka semaphore)
813 // is enabled.
814 //
815 void
816 net_load(cyg_addrword_t who)
817 {
818     int i;
819     while (true) {
820         cyg_semaphore_wait(&load_thread_sem[who]);
821         for (i = 0;  i < load_thread_level;  i++) {
822             do_some_random_computation(i);
823         }
824         cyg_thread_delay(1);  // Wait until the next 'tick'
825         cyg_semaphore_post(&load_thread_sem[who]);
826     }
827 }
828
829 //
830 // Some arbitrary computation, designed to use up the CPU and cause associated
831 // cache "thrash" behaviour - part of background load modelling.
832 //
833 static void
834 do_some_random_computation(int p)
835 {
836     // Just something that might be "hard"
837     volatile double x;
838     x = ((p * 10) * 3.14159) / 180.0;  // radians
839 }
840
841 //
842 // This thread does nothing but count.  It will be allowed to count
843 // as long as the semaphore is "free".  
844 //
845 void
846 net_idle(cyg_addrword_t param)
847 {
848     while (true) {
849         cyg_semaphore_wait(&idle_thread_sem);
850         idle_thread_count++;
851         cyg_semaphore_post(&idle_thread_sem);
852     }
853 }
854
855 void
856 cyg_start(void)
857 {
858     int i;
859     // Create processing threads
860     for (i = 0;  i < CYGHWR_NET_DRIVERS;  i++) {
861         cyg_thread_create(MAIN_THREAD_PRIORITY,     // Priority
862                           net_test,                 // entry
863                           i,                        // entry parameter
864                           "Network test",           // Name
865                           &main_thread_stack[i][0], // Stack
866                           STACK_SIZE,               // Size
867                           &main_thread_handle[i],   // Handle
868                           &main_thread_data[i]      // Thread data structure
869             );
870     }
871     cyg_thread_resume(main_thread_handle[0]);   // Start first one
872     // Create the idle thread environment
873     cyg_semaphore_init(&idle_thread_sem, 0);
874     cyg_thread_create(IDLE_THREAD_PRIORITY,     // Priority
875                       net_idle,                 // entry
876                       0,                        // entry parameter
877                       "Network idle",           // Name
878                       &idle_thread_stack[0],    // Stack
879                       STACK_SIZE,               // Size
880                       &idle_thread_handle,      // Handle
881                       &idle_thread_data         // Thread data structure
882             );
883     cyg_thread_resume(idle_thread_handle);      // Start it
884     // Create the load threads and their environment(s)
885     for (i = 0;  i < NUM_LOAD_THREADS;  i++) {
886         cyg_semaphore_init(&load_thread_sem[i], 0);
887         cyg_thread_create(LOAD_THREAD_PRIORITY,     // Priority
888                           net_load,                 // entry
889                           i,                        // entry parameter
890                           "Background load",        // Name
891                           &load_thread_stack[i][0], // Stack
892                           STACK_SIZE,               // Size
893                           &load_thread_handle[i],   // Handle
894                           &load_thread_data[i]      // Thread data structure
895             );
896         cyg_thread_resume(load_thread_handle[i]);   // Start it
897     }
898     cyg_scheduler_start();
899 }
900
901 #else
902
903 int 
904 main(int argc, char *argv[])
905 {
906     net_test(0);
907 }
908 #endif