OpenCores
URL https://opencores.org/ocsvn/xenie/xenie/trunk

Subversion Repositories xenie

[/] [xenie/] [trunk/] [examples/] [Eth_example/] [sw/] [XenieEthExample/] [WinSock_test/] [src/] [main.c] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 DFC
/***************************************************************************
2
 *
3
 * (C) Copyright 2017 DFC Design, s.r.o., Brno, Czech Republic
4
 * Author: Marek Kvas (m.kvas@dspfpga.com)
5
 *
6
 ***************************************************************************
7
 *
8
 * This file is part of Xenia Ethernet Example project.
9
 *
10
 * Xenia Ethernet Example project is free software: you can
11
 * redistribute it and/or modify it under the terms of
12
 * the GNU Lesser General Public License as published by the Free
13
 * Software Foundation, either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * Xenia Ethernet Example project is distributed in the hope that
17
 * it will be useful, but WITHOUT ANY WARRANTY; without even
18
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A
19
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License
20
 * for more details.
21
 *
22
 * You should have received a copy of the GNU Lesser General Public
23
 * License along with Xenia Ethernet Example project.  If not,
24
 * see <http://www.gnu.org/licenses/>.
25
 *
26
 ***************************************************************************
27
 *
28
 * !!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!
29
 * This console application demonstrates functionality of Xenie Ethernet
30
 * Example design. The application generates high bandwidth network traffic
31
 * which - if accidentally routed to corporate/public network segment - can
32
 * saturate network infrastructure and effectively prevent network from
33
 * correct function. Some devices may even start to behave unpredictably
34
 * than. It is highly recommended to use this example on dedicated private
35
 * network segments only. If you are not sure about network infrastructure,
36
 * consult situation with your network administrator.
37
 * !!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!
38
 *
39
 * As the first step, presence of any Xenie with correct running design
40
 * is verified using Network info discovery packet. This packet is
41
 * broadcasted to all interfaces. When Xenie receives it, it responds with
42
 * unicast response containing its MAC, IPv4 address and netmask. Because
43
 * Xenie example design doesn't have ARP, static ARP record is created
44
 * in order to enable unicast communication.
45
 *
46
 * !!! Static ARP record may - if not well understood and managed -
47
 * cause weird behaviour of the network. Static ARP record is not
48
 * permanent, so it disappears after system reboot, or ARP table reset.
49
 *
50
 * If Xenie is found on the network, number of transmitter / receiver
51
 * thread pairs is created. The number of this pairs is given by
52
 * SESSIONS_COUNT macro.
53
 *
54
 * Each transmitter thread sends UDP test traffic as fast as possible to
55
 * Xenie address. Xenie captures this packets, inserts some statistical
56
 * data into each datagram and sends them back.
57
 * This "looped back" datagrams are captured by the corresonding receiver
58
 * thread. It checks the statistics inserted by Xenie and determines whether
59
 * any datagrams were lost. The lost count and some other information is
60
 * stored in the context of each receiver.
61
 *
62
 * The main thread periodically reads the statistics from all the receiver
63
 * threads, sums them up (if applicable) and prints info to the console.
64
 *
65
 * Integrity of the received frames is protected by 32 bit CRC at the
66
 * Ethernet layer so it is not necessary to check for datagram payload
67
 * correctness. Corrupted packets are simply discarded by NIC.
68
 *
69
 * Timestamps from Xenie are used to measure bandwidth. Calculated number
70
 * should match number given by Windows task manager. Be careful about
71
 * interpretation of graphs shown by the task manager as it sums up TX and
72
 * RX traffic. So if 50 % of bandwidth is really used, graphs show 100 %
73
 * already.
74
 *
75
 * In order to generate maximum traffic, maximum frame size is used.
76
 * MTU macro can be modified to limit packet size. By default 9000
77
 * bytes is used - it is standard maximum value for jumbo frames.
78
 * When this macro is set to value higher than real MTU used by
79
 * machine running this application, datagrams are fragmented at the IP
80
 * layer. As Xenie cannot handle fragmented IP packets, the test wont
81
 * work as expected - high but not 100 % packet loss is
82
 * most likely result. If host machine has MTU high enough, but
83
 * there is any network switch on the path to Xenie that doesn't
84
 * support set MTU, the traffic will most likely be lost completely.
85
 * !!! Check your NIC settings for the MTU before you run this application.
86
 *
87
 *
88
 */
89
 
90
#include <stdio.h>
91
#include <stdlib.h>
92
#include <winsock2.h>
93
#include <WS2tcpip.h>
94
#include <IPHlpApi.h>
95
#include <stdint.h>
96
 
97
/* Windows Socket library */
98
#pragma comment(lib,"ws2_32.lib")
99
 
100
/*
101
 * Ports of services provided by xenie eth example design.
102
 * They are hardcoded in HDL.
103
 */
104
#define XENIE_TEST_PORT                                         0xdfc1
105
#define XENIE_NET_INFO_DICOVERY_PORT            0xdfcc
106
/* Magic number hardcoded in HDL for our traffic identification */
107
#define TEST_PACKET_MAGIC       0xDFCDFC01
108
 
109
/* Namber of TX/RX thread pairs to be created */
110
#define SESSIONS_COUNT          60
111
 
112
/*
113
 * MTU must be set to value equal or less than MTU set on NIC.
114
 * 9000 is maximum for most of standard NICs.
115
 *
116
 * If set too high, Windows stack will fragment datagrams on IP
117
 * leyer. Xenie test design doesn't support fragmented packets -
118
 * communication will be corrupted.
119
 */
120
/* MTU of the NIC or path */
121
#define MTU 9000 
122
/* Real length of Ethernet frame (pramble and FCS excluded)*/
123
#define MAX_ETH_FRAME_SIZE ((MTU) + 14) 
124
/* Max lenght of UDP payload to fulfill MTU */
125
#define MAX_PKT_UDP_DATA ((MAX_ETH_FRAME_SIZE) - (14 + 20 + 8)) 
126
/* Lenght of balast after out test protocol header to create maximum packet */
127
#define MAX_PKT_DATA_LENGTH ((MAX_PKT_UDP_DATA) - 32) 
128
 
129
/* Structure defining packet carrying Xenie's network settings */
130
#pragma pack(push)
131
struct xenie_net_info_pkt_s {
132
        uint64_t tstmp;
133
        unsigned char mac_addr[6];
134
        unsigned char pad[2];
135
        IN_ADDR ip_addr;
136
        IN_ADDR net_mask;
137
};
138
#pragma pack(pop)
139
 
140
 
141
/*
142
 * Send xenie discovery packet.
143
 * Zero is returned on success and xenie argument is
144
 * filled with received data.
145
 */
146
int find_xenie(struct xenie_net_info_pkt_s *xenie)
147
{
148
        int i;
149
        int res, ret = -1;
150
        SOCKET s;
151
        SOCKADDR_IN xenie_net_info_dicovery;
152
        DWORD optval;
153
 
154
        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
155
        if (s == INVALID_SOCKET)
156
                return -1;
157
 
158
        /* Enable broadcasts */
159
        optval = 100;
160
        res = setsockopt(s, SOL_SOCKET, SO_BROADCAST,
161
                        (char *)&optval, sizeof(optval));
162
        if (res)
163
                goto err;
164
 
165
        /* Set Timeout for response */
166
        optval = 100;
167
        res = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
168
                        (char *)&optval, sizeof(optval));
169
        if (res)
170
                goto err;
171
 
172
        /* Send dicovery packet */
173
        xenie_net_info_dicovery.sin_addr.s_addr = INADDR_BROADCAST;
174
        xenie_net_info_dicovery.sin_port = ntohs(XENIE_NET_INFO_DICOVERY_PORT);
175
        xenie_net_info_dicovery.sin_family = AF_INET;
176
 
177
        res = sendto(s," ", 1, 0, (SOCKADDR*)&xenie_net_info_dicovery,
178
                                sizeof(xenie_net_info_dicovery));
179
        if(res != 1) {
180
                printf("err %d\n", WSAGetLastError());
181
                goto err;
182
        }
183
 
184
 
185
        /* Receive response */
186
        res = recv(s, (char*)xenie, sizeof(*xenie), 0);
187
        if(res != sizeof(*xenie))
188
                goto err;
189
 
190
        /* Change byteorder for IP addresses */
191
        xenie->ip_addr.s_addr = ntohl(xenie->ip_addr.s_addr);
192
        xenie->net_mask.s_addr = ntohl(xenie->net_mask.s_addr);
193
        /* swap bytes for mac address */
194
        for(i = 0; i < 3; i++) {
195
                unsigned char tmp;
196
                tmp = xenie->mac_addr[i];
197
                xenie->mac_addr[i] = xenie->mac_addr[5-i];
198
                xenie->mac_addr[5-i] = tmp;
199
        }
200
 
201
        ret = 0;
202
err:
203
        closesocket(s);
204
        return ret;
205
}
206
 
207
 
208
/*
209
 * Beacause xenie with demo udp_ip stack doesn't suppor ARP.
210
 * it is necessary to create static ARP record if unicast
211
 * communication is needed.
212
 */
213
int create_arp_record(struct xenie_net_info_pkt_s *xenie)
214
{
215
        unsigned int i;
216
        int res;
217
        int ret = 0;
218
        MIB_IPNETROW arp_entry;
219
        PMIB_IPNETTABLE ip_net_table;
220
        unsigned long arpTableLength = 0;
221
 
222
 
223
        /*
224
         * Get current ARP table to find whether adderess
225
         * is already assigned or not
226
         */
227
        res = GetIpNetTable(NULL, &arpTableLength, 1);
228
        if (res != ERROR_INSUFFICIENT_BUFFER)
229
                return -1;
230
        ip_net_table = (PMIB_IPNETTABLE)malloc(arpTableLength);
231
        if (ip_net_table == NULL)
232
                return -1;
233
        res = GetIpNetTable(ip_net_table, &arpTableLength, 1);
234
        if (res) {
235
                ret = -1;
236
                goto end;
237
        }
238
 
239
        /* We have to create new record */
240
        arp_entry.dwPhysAddrLen = 6;
241
        memcpy(&arp_entry.bPhysAddr, xenie->mac_addr, arp_entry.dwPhysAddrLen);
242
        res = GetBestInterface(xenie->ip_addr.s_addr, &arp_entry.dwIndex);
243
        if(res){
244
                ret = -1;
245
                goto end;
246
        }
247
        arp_entry.dwAddr = xenie->ip_addr.s_addr;
248
        arp_entry.Type = MIB_IPNET_TYPE_STATIC;
249
 
250
        /*
251
         * First Search ARP table for our address whether
252
         * there is any similar record
253
         */
254
        for (i = 0; i < ip_net_table->dwNumEntries; i++) {
255
                if (ip_net_table->table[i].dwAddr == xenie->ip_addr.s_addr) {
256
                        if ((strncmp((char*)ip_net_table->table[i].bPhysAddr,
257
                                                                         (char*)xenie->mac_addr, 6) != 0) ||
258
                           (ip_net_table->table[i].Type != MIB_IPNET_TYPE_STATIC) ||
259
                           (ip_net_table->table[i].dwIndex != arp_entry.dwIndex)) {
260
                                res = DeleteIpNetEntry(&ip_net_table->table[i]);
261
                        } else {
262
                                /* Record already exists so let it be */
263
                                goto end;
264
                        }
265
                }
266
        }
267
 
268
 
269
 
270
        res = CreateIpNetEntry(&arp_entry);
271
        if(res) {
272
                ret = -1;
273
                goto end;
274
        }
275
end:
276
        free(ip_net_table);
277
        return ret;
278
}
279
 
280
 
281
/* Structure definind packets used for testing */
282
struct test_counters {
283
        uint32_t loopback_pkt_cnt;
284
        uint32_t test_pkt_cnt;
285
        uint32_t unknown_port_pkt_cnt;
286
        uint32_t test_pkt_accepted_cnt;
287
};
288
 
289
#pragma pack(push)
290
struct testPkt {
291
        uint32_t magic;
292
        uint32_t seqNo;
293
        uint64_t tstmp;
294
        struct test_counters cnts;
295
        char data[MAX_PKT_DATA_LENGTH];
296
};
297
#pragma pack(pop)
298
 
299
/* Structure used to managed threads */
300
struct threadManagement {
301
        HANDLE threadHandle;
302
        DWORD threadID;
303
        HANDLE exitEvent;
304
};
305
 
306
/* Collection of statistics counters*/
307
struct rcv_stats {
308
        uint32_t received_pkts;
309
        uint32_t received_test_pkts;
310
        uint32_t lost_pkts;
311
        uint32_t seqNo_restarts;
312
        uint64_t max_pkt_period;
313
};
314
 
315
/* Context for received thread */
316
struct rcvThreadData {
317
        struct threadManagement tmng;
318
        SOCKET *s;
319
        HANDLE   accessMutex;
320
        uint32_t last_seqNo;
321
        uint64_t last_timestamp;
322
        uint32_t first_test_pkt_accepted_cnt;
323
        struct rcv_stats stats;
324
        struct test_counters cnts;
325
        unsigned int ring_low_watermark;
326
};
327
 
328
/* Context for send thread */
329
struct sendThreadData {
330
        struct threadManagement tmng;
331
        HANDLE   accessMutex;
332
        SOCKET  *s;
333
        uint32_t sent_pkts;
334
};
335
 
336
/* Structure keeping references to correspondind send/receive threads */
337
struct sendRcvSession {
338
        struct rcvThreadData rcv;
339
        struct sendThreadData snd;
340
        SOCKET s;
341
};
342
 
343
/* Body od send threads */
344
DWORD WINAPI sendThread_func (LPVOID param) {
345
        int res;
346
        int i;
347
        struct sendThreadData *ctx = (struct sendThreadData*)param;
348
        struct testPkt pkt;
349
 
350
        ctx->sent_pkts = 0;
351
        pkt.magic = TEST_PACKET_MAGIC;
352
        /* Fill body of packet with random data */
353
        srand( (unsigned)time( NULL ) );
354
        for(i = 0; i < MAX_PKT_DATA_LENGTH; i++) {
355
                pkt.data[i] = rand();
356
        }
357
 
358
        while(WaitForSingleObject(ctx->tmng.exitEvent,0) == WAIT_TIMEOUT) {
359
                WaitForSingleObject(ctx->accessMutex, INFINITE);
360
                pkt.seqNo = ctx->sent_pkts;
361
                res = send(*ctx->s, (char *)&pkt, MAX_PKT_UDP_DATA, 0);
362
                if (res < 0) {
363
                        printf("ERROR: Send failed with error %d\n", WSAGetLastError());
364
                } else {
365
                        ctx->sent_pkts++;
366
                }
367
                ReleaseMutex(ctx->accessMutex);
368
        }
369
}
370
 
371
/* Budy of receive thread */
372
DWORD WINAPI rcvThread_func(LPVOID param)
373
{
374
        int res;
375
        struct rcvThreadData *ctx = (struct rcvThreadData*)param;
376
        struct testPkt pkt;
377
 
378
 
379
        /* Loop until asked to exit */
380
        while(WaitForSingleObject(ctx->tmng.exitEvent,0) == WAIT_TIMEOUT) {
381
                res = recv(*ctx->s, (char*)&pkt, sizeof(pkt), 0);
382
                if (res > 0) {
383
                        /* packet received */
384
                        ctx->stats.received_pkts++;
385
                        //pkt = (struct pkt*)cur_recv_req->pkt_addr;
386
                        /* Check it is ours test packet */
387
                        if((pkt.magic == TEST_PACKET_MAGIC) && (res == MAX_PKT_UDP_DATA)) {
388
                                WaitForSingleObject(ctx->accessMutex, INFINITE);
389
                                /* Careful about the first packet */
390
                                if (ctx->stats.received_test_pkts) {
391
                                        if(pkt.seqNo < (ctx->last_seqNo+1)) {
392
                                                ctx->stats.seqNo_restarts++;
393
                                        } else {
394
                                                ctx->stats.lost_pkts += pkt.seqNo - ctx->last_seqNo -1;
395
                                        }
396
                                } else {
397
                                        ctx->first_test_pkt_accepted_cnt =
398
                                                pkt.cnts.test_pkt_accepted_cnt;
399
                                }
400
                                ctx->stats.received_test_pkts++;
401
                                ctx->last_seqNo = pkt.seqNo;
402
                                ctx->cnts = pkt.cnts;
403
                                ctx->last_timestamp = pkt.tstmp;
404
                                ReleaseMutex(ctx->accessMutex);
405
                        } else {
406
                                /* This packet doesnt belong to our test */
407
                                printf("ERROR: Captured packet with wrong magic number or length\n");
408
                        }
409
                } else if (res == WSAETIMEDOUT) {
410
                        // recv timed out - nothing happened
411
                        continue;
412
                } else {
413
                        // error occured
414
                        printf("ERROR: recv returned error number %d\n",
415
                                WSAGetLastError());
416
                }
417
        }
418
 
419
        return 0;
420
}
421
 
422
/* Convenience function creating send/receive thread */
423
int startThread(LPTHREAD_START_ROUTINE lpStartAddress,
424
                                struct threadManagement *tmng)
425
{
426
        tmng->exitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
427
        if (tmng->exitEvent == NULL)
428
                return -1;
429
        tmng->threadHandle = CreateThread(NULL, 0, lpStartAddress,
430
                        tmng, 0, &tmng->threadID);
431
        if (tmng->threadHandle == NULL) {
432
                CloseHandle(tmng->threadHandle);
433
                return -1;
434
        }
435
 
436
        return 0;
437
}
438
 
439
/* Convenience function creating send/receive thread pair */
440
int create_session(struct sendRcvSession *session,
441
                                        struct xenie_net_info_pkt_s *xenie)
442
{
443
        int res;
444
        SOCKADDR_IN xenie_addr;
445
        DWORD optval;
446
 
447
        /* Create socket common for both send and receive */
448
        session->s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
449
        if (session->s == INVALID_SOCKET)
450
                return -1;
451
 
452
        /* Set Timeout for response */
453
        optval = 100;
454
        res = setsockopt(session->s, SOL_SOCKET, SO_RCVTIMEO,
455
                (char *)&optval, sizeof(optval));
456
        if (res) {
457
                printf("ERROR: Cannot set timeout on socket\n");
458
                goto clean_skt;
459
        }
460
 
461
        /* Set receive buffer for response */
462
        optval = 32*1024*1024;
463
        res = setsockopt(session->s, SOL_SOCKET, SO_RCVBUF,
464
                (char *)&optval, sizeof(optval));
465
        if (res) {
466
                printf("ERROR: Cannot set timeout on socket\n");
467
                goto clean_skt;
468
        }
469
 
470
        /* Connect to test socket */
471
        xenie_addr.sin_addr.s_addr = xenie->ip_addr.s_addr;
472
        xenie_addr.sin_port = ntohs(XENIE_TEST_PORT);
473
        xenie_addr.sin_family = AF_INET;
474
 
475
        res = connect(session->s, (SOCKADDR*)&xenie_addr, sizeof(xenie_addr));
476
        if (res < 0) {
477
                printf("ERROR: Cannot send data to selected socket.\n");
478
                goto clean_skt;
479
        }
480
 
481
        session->rcv.accessMutex = CreateMutex(NULL, 0, NULL);
482
        session->snd.accessMutex = CreateMutex(NULL, 0, NULL);
483
 
484
        if ((session->rcv.accessMutex == NULL) ||
485
                (session->rcv.accessMutex == NULL)) {
486
                goto clean_mutex;
487
        }
488
 
489
        session->rcv.s = &session->s;
490
        session->snd.s = &session->s;
491
 
492
        /* Create thread for receiving */
493
        if(startThread(rcvThread_func, &session->rcv.tmng)) {
494
                printf("ERROR: Cannot start receive thread.\n");
495
                goto clean_mutex;
496
        }
497
 
498
        /* Create thread for sending */
499
        if(startThread(sendThread_func, &session->snd.tmng)) {
500
                printf("ERROR: Cannot start send thread.\n");
501
                goto clean_rcvThread;
502
        }
503
 
504
        return 0;
505
 
506
clean_rcvThread:
507
        SetEvent(session->rcv.tmng.exitEvent);
508
        /* wait for thread to really end */
509
        WaitForSingleObject(session->rcv.tmng.threadHandle, INFINITE);
510
clean_mutex:
511
        CloseHandle(session->rcv.accessMutex);
512
        CloseHandle(session->snd.accessMutex);
513
clean_skt:
514
        closesocket(session->s);
515
        return -1;
516
}
517
 
518
int main (int argc, char *argv[])
519
{
520
        WSADATA wsaData;
521
        int res;
522
        int i;
523
        struct xenie_net_info_pkt_s xenie;
524
        struct rcvThreadData rcvThreadCtx;
525
        struct sendThreadData sendThreadCtx;
526
        struct sendRcvSession sessions[SESSIONS_COUNT];
527
        uint64_t last_timestamp = 0;
528
        uint32_t last_test_pkt_accepted_cnt =0;
529
 
530
 
531
 
532
        /* Windows sockets library init */
533
        res = WSAStartup(MAKEWORD(2, 2), &wsaData);
534
    if (res != NO_ERROR) {
535
                printf("ERROR: Cannot initialize Windows Sockets library. Error: %d\n",
536
                        WSAGetLastError());
537
        return 1;
538
    }
539
 
540
        res = find_xenie(&xenie);
541
        if (res) {
542
                printf("ERROR: No xenie board has been found.\n");
543
                return 1;
544
        }
545
 
546
        printf("Xenie board found:\n");
547
        printf("MAC:       %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
548
                xenie.mac_addr[5],xenie.mac_addr[4], xenie.mac_addr[3],
549
                xenie.mac_addr[2], xenie.mac_addr[1], xenie.mac_addr[0]);
550
        printf("IP:        %s\n", inet_ntoa(xenie.ip_addr));
551
        printf("Net mask:  %s\n\n", inet_ntoa(xenie.net_mask));
552
 
553
        if (create_arp_record(&xenie)) {
554
                printf("ERROR: Cannot create static ARP record for Xenie borad\n");
555
                return 1;
556
        }
557
 
558
        /* Clean memory with session contexts */
559
        memset(sessions, 0, sizeof(sessions));
560
 
561
        /* Start all sessions */
562
        for (i = 0; i < SESSIONS_COUNT; i++) {
563
                printf(" Creating session %d ... ", i);
564
                if (create_session(&sessions[i], &xenie)) {
565
                        printf("failed.\n");
566
                        return -1;
567
                } else {
568
                        printf("Ok.\n");
569
                }
570
        }
571
 
572
 
573
        /* Main thread prints statistics once a second */
574
        while (1) {
575
                struct rcv_stats stats;
576
                struct test_counters cnts;
577
                uint32_t sent_pkts, received_pkts, lost_pkts;
578
                uint32_t test_pkt_cnt, test_pkt_accepted_cnt;
579
                uint32_t loopback_pkt_cnt, unknown_port_pkt_cnt;
580
                uint32_t pkt_cnt_per_unit;
581
                uint64_t tstmp, unit;
582
                double bandwidth;
583
 
584
                /* Collect statistics */
585
                sent_pkts = 0;
586
                received_pkts = 0;
587
                lost_pkts = 0;
588
                test_pkt_cnt = 0;
589
                test_pkt_accepted_cnt = 0;
590
                loopback_pkt_cnt = 0;
591
                unknown_port_pkt_cnt = 0;
592
 
593
                for (i = 0; i < SESSIONS_COUNT; i++) {
594
                        WaitForSingleObject(sessions[i].rcv.accessMutex, INFINITE);
595
                        stats = sessions[i].rcv.stats;
596
                        cnts = sessions[i].rcv.cnts;
597
                        tstmp = sessions[i].rcv.last_timestamp;
598
                        ReleaseMutex(sessions[i].rcv.accessMutex);
599
 
600
                        WaitForSingleObject(sessions[i].snd.accessMutex, INFINITE);
601
                        sent_pkts += sessions[i].snd.sent_pkts;
602
                        ReleaseMutex(sessions[i].snd.accessMutex);
603
 
604
                        received_pkts += stats.received_pkts;
605
                        lost_pkts += stats.lost_pkts;
606
                }
607
                /* These are common for all sessions and don't sum them up*/
608
                test_pkt_cnt = cnts.test_pkt_cnt;
609
                test_pkt_accepted_cnt = cnts.test_pkt_accepted_cnt;
610
                loopback_pkt_cnt = cnts.loopback_pkt_cnt;
611
                unknown_port_pkt_cnt = cnts.unknown_port_pkt_cnt;
612
 
613
                pkt_cnt_per_unit = test_pkt_accepted_cnt - last_test_pkt_accepted_cnt;
614
                last_test_pkt_accepted_cnt = test_pkt_accepted_cnt;
615
                unit = tstmp - last_timestamp;
616
                last_timestamp = tstmp;
617
 
618
                bandwidth = (double)pkt_cnt_per_unit *
619
                        MAX_ETH_FRAME_SIZE/((double)unit/156250000);
620
 
621
                printf("----------\n");
622
                printf("Bandwidth %.3f MB/s (%.1f %%)\n",
623
                        bandwidth/1024/1024, 100*8*bandwidth/10000000000);
624
                printf("Sent pkts %-9u, received %-9u, lost %-5u (%-5d)\n",
625
                        sent_pkts, received_pkts, lost_pkts, test_pkt_accepted_cnt -
626
                        sessions[0].rcv.first_test_pkt_accepted_cnt - sent_pkts);
627
                printf("test_pkt_cnt %-9u, test_accepted_pkt_cnt, "
628
                           "%-9u loopback %-9u unknown_pkt_cnt %-9u\n",
629
                        test_pkt_cnt, test_pkt_accepted_cnt,
630
                        loopback_pkt_cnt, unknown_port_pkt_cnt);
631
                Sleep(1000);
632
        }
633
 
634
        return 0;
635
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.