]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/common/v2_0/tests/nc6_test_master.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / common / v2_0 / tests / nc6_test_master.c
1 //==========================================================================
2 //
3 //      tests/nc6_test_master.c
4 //
5 //      Network characterizations test (master 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 - master portion
33
34 #include "nc_test_framework.h"
35
36 #ifdef __ECOS
37 #ifndef CYGPKG_LIBC_STDIO
38 #define perror(s) diag_printf(#s ": %s\n", strerror(errno))
39 #endif
40 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
41 static char stack[STACK_SIZE];
42 static cyg_thread thread_data;
43 static cyg_handle_t thread_handle;
44 #endif
45
46 struct test_params {
47     int  argc;
48     char **argv;
49 };
50
51 #define MAX_BUF 32*1024
52 static unsigned char in_buf[MAX_BUF], out_buf[MAX_BUF];
53
54 static int test_seq = 1;
55 static long long idle_count;
56 static long      idle_ticks;
57 #define IDLE_TEST_TIME   10
58
59 struct pause {
60     int pause_ticks;
61     int pause_threshold;
62 };
63 #define LENGTH(x) (sizeof(x)/sizeof(x[0]))
64
65 #ifdef __ECOS
66 extern void
67 cyg_test_exit(void);
68 #else
69 void
70 cyg_test_exit(void)
71 {
72     test_printf("... Done\n");
73     exit(1);
74 }
75 #endif
76
77 #ifdef __ECOS
78 static void
79 test_delay(int ticks)
80 {
81     cyg_thread_delay(ticks);
82 }
83
84 #else
85
86 static void
87 test_delay(int ticks)
88 {
89     usleep(ticks * 10000);
90 }
91 #endif
92
93 void
94 pexit(char *s)
95 {
96     perror(s);
97     cyg_test_exit();
98 }
99
100 #ifdef __ECOS
101 # ifdef CYGPKG_POSIX
102 # #include <pkgconf/posix.h>
103 # endif
104 # ifndef CYGPKG_POSIX_TIMERS
105 int
106 gettimeofday(struct timeval *tv, struct timezone *tz)
107 {
108     cyg_tick_count_t cur_time;
109     cur_time = cyg_current_time();
110     tv->tv_sec = cur_time / 100;
111     tv->tv_usec = (cur_time % 100) * 10000;
112 }
113 # endif
114 #endif
115
116 void
117 show_results(const char *msg, struct timeval *start, 
118              struct timeval *end, int nbufs, int buflen,
119              int lost, int seq_errors)
120 {
121     struct timeval tot_time;
122 #ifndef __ECOS
123     double real_time, thru;
124     long tot_bytes = nbufs * buflen;
125 #endif
126     timersub(end, start, &tot_time);
127     test_printf("%s - %d bufs of %d bytes in %d.%02d seconds",
128                 msg, nbufs, buflen, 
129                 tot_time.tv_sec, tot_time.tv_usec / 10000);
130 #ifndef __ECOS
131     real_time = tot_time.tv_sec + ((tot_time.tv_usec / 10000) * .01);
132     // Compute bytes / second (rounded up)
133     thru = tot_bytes / real_time;
134     // Convert to Mb / second
135     test_printf(" - %.2f KB/S", thru / 1024.0);
136     test_printf(" - %.4f Mbit/S (M = 10^6)", thru * 8.0 / 1000000.0);
137 #endif
138     if (lost) {
139         test_printf(", %d lost", lost);
140     }
141     if (seq_errors) {
142         test_printf(", %d out of sequence", seq_errors);
143     }
144     test_printf("\n");
145 }
146
147 void
148 new_test(void)
149 {
150     test_seq++;
151 }
152
153 static int
154 sa_len(struct sockaddr *sa)
155 {
156     switch (sa->sa_family) {
157     case AF_INET:
158         return sizeof(struct sockaddr_in);
159     case AF_INET6:
160         return sizeof(struct sockaddr_in6);
161     default:
162         printf("Unknown socket type: %d\n", sa->sa_family);
163         return sizeof(struct sockaddr_storage);
164     }
165 }
166
167 int
168 nc_message(int s, struct nc_request *req, 
169            struct nc_reply *reply, struct sockaddr *slave)
170 {
171     fd_set fds;
172     struct timeval timeout;
173
174     req->seq = htonl(test_seq);
175     if (sendto(s, req, sizeof(*req), 0, slave, sa_len(slave)) < 0) {
176         perror("sendto");
177         return false;
178     }
179     FD_ZERO(&fds);
180     FD_SET(s, &fds);
181     timeout.tv_sec = NC_REPLY_TIMEOUT;
182     timeout.tv_usec = 0;
183     if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
184         test_printf("No response to command\n");
185         return false;
186     }
187     if (recvfrom(s, reply, sizeof(*reply), 0, 0, 0) < 0) {
188         perror("recvfrom");
189         return false;
190     }
191     if (reply->seq != req->seq) {
192         test_printf("Response out of order - sent: %d, recvd: %d\n",
193                     ntohl(req->seq), ntohl(reply->seq));
194         return false;
195     }
196     return true;
197 }
198
199 void
200 show_test_results(struct nc_test_results *results)
201 {
202     if ((ntohl(results->key1) == NC_TEST_RESULT_KEY1) &&
203         (ntohl(results->key2) == NC_TEST_RESULT_KEY2) &&
204         (ntohl(results->seq) == test_seq)) {
205         test_printf("   slave sent %d, recvd %d\n", 
206                     ntohl(results->nsent), ntohl(results->nrecvd));
207     } else {
208         test_printf("   ... invalid results - keys: %x/%x, seq: %d/%d\n",
209                     ntohl(results->key1), ntohl(results->key2),
210                     ntohl(results->seq), test_seq);
211     }
212 }
213
214 void
215 do_udp_test(int s1, int type, struct sockaddr *slave,
216             int nbufs, int buflen, int pause_time, int pause_threshold)
217 {
218     int i, s, td_len, seq, seq_errors, total_packets;
219     struct sockaddr_storage test_chan_master, test_chan_slave;
220     struct timeval start_time, end_time;
221     struct nc_request req;
222     struct nc_reply reply;
223     struct nc_test_results results;
224     struct nc_test_data *tdp;
225     fd_set fds;
226     struct timeval timeout;
227     int lost_packets = 0;
228     int need_send, need_recv;
229     const char *type_name;
230     int pkt_ctr = 0;
231
232     need_recv = true;  need_send = true;  type_name = "UDP echo";
233     switch (type) {
234     case NC_REQUEST_UDP_RECV:
235         need_recv = false;
236         need_send = true;
237         type_name = "UDP recv";
238         break;
239     case NC_REQUEST_UDP_SEND:
240         need_recv = true;
241         need_send = false;
242         type_name = "UDP send";
243         break;
244     case NC_REQUEST_UDP_ECHO:
245         break;
246     }
247
248     new_test();
249     req.type = htonl(type);
250     req.nbufs = htonl(nbufs);
251     req.buflen = htonl(buflen);
252     req.slave_port = htonl(NC_TESTING_SLAVE_PORT);
253     req.master_port = htonl(NC_TESTING_MASTER_PORT);
254     nc_message(s1, &req, &reply, slave);
255     if (reply.response != ntohl(NC_REPLY_ACK)) {
256         test_printf("Slave denied %s [%d,%d] test\n", type_name, nbufs, buflen);
257         return;
258     }
259
260     s = socket(slave->sa_family, SOCK_DGRAM, 0);
261     if (s < 0) {
262         pexit("datagram socket");
263     }
264
265     memset(&test_chan_master, 0, sizeof(test_chan_master));
266     ((struct sockaddr *)&test_chan_master)->sa_family = slave->sa_family;
267     memcpy(&test_chan_slave, slave, sa_len(slave));
268 #ifndef __linux
269     ((struct sockaddr *)&test_chan_master)->sa_len = slave->sa_len;
270 #endif
271     switch (slave->sa_family) {
272     case AF_INET:
273         ((struct sockaddr_in *)&test_chan_master)->sin_addr.s_addr = htonl(INADDR_ANY);
274         ((struct sockaddr_in *)&test_chan_master)->sin_port = htons(ntohl(req.master_port));
275         ((struct sockaddr_in *)&test_chan_slave)->sin_port = htons(ntohl(req.slave_port));
276         break;
277     case AF_INET6:
278         ((struct sockaddr_in6 *)&test_chan_master)->sin6_addr = in6addr_any;
279         ((struct sockaddr_in6 *)&test_chan_master)->sin6_port = htons(ntohl(req.master_port));
280         ((struct sockaddr_in6 *)&test_chan_slave)->sin6_port = htons(ntohl(req.slave_port));
281         break;
282     default:
283         pexit("strange TCP sockaddr");
284     }
285
286     if (bind(s, (struct sockaddr *)&test_chan_master, 
287              sa_len((struct sockaddr *)&test_chan_master)) < 0) {
288         perror("UDP bind <do_udp_test>");
289         close(s);
290         return;
291     }
292     test_printf("Start %s [%d,%d]", type_name, nbufs, buflen);
293     if (pause_time) {
294         test_printf(" - %dms delay after %d packet%s\n", pause_time*10, 
295                     pause_threshold, pause_threshold > 1 ? "s" : "");
296     } else {
297         test_printf(" - no delays\n");
298     }
299
300     gettimeofday(&start_time, 0);
301     seq = 0;  seq_errors = 0;  total_packets = 0;
302     for (i = 0;  i < nbufs;  i++) {
303         td_len = buflen + sizeof(struct nc_test_data);
304         if (need_send) {
305             tdp = (struct nc_test_data *)out_buf;
306             tdp->key1 = htonl(NC_TEST_DATA_KEY1);
307             tdp->key2 = htonl(NC_TEST_DATA_KEY2);
308             tdp->seq = htonl(i);
309             tdp->len = htonl(td_len);
310             if (sendto(s, tdp, td_len, 0, 
311                        (struct sockaddr *)&test_chan_slave, 
312                        sa_len((struct sockaddr *)&test_chan_slave)) < 0) {
313                 perror("sendto");
314                 close(s);
315                 return;
316             }
317             total_packets++;
318         }
319         if (need_recv) {
320             FD_ZERO(&fds);
321             FD_SET(s, &fds);
322             timeout.tv_sec = NC_TEST_TIMEOUT;
323             timeout.tv_usec = 0;
324             if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
325                 test_printf("Slave timed out after %d buffers\n", i);
326                 lost_packets++;
327             } else {
328                 tdp = (struct nc_test_data *)in_buf;
329                 if (recvfrom(s, tdp, td_len, 0, 0, 0) < 0) {
330                     perror("recvfrom");
331                     close(s);
332                     return;
333                 }
334                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
335                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
336                     if (ntohl(tdp->seq) != seq) {
337                         test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
338                                     ntohl(tdp->seq), seq);
339                         seq_errors++;
340                         if (!need_send) {
341                             // Reset sequence to what the slave wants
342                             seq = ntohl(tdp->seq);
343                         }
344                     }
345                 } else {
346                     test_printf("Bad data packet - key: %x/%x, seq: %d\n",
347                                 ntohl(tdp->key1), ntohl(tdp->key2),
348                                 ntohl(tdp->seq));
349                 }
350                 total_packets++;
351             }
352             seq++;
353             if (seq == nbufs) {
354                 break;
355             }
356             if (pause_time && (++pkt_ctr == pause_threshold)) {
357                 pkt_ctr = 0;
358                 test_delay(pause_time);
359             }
360         }
361     }
362     gettimeofday(&end_time, 0);
363     show_results(type_name, &start_time, &end_time, total_packets, buflen, 
364                  lost_packets, seq_errors);
365     // Fetch results record
366     FD_ZERO(&fds);
367     FD_SET(s, &fds);
368     timeout.tv_sec = NC_RESULTS_TIMEOUT;
369     timeout.tv_usec = 0;
370     if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
371         test_printf("No results record sent\n");
372     } else {
373         if (recvfrom(s, &results, sizeof(results), 0, 0, 0) < 0) {
374             perror("recvfrom");
375         }
376         show_test_results(&results);
377     }
378     close(s);
379 }
380
381 //
382 // Read data from a stream, accounting for the fact that packet 'boundaries'
383 // are not preserved.  This can also timeout (which would probably wreck the
384 // data boundaries).
385 //
386
387 int
388 do_read(int fd, void *buf, int buflen)
389 {
390     char *p = (char *)buf;
391     int len = buflen;
392     int res;
393     while (len) {
394         res = read(fd, p, len);
395         if (res < 0) {
396             perror("read");
397         } else {
398             len -= res;
399             p += res;
400             if (res == 0) {
401                 break;
402             }
403         }
404     }
405     return (buflen - len);
406 }
407
408 void
409 do_tcp_test(int s1, int type, struct sockaddr *slave,
410             int nbufs, int buflen, int pause_time, int pause_threshold)
411 {
412     int i, s, td_len, tot_len, wlen, len, seq, seq_errors, total_packets, res;
413     struct sockaddr_storage test_chan_slave;
414     struct timeval start_time, end_time;
415     struct nc_request req;
416     struct nc_reply reply;
417     struct nc_test_results results;
418     struct nc_test_data *tdp;
419     int lost_packets = 0;
420     int conn_failures = 0;
421     int need_send, need_recv;
422     const char *type_name;
423     int pkt_ctr = 0;
424     unsigned char *dp;
425
426     need_recv = true;  need_send = true;  type_name = "TCP echo";
427     switch (type) {
428     case NC_REQUEST_TCP_RECV:
429         need_recv = false;
430         need_send = true;
431         type_name = "TCP recv";
432         break;
433     case NC_REQUEST_TCP_SEND:
434         need_recv = true;
435         need_send = false;
436         type_name = "TCP send";
437         break;
438     case NC_REQUEST_TCP_ECHO:
439         break;
440     }
441
442     new_test();
443     req.type = htonl(type);
444     req.nbufs = htonl(nbufs);
445     req.buflen = htonl(buflen);
446     req.slave_port = htonl(NC_TESTING_SLAVE_PORT);
447     req.master_port = htonl(NC_TESTING_MASTER_PORT);
448     nc_message(s1, &req, &reply, slave);
449     if (reply.response != ntohl(NC_REPLY_ACK)) {
450         test_printf("Slave denied %s [%d,%d] test\n", type_name, nbufs, buflen);
451         return;
452     }
453
454     s = socket(slave->sa_family, SOCK_STREAM, 0);
455     if (s < 0) {
456         pexit("datagram socket");
457     }
458
459     test_printf("Start %s [%d,%d]", type_name, nbufs, buflen);
460     if (pause_time) {
461         test_printf(" - %dms delay after %d packet%s\n", pause_time*10, 
462                     pause_threshold, pause_threshold > 1 ? "s" : "");
463     } else {
464         test_printf(" - no delays\n");
465     }
466
467     test_delay(3*100);  
468     memcpy(&test_chan_slave, slave, sa_len(slave));
469     switch (slave->sa_family) {
470     case AF_INET:
471         ((struct sockaddr_in *)&test_chan_slave)->sin_port = htons(ntohl(req.slave_port));
472         break;
473     case AF_INET6:
474         ((struct sockaddr_in6 *)&test_chan_slave)->sin6_port = htons(ntohl(req.slave_port));
475         break;
476     default:
477         pexit("strange TCP sockaddr");
478     }
479     while (connect(s, (struct sockaddr *)&test_chan_slave, sa_len(slave)) < 0) { 
480         perror("Can't connect to slave");
481         if (++conn_failures > MAX_ERRORS) {
482             test_printf("Too many connection failures - giving up\n");
483             return;
484         }
485         if (errno == ECONNREFUSED) {
486             // Give the slave a little time
487             test_delay(100);  // 1 second
488         } else {
489             return;
490         }
491     }
492
493     gettimeofday(&start_time, 0);
494     seq = 0;  seq_errors = 0;  total_packets = 0;
495     for (i = 0;  i < nbufs;  i++) {
496         td_len = buflen + sizeof(struct nc_test_data);
497         if (need_send) {
498             tdp = (struct nc_test_data *)out_buf;
499             tdp->key1 = htonl(NC_TEST_DATA_KEY1);
500             tdp->key2 = htonl(NC_TEST_DATA_KEY2);
501             tdp->seq = htonl(i);
502             tdp->len = htonl(td_len);
503             tot_len = 0;
504             dp = (unsigned char *)tdp;
505             while (tot_len < td_len) {
506                 len = td_len - tot_len;
507                 if ((wlen = write(s, dp, len)) != len) {
508                     if (wlen < 0) {
509                         test_printf("Slave connection broken\n");
510                         perror("write");
511                         close(s);
512                         return;
513                     } else {
514                         test_printf("block: %d, short write - only %d of %d\n", 
515                                     total_packets, wlen, len);
516                     }
517                 }
518                 tot_len += wlen;
519                 dp += wlen;
520             }
521             total_packets++;
522         }
523         if (need_recv) {
524             tdp = (struct nc_test_data *)in_buf;
525             res = do_read(s, tdp, td_len);
526             if (res != td_len) {
527                 lost_packets++;
528                 if (res < 0) {
529                     test_printf("Slave connection broken\n");
530                     perror("read");
531                     break;
532                 } else {
533                     test_printf("Slave timed out after %d buffers [read %d bytes]\n", i, res);
534                 }
535             } else {
536                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
537                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
538                     if (ntohl(tdp->seq) != seq) {
539                         test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
540                                     ntohl(tdp->seq), seq);
541                         seq_errors++;
542                         if (!need_send) {
543                             // Reset sequence to what the slave wants
544                             seq = ntohl(tdp->seq);
545                         }
546                     }
547                 } else {
548                     test_printf("Bad data packet - key: %x/%x, seq: %d\n",
549                                 ntohl(tdp->key1), ntohl(tdp->key2),
550                                 ntohl(tdp->seq));
551                 }
552                 total_packets++;
553             }
554             seq++;
555             if (seq == nbufs) {
556                 break;
557             }
558             if (pause_time && (++pkt_ctr == pause_threshold)) {
559                 pkt_ctr = 0;
560                 test_delay(pause_time);
561             }
562         }
563     }
564     gettimeofday(&end_time, 0);
565     show_results(type_name, &start_time, &end_time, total_packets, buflen, 
566                  lost_packets, seq_errors);
567     // Fetch results record
568     if (do_read(s, &results, sizeof(results)) != sizeof(results)) {
569         test_printf("No results record sent\n");
570     } else {
571         show_test_results(&results);
572     }
573     close(s);
574 }
575
576 int
577 do_set_load(int s, struct sockaddr *slave, int load_level)
578 {
579     struct nc_request req;
580     struct nc_reply reply;
581     req.type = htonl(NC_REQUEST_SET_LOAD);
582     req.nbufs = htonl(load_level);
583     nc_message(s, &req, &reply, slave);
584     return (reply.response == ntohl(NC_REPLY_ACK));
585 }
586
587 int
588 do_start_idle(int s, struct sockaddr *slave)
589 {
590     struct nc_request req;
591     struct nc_reply reply;
592     req.type = htonl(NC_REQUEST_START_IDLE);
593     nc_message(s, &req, &reply, slave);
594     return (reply.response == ntohl(NC_REPLY_ACK));
595 }
596
597 void
598 do_stop_idle(int s, struct sockaddr *slave, int calibrate)
599 {
600     struct nc_request req;
601     struct nc_reply reply;
602     long long res_idle_count;
603     long long adj_count;
604     int idle, res_idle_ticks;
605     req.type = htonl(NC_REQUEST_STOP_IDLE);
606     nc_message(s, &req, &reply, slave);
607     if (reply.response == ntohl(NC_REPLY_ACK)) {
608         res_idle_ticks = ntohl(reply.misc.idle_results.elapsed_time);
609         res_idle_count = ((long long)ntohl(reply.misc.idle_results.count[0]) << 32) |
610             ntohl(reply.misc.idle_results.count[1]);
611         test_printf("IDLE - ticks: %d, count: %ld", 
612                     res_idle_ticks, res_idle_count);
613         if (calibrate) {
614             idle_count = res_idle_count;
615             idle_ticks = res_idle_ticks;
616         } else {
617             adj_count = res_idle_count / res_idle_ticks;
618             adj_count *= idle_ticks;
619             idle = (int) ((adj_count * 100) / idle_count);
620             test_printf(", %d%% idle", idle);
621         }
622         test_printf("\n");
623     } else {
624         test_printf("Slave failed on IDLE\n");
625     }
626 }
627
628 void
629 do_disconnect(int s, struct sockaddr *slave)
630 {
631     struct nc_request req;
632     struct nc_reply reply;
633     req.type = htonl(NC_REQUEST_DISCONNECT);
634     nc_message(s, &req, &reply, slave);
635 }
636
637 static void
638 nc_master_test(struct sockaddr *slave, int test_tcp, int test_udp,
639                int test_slave_loads, int test_master_loads)
640 {
641     int s, i;
642     struct sockaddr_storage my_addr;
643     struct pause pause_times[] = {
644         {0,0}, {1,10}, {5,10}, {10,10}, {1,1} };
645
646
647     s = socket(slave->sa_family, SOCK_DGRAM, 0);
648     if (s < 0) {
649         pexit("datagram socket");
650     }
651
652     memset(&my_addr, 0, sizeof(my_addr));
653     ((struct sockaddr *)&my_addr)->sa_family = slave->sa_family;
654 #ifndef __linux
655     ((struct sockaddr *)&my_addr)->sa_len = slave->sa_len;
656 #endif
657     switch (slave->sa_family) {
658     case AF_INET:
659         ((struct sockaddr_in *)&my_addr)->sin_addr.s_addr = htonl(INADDR_ANY);
660         ((struct sockaddr_in *)&my_addr)->sin_port = htons(NC_MASTER_PORT);
661         break;
662     case AF_INET6:
663         ((struct sockaddr_in6 *)&my_addr)->sin6_addr = in6addr_any;
664         ((struct sockaddr_in6 *)&my_addr)->sin6_port = htons(NC_MASTER_PORT);
665         break;
666     default:
667         pexit("strange sockaddr family");
668     }
669     if (bind(s, (struct sockaddr *) &my_addr, sa_len((struct sockaddr *)&my_addr)) < 0) {
670         pexit("UDP bind <main>");
671     }
672
673     test_printf("================== No load, master at 100%% ========================\n");
674     if (test_udp) {
675         do_udp_test(s, NC_REQUEST_UDP_ECHO, slave, 640, 1024, 0, 0);
676         do_udp_test(s, NC_REQUEST_UDP_SEND, slave, 640, 1024, 0, 0);
677         do_udp_test(s, NC_REQUEST_UDP_RECV, slave, 640, 1024, 0, 0);
678     }
679     if (test_tcp) {
680         do_tcp_test(s, NC_REQUEST_TCP_ECHO, slave, 640, 1024, 0, 0);
681         do_tcp_test(s, NC_REQUEST_TCP_SEND, slave, 640, 1024, 0, 0);
682         do_tcp_test(s, NC_REQUEST_TCP_RECV, slave, 640, 1024, 0, 0);
683         do_tcp_test(s, NC_REQUEST_TCP_ECHO, slave, 64, 10240, 0, 0);
684     }
685
686     if (test_slave_loads) {
687         if (do_set_load(s, slave, 0)) {
688             test_printf("\n====================== Various slave compute loads ===================\n");
689             for (i = 0;  i < 60;  i += 10) {
690                 test_printf(">>>>>>>>>>>> slave processing load at %d%%\n", i);                
691                 do_set_load(s, slave, i);
692                 if (test_udp) {
693                     do_udp_test(s, NC_REQUEST_UDP_ECHO, slave, 2048, 1024, 0, 0);
694                 }
695                 if (test_tcp) {
696                     do_tcp_test(s, NC_REQUEST_TCP_ECHO, slave, 2048, 1024, 0, 0);
697                 }
698             }
699         }
700     }
701
702     if (test_master_loads) {
703         if (do_start_idle(s, slave)) {
704             test_printf("\n====================== Various master loads ===================\n");
705             test_printf("Testing IDLE for %d seconds\n", IDLE_TEST_TIME);
706             test_delay(IDLE_TEST_TIME*100);
707             do_stop_idle(s, slave, true);
708             for (i = 0;  i < LENGTH(pause_times);  i++) {
709                 if (test_udp) {
710                     do_start_idle(s, slave);
711                     do_udp_test(s, NC_REQUEST_UDP_ECHO, slave, 2048, 1024, 
712                                 pause_times[i].pause_ticks, pause_times[i].pause_threshold);
713                     do_stop_idle(s, slave, false);
714                 }
715                 if (test_tcp) {
716                     do_start_idle(s, slave);
717                     do_tcp_test(s, NC_REQUEST_TCP_ECHO, slave, 2048, 1024, 
718                                 pause_times[i].pause_ticks, pause_times[i].pause_threshold);
719                     do_stop_idle(s, slave, false);
720                 }
721             }
722         }
723     }
724
725 //    do_disconnect(s, slave);
726     close(s);
727 }
728
729 static void
730 nc_master(struct test_params *p)
731 {
732     struct sockaddr_storage slave, my_addr;
733     struct addrinfo *ai, *addrs, hints;
734     char *host = (char *)NULL;
735     int i;
736     int err = 0;
737     int test_tcp = true;
738     int test_udp = true;
739     int test_slave_loads = true;
740     int test_master_loads = true;
741
742     for (i = 1;  i < p->argc;  i++) {
743         if (p->argv[i][0] == '-') {
744             switch (p->argv[i][1]) {
745             case 't':
746                 test_tcp = false;
747                 break;
748             case 'u':
749                 test_udp = false;
750                 break;
751             case 's':
752                 test_slave_loads = false;
753                 break;
754             case 'm':
755                 test_master_loads = false;
756                 break;
757             default:
758                 test_printf("... invalid switch '%s'\n", p->argv[i]);
759                 err++;
760             }
761         } else {
762             if (host != (char *)NULL) {
763                 test_printf("... ignoring argument '%s'\n", p->argv[i]);
764                 err++;
765             } else {
766                 host = p->argv[i];
767             }
768         }
769     }
770     if ((err != 0) || (p->argc < 2) || (host == (char *)NULL)) {
771         test_printf("usage: 'master <host> [-t] [-u] [-s] [-m]'\n");
772         test_printf("   -t - suppress TCP tests\n");
773         test_printf("   -u - suppress UDP tests\n");
774         test_printf("   -s - suppress slave load tests\n");
775         test_printf("   -m - suppress master load tests\n");
776         return;
777     }
778     bzero(&hints, sizeof(hints));
779     hints.ai_family = PF_UNSPEC;
780     hints.ai_socktype = SOCK_DGRAM;
781     hints.ai_flags = AI_PASSIVE;
782     if ((err = getaddrinfo(p->argv[1], _string(NC_SLAVE_PORT), &hints, &addrs)) != EAI_NONE) {
783         test_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
784         pexit("getaddrinfo");
785     }
786     // Prepare a socket for each connection type
787     ai = addrs;
788     while (ai) {
789         nc_master_test(ai->ai_addr, test_tcp, test_udp, test_slave_loads, test_master_loads);
790         ai = ai->ai_next;
791     }
792 }
793
794 void
795 net_test(test_param_t p)
796 {
797     test_printf("Start Network Characterization - MASTER\n");
798 #ifdef __ECOS
799     init_all_network_interfaces();
800 #endif
801     nc_master((struct test_params *)p);
802     cyg_test_exit();
803 }
804
805 #ifdef __ECOS
806 void
807 cyg_start(void)
808 {
809     static struct test_params p;
810     // Create a main thread, so we can run the scheduler and have time 'pass'
811     cyg_thread_create(10,                // Priority - just a number
812                       net_test,          // entry
813                       (cyg_addrword_t)&p,// entry parameter
814                       "Network test",    // Name
815                       &stack[0],         // Stack
816                       STACK_SIZE,        // Size
817                       &thread_handle,    // Handle
818                       &thread_data       // Thread data structure
819             );
820     cyg_thread_resume(thread_handle);  // Start it
821     cyg_scheduler_start();
822 }
823
824 #else
825
826 int
827 main(int argc, char *argv[])
828 {
829     struct test_params p;
830     p.argc = argc;
831     p.argv = argv;
832     net_test(&p);
833 }
834 #endif