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 <devif/queue_interface.h>
18#include <devif/backends/net/udp.h>
19#include <bench/bench.h>
20#include <net_interfaces/flags.h>
21#include <net/net_filter.h>
22
23//#define DEBUG(x...) printf("devif_test: " x)
24#define DEBUG(x...) do {} while (0)
25
26
27#define NUM_ENQ 512
28#define MEMORY_SIZE BASE_PAGE_SIZE*NUM_ENQ
29#define TX_BUF_SIZE 2048
30#define RX_BUF_SIZE 2048
31
32static uint32_t ip_dst;
33static uint64_t mac_dst;
34static uint16_t port_src;
35static uint16_t port_dst;
36
37static struct capref memory_rx;
38static struct capref memory_tx;
39static regionid_t regid_rx;
40static regionid_t regid_tx;
41static struct frame_identity id;
42static void* va_rx;
43static void* va_tx;
44
45static uint32_t num_tx = 0;
46static uint32_t num_rx = 0;
47static struct udp_q* udp_q;
48static const char* cardname;
49
50/*
51static void wait_for_interrupt(void)
52{
53    uint32_t tx = num_tx;
54
55    while(tx == num_tx) {
56        errval_t err = event_dispatch(get_default_waitset());
57        if (err_is_fail(err)) {
58            USER_PANIC_ERR(err, "error in event_dispatch for wait_for_interrupt");
59        }
60    }
61}
62*/
63
64static uint64_t total_rx = 0;
65static bool reg_done = false;
66
67static bool use_interrupts = false;
68
69
70static void event_cb(void* queue)
71{
72    struct devq* q = (struct devq*) udp_q;
73
74    errval_t err;
75
76    regionid_t rid;
77    genoffset_t offset;
78    genoffset_t length;
79    genoffset_t valid_data;
80    genoffset_t valid_length;
81    uint64_t flags;
82
83    err = SYS_ERR_OK;
84
85    uint64_t start = 0, end = 0;
86
87    if (!reg_done) {
88        return;
89    }
90
91    while (err == SYS_ERR_OK) {
92        start = rdtsc();
93        err = devq_dequeue(q, &rid, &offset, &length, &valid_data,
94                           &valid_length, &flags);
95        if (err_is_fail(err)) {
96            break;
97        }
98
99        if (flags & NETIF_TXFLAG) {
100            DEBUG("Received TX buffer back \n");
101            num_tx++;
102        } else if (flags & NETIF_RXFLAG) {
103            num_rx++;
104            DEBUG("Received RX buffer \n");
105            err = devq_enqueue(q, rid, offset, length, 0,
106                               0, NETIF_RXFLAG);
107            end = rdtsc();
108            total_rx += end - start;
109        } else {
110            printf("Unknown flags %lx \n", flags);
111        }
112    }
113}
114
115static void test_udp(void)
116{
117    errval_t err;
118    struct devq* q;
119
120    // create queue with interrupts
121    udp_create(&udp_q, cardname, port_src, port_dst,
122               ip_dst, event_cb, !use_interrupts);
123
124    q = (struct devq*) udp_q;
125
126    assert(q != NULL);
127
128    num_tx = 0;
129    num_rx = 0;
130    err = devq_register(q, memory_rx, &regid_rx);
131    if (err_is_fail(err)){
132        USER_PANIC("Registering memory to devq failed \n");
133    }
134
135    // inesrt buffers
136    for (int i = 0; i < NUM_ENQ; i++) {
137        err = devq_enqueue(q, regid_rx, i*(RX_BUF_SIZE), RX_BUF_SIZE,
138                           0, RX_BUF_SIZE,
139                           NETIF_RXFLAG);
140        if (err_is_fail(err)){
141            USER_PANIC("Devq enqueue RX buffer failed \n");
142        }
143    }
144
145
146    err = devq_register(q, memory_tx, &regid_tx);
147    if (err_is_fail(err)){
148        USER_PANIC("Registering memory to devq failed \n");
149    }
150
151    reg_done = true;
152    // write something into the buffers
153    char* data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
154                 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
155                 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
156    printf("Data length %zu \n", strlen(data));
157
158    for (int i = 0; i < NUM_ENQ; i++) {
159        udp_write_buffer(udp_q, regid_tx, i*(TX_BUF_SIZE),
160                         data, strlen(data));
161    }
162
163    uint64_t total = 0, start = 0, end = 0;
164    for (int z = 0; z < NUM_ENQ; z++) {
165
166        start = rdtsc();
167        for (int i = 0; i < NUM_ENQ; i++) {
168            err = devq_enqueue(q, regid_tx, i*(TX_BUF_SIZE), TX_BUF_SIZE,
169                               0, strlen(data), NETIF_TXFLAG | NETIF_TXFLAG_LAST);
170            if (err_is_fail(err)){
171                USER_PANIC("Devq enqueue failed \n");
172            }
173        }
174
175        while (num_tx < NUM_ENQ*z) {
176            if (use_interrupts) {
177                event_dispatch(get_default_waitset());
178            } else {
179                event_cb(q);
180            }
181        }
182
183        end = rdtsc();
184        total += end - start;
185    }
186    printf("Average %f cycles TX\n", (double)total/(NUM_ENQ*NUM_ENQ));
187    barrelfish_usleep(1000*1000);
188    printf("Testing receiving UDP packets \n");
189
190    for (int z = 0; z < NUM_ENQ; z++) {
191        while(num_rx < NUM_ENQ*z) {
192            if (use_interrupts) {
193                event_dispatch(get_default_waitset());
194            } else {
195                event_cb(q);
196            }
197        }
198    }
199
200    printf("Average %f cycles RX\n", (double)total_rx/(NUM_ENQ*NUM_ENQ));
201
202    err = devq_deregister(q, regid_rx, &memory_rx);
203    if (err_is_fail(err)){
204        printf("%s \n", err_getstring(err));
205        USER_PANIC("Devq deregister tx failed \n");
206    }
207
208    err = devq_deregister(q, regid_tx, &memory_tx);
209    if (err_is_fail(err)){
210        printf("%s \n", err_getstring(err));
211        USER_PANIC("Devq deregister tx failed \n");
212    }
213
214    printf("Receiving UDP packets done \n");
215    printf("SUCCESS: udp test ended \n");
216}
217
218int main(int argc, char *argv[])
219{
220    errval_t err;
221    // Allocate memory
222    err = frame_alloc(&memory_tx, MEMORY_SIZE, NULL);
223    if (err_is_fail(err)){
224        USER_PANIC("Allocating cap failed \n");
225    }
226
227    err = frame_alloc(&memory_rx, MEMORY_SIZE, NULL);
228    if (err_is_fail(err)){
229        USER_PANIC("Allocating cap failed \n");
230    }
231
232    // RX frame
233    err = invoke_frame_identify(memory_rx, &id);
234    if (err_is_fail(err)) {
235        USER_PANIC("Frame identify failed \n");
236    }
237
238    err = vspace_map_one_frame_attr(&va_rx, id.bytes, memory_rx,
239                                    VREGION_FLAGS_READ, NULL, NULL);
240    if (err_is_fail(err)) {
241        USER_PANIC("Frame mapping failed \n");
242    }
243
244    // RX frame
245    err = invoke_frame_identify(memory_tx, &id);
246    if (err_is_fail(err)) {
247        USER_PANIC("Frame identify failed \n");
248    }
249
250    err = vspace_map_one_frame_attr(&va_tx, id.bytes, memory_tx,
251                                    VREGION_FLAGS_READ_WRITE, NULL, NULL);
252    if (err_is_fail(err)) {
253        USER_PANIC("Frame mapping failed \n");
254    }
255
256    if (argc > 5) {
257        char* end;
258        ip_dst = atoi(argv[1]);
259        mac_dst = strtoull(argv[2], &end, 10);
260        port_src = atoi(argv[3]);
261        port_dst = atoi(argv[4]);
262        cardname = argv[5];
263    } else {
264        USER_PANIC("NO src or dst IP given \n");
265    }
266
267    barrelfish_usleep(1000*1000*15);
268
269    test_udp();
270}
271
272