1/*
2 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <time.h>
13#include <barrelfish/barrelfish.h>
14#include <barrelfish/waitset.h>
15#include <barrelfish/waitset_chan.h>
16#include <barrelfish/deferred.h>
17#include <barrelfish/sys_debug.h>
18#include <devif/queue_interface.h>
19#include <devif/backends/net/udp.h>
20#include <bench/bench.h>
21#include <net_interfaces/flags.h>
22
23
24#define BENCH
25//#define DEBUG(x...) printf("devif_test: " x)
26#define DEBUG(x...) do {} while (0)
27
28#define TX_BUF_SIZE 2048
29#define RX_BUF_SIZE 2048
30#define NUM_BUF 1024
31#define MEMORY_SIZE RX_BUF_SIZE*NUM_BUF
32
33
34
35static struct devq* udp_q;
36static struct capref memory_rx;
37static regionid_t regid_rx;
38static struct frame_identity id;
39static lpaddr_t phys_rx;
40static void* va_rx;
41
42static uint32_t ip_dst;
43static uint64_t mac_dst;
44static uint16_t port_src;
45static uint16_t port_dst;
46static const char* cardname;
47
48
49static uint64_t bytes = 0;
50#ifdef BENCH
51static uint64_t num_dequeue_tx = 0;
52static uint64_t num_dequeue_rx = 0;
53static uint64_t num_enqueue_tx = 0;
54static uint64_t num_enqueue_rx = 0;
55static uint64_t enq_s, enq_e;
56static uint64_t deq_s, deq_e;
57static uint64_t tot_enq_rx, tot_deq_rx;
58static uint64_t tot_enq_tx, tot_deq_tx;
59#endif
60static uint64_t num_rx = 0;
61static uint64_t start;
62static uint64_t end;
63static uint64_t tsc_per_ms;
64
65static bool use_irq = false;
66
67static void event_cb(void* queue)
68{
69    struct devq* q = (struct devq*) udp_q;
70
71    errval_t err;
72
73    regionid_t rid;
74    genoffset_t offset;
75    genoffset_t length;
76    genoffset_t valid_data;
77    genoffset_t valid_length;
78    uint64_t flags;
79
80    err = SYS_ERR_OK;
81
82    while (err == SYS_ERR_OK) {
83#ifdef BENCH
84        deq_s = rdtsc();
85#endif
86        err = devq_dequeue(q, &rid, &offset, &length, &valid_data,
87                           &valid_length, &flags);
88
89        if (err_is_fail(err)) {
90            break;
91        }
92
93        if (flags & NETIF_TXFLAG) {
94#ifdef BENCH
95            deq_e = rdtsc();
96            num_dequeue_tx++;
97            tot_deq_tx += deq_e - deq_s;
98#endif
99            DEBUG("Received TX buffer back \n");
100#ifdef BENCH
101            enq_s = rdtsc();
102#endif
103            err = devq_enqueue(q, rid, offset, length, 0,
104                               0, NETIF_RXFLAG);
105            if (err_is_fail(err)) {
106                break;
107            }
108#ifdef BENCH
109            enq_e = rdtsc();
110            num_enqueue_rx++;
111            tot_enq_rx += enq_e - enq_s;
112#endif
113        } else if (flags & NETIF_RXFLAG) {
114#ifdef BENCH
115            deq_e = rdtsc();
116            num_dequeue_rx++;
117            tot_deq_rx += deq_e - deq_s;
118#endif
119            num_rx++;
120            bytes += valid_length;
121            DEBUG("Received RX buffer \n");
122#ifdef BENCH
123            enq_s = rdtsc();
124#endif
125            // TODO change to TX flag
126            //printf("offset %lu lenght %lu valid_length %lu \n", offset, length, valid_length);
127            err = devq_enqueue(q, rid, offset, length, 0,
128                               valid_length, NETIF_TXFLAG | NETIF_TXFLAG_LAST);
129            if (err_is_fail(err)) {
130                break;
131            }
132#ifdef BENCH
133            enq_e = rdtsc();
134            tot_enq_tx += enq_e - enq_s;
135            num_enqueue_tx++;
136#endif
137            if ((num_rx % 1000000) == 0) {
138                end = rdtsc();
139                double time = ((double) end-start)/(tsc_per_ms*1000);
140                printf("Mbit/s %f during %f seconds \n",
141                      ((double)bytes*8)/(1000*1000*time), time);
142                printf("Num packets/s %f \n", (double) 1000000/time);
143#ifdef BENCH
144                printf("AVG deq_rx %f micro seconds\n", ((double) (tot_deq_rx/num_dequeue_rx)/(tsc_per_ms/1000)));
145                printf("AVG enq_rx %f micro seconds\n", ((double) (tot_enq_rx/num_enqueue_rx)/(tsc_per_ms/1000)));
146                printf("AVG deq_tx %f micro seconds\n", ((double) (tot_deq_tx/num_dequeue_tx)/(tsc_per_ms/1000)));
147                printf("AVG enq_tx %f micro seconds\n", ((double) (tot_enq_tx/num_enqueue_tx)/(tsc_per_ms/1000)));
148
149                tot_deq_rx = 0;
150                tot_deq_tx = 0;
151                tot_enq_rx = 0;
152                tot_enq_tx = 0;
153                num_enqueue_rx = 0;
154                num_enqueue_tx = 0;
155                num_dequeue_rx = 0;
156                num_dequeue_tx = 0;
157#endif
158                num_rx = 0;
159                bytes = 0;
160                start = rdtsc();
161            }
162        } else {
163            printf("Unknown flags %lx \n", flags);
164        }
165
166    }
167}
168
169int main(int argc, char *argv[])
170{
171    if (argc > 5) {
172        char* stop;
173        ip_dst = atoi(argv[1]);
174        mac_dst = strtoull(argv[2], &stop, 10);
175
176        port_src = atoi(argv[3]);
177        port_dst = atoi(argv[4]);
178        cardname = argv[5];
179    } else {
180        USER_PANIC("NO src or dst IP given \n");
181    }
182
183    errval_t err;
184    // Allocate memory
185    err = frame_alloc(&memory_rx, MEMORY_SIZE, NULL);
186    if (err_is_fail(err)){
187        USER_PANIC("Allocating cap failed \n");
188    }
189
190    // RX frame
191    err = invoke_frame_identify(memory_rx, &id);
192    if (err_is_fail(err)) {
193        USER_PANIC("Frame identify failed \n");
194    }
195
196    err = vspace_map_one_frame_attr(&va_rx, id.bytes, memory_rx,
197                                    VREGION_FLAGS_READ_WRITE, NULL, NULL);
198    if (err_is_fail(err)) {
199        USER_PANIC("Frame mapping failed \n");
200    }
201
202    phys_rx = id.base;
203
204    err = udp_create((struct udp_q**) &udp_q, cardname, port_src, port_dst,
205                     ip_dst, event_cb, true);
206    if (err_is_fail(err)) {
207        USER_PANIC("Queue creation failed \n");
208    }
209
210    err = devq_register(udp_q, memory_rx, &regid_rx);
211    if (err_is_fail(err)) {
212        USER_PANIC("Register failed \n");
213    }
214
215    for (int j = 0; j < NUM_BUF; j++) {
216        err = devq_enqueue(udp_q, regid_rx, j*RX_BUF_SIZE, RX_BUF_SIZE, 0, RX_BUF_SIZE,
217                           NETIF_RXFLAG);
218        if (err_is_fail(err)) {
219            USER_PANIC("Err %s \n", err_getstring(err));
220        }
221    }
222
223    err = sys_debug_get_tsc_per_ms(&tsc_per_ms);
224    assert(err_is_ok(err));
225
226    barrelfish_usleep(1000*1000*15);
227
228    if (use_irq) {
229        while (true) {
230            event_dispatch(get_default_waitset());
231        }
232    } else {
233        printf("Testing receiving UDP packets \n");
234        start = rdtsc();
235        while(true) {
236            event_cb(udp_q);
237        }
238    }
239
240}
241
242