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