1/**
2 * \file
3 * \brief LWIP test/demo code
4 */
5
6/*
7 * Copyright (c) 2013, University of Washington.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <assert.h>
17#include <barrelfish/barrelfish.h>
18#include <netif/e1000.h>
19#include <netif/etharp.h>
20#include <lwip/ip.h>
21#include <lwip/udp.h>
22
23static ether_terminate_queue ether_terminate_queue_ptr = NULL;
24static ether_get_mac_address_t ether_get_mac_address_ptr = NULL;
25static ether_transmit_pbuf_list_t ether_transmit_pbuf_list_ptr = NULL;
26static ether_get_tx_free_slots tx_free_slots_fn_ptr = NULL;
27static ether_handle_free_TX_slot handle_free_tx_slot_fn_ptr = NULL;
28static ether_rx_register_buffer rx_register_buffer_fn_ptr = NULL;
29static ether_rx_get_free_slots rx_get_free_slots_fn_ptr = NULL;
30
31uint64_t interrupt_counter = 0;
32uint64_t total_rx_p_count = 0;
33uint64_t total_rx_datasize = 0;
34struct client_closure *g_cl = NULL;
35
36#define MAX_PACKETS     256
37#define PACKET_SIZE     2048
38
39struct packet {
40    uint8_t     *payload;
41    lpaddr_t    pa;
42    size_t      len;
43};
44
45static struct packet rx_packets[MAX_PACKETS], tx_packets[MAX_PACKETS];
46
47void ethernetif_backend_init(char *service_name, uint64_t queueid,
48                             ether_get_mac_address_t get_mac_ptr,
49                             ether_terminate_queue terminate_queue_ptr,
50                             ether_transmit_pbuf_list_t transmit_ptr,
51                             ether_get_tx_free_slots tx_free_slots_ptr,
52                             ether_handle_free_TX_slot handle_free_tx_slot_ptr,
53                             size_t rx_bufsz,
54                             ether_rx_register_buffer rx_register_buffer_ptr,
55                             ether_rx_get_free_slots rx_get_free_slots_ptr)
56{
57    ether_terminate_queue_ptr = terminate_queue_ptr;
58    ether_get_mac_address_ptr = get_mac_ptr;
59    ether_transmit_pbuf_list_ptr = transmit_ptr;
60    tx_free_slots_fn_ptr = tx_free_slots_ptr;
61    handle_free_tx_slot_fn_ptr = handle_free_tx_slot_ptr;
62    rx_register_buffer_fn_ptr = rx_register_buffer_ptr;
63    rx_get_free_slots_fn_ptr = rx_get_free_slots_ptr;
64    /* printf("PBUF_POOL_BUFSIZE = %u, rx buffer size = %zu\n", PBUF_POOL_BUFSIZE, */
65    /*        rx_bufsz); */
66}
67
68static struct packet *get_tx_packet(void)
69{
70    static unsigned int idx = 0;
71    struct packet *p = &tx_packets[idx];
72
73    // Busy-wait until packet not in flight
74    while(p->len != 0) {
75        handle_free_tx_slot_fn_ptr();
76    }
77
78    idx = (idx + 1) % MAX_PACKETS;
79    return p;
80}
81
82static void packet_output(struct packet *p)
83{
84    struct driver_buffer buf;
85
86    buf.pa = p->pa;
87    buf.va = p->payload;
88    buf.len = p->len;
89    buf.flags = 0;
90    buf.opaque = p;
91
92    errval_t err = ether_transmit_pbuf_list_ptr(&buf, 1);
93    assert(err_is_ok(err));
94}
95
96#include <barrelfish/sys_debug.h>
97
98// This is roughly Mon Apr 25 13:50 CEST 2011
99#define TOD_OFFSET      1303732456ULL
100
101int gettimeofday(struct timeval *tv, struct timezone *tz)
102{
103    uint64_t now = rdtsc();
104    static uint64_t tscperms = 0;
105
106    if(tscperms == 0) {
107        errval_t err = sys_debug_get_tsc_per_ms(&tscperms);
108        assert(err_is_ok(err));
109        assert(tscperms >= 1000);
110    }
111
112    uint64_t tod_us = (TOD_OFFSET * 1000000) + (now / (tscperms / 1000));
113
114    if(tv != NULL) {
115        tv->tv_sec = tod_us / 1000000;
116        tv->tv_usec = tod_us % 1000000;
117    }
118
119    assert(tz == NULL);
120    if(tz != NULL) {
121    }
122
123    return 0;
124}
125
126#define MAX_STAMPS      10000
127
128static uint64_t tstamp[MAX_STAMPS];
129static int stamps = 0;
130
131void process_received_packet(struct driver_rx_buffer *buffer, size_t count,
132                             uint64_t flags)
133{
134    uint64_t instamp = rdtsc();
135
136    struct packet *p = buffer->opaque;
137    assert(p != NULL);
138    assert(count == 1);
139    p->len = buffer->len;
140
141    /* printf("Incoming packet\n"); */
142
143    // Drop packets with invalid checksums
144    if(flags & NETIF_RXFLAG_IPCHECKSUM) {
145        if(!(flags & NETIF_RXFLAG_IPCHECKSUM_GOOD)) {
146            goto out;
147        }
148    }
149
150    if(flags & NETIF_RXFLAG_L4CHECKSUM) {
151        if(!(flags & NETIF_RXFLAG_L4CHECKSUM_GOOD)) {
152            goto out;
153        }
154    }
155
156    /* printf("Checksum good\n"); */
157
158    struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
159    switch (htons(ethhdr->type)) {
160    case ETHTYPE_ARP:
161        {
162            /* printf("Is an ARP packet\n"); */
163            struct etharp_hdr *arphdr = (struct etharp_hdr *)(p->payload + SIZEOF_ETH_HDR);
164            struct eth_addr mymac;
165            bool ourarp = false;
166
167            if(htons(arphdr->opcode) == ARP_REQUEST) {
168                // 10.0.2.15
169                if(htons(arphdr->dipaddr.addrw[0]) == 0x0a00 &&
170                   htons(arphdr->dipaddr.addrw[1]) == 0x020f) {
171                    memcpy(&mymac.addr, "\x52\x54\x00\x12\x34\x56", ETHARP_HWADDR_LEN);
172                    ourarp = true;
173                } else if(htons(arphdr->dipaddr.addrw[0]) == 0x80d0 &&
174                          htons(arphdr->dipaddr.addrw[1]) == 0x0643) {
175                    memcpy(&mymac.addr, "\xa0\x36\x9f\x10\x00\xa6", ETHARP_HWADDR_LEN);
176                    ourarp = true;
177                }
178            }
179
180            if(ourarp) {
181                /* printf("ARP request for us\n"); */
182                // Send reply
183                struct packet *outp = get_tx_packet();
184                struct eth_hdr *myeth = (struct eth_hdr *)outp->payload;
185                struct etharp_hdr *myarp = (struct etharp_hdr *)(outp->payload + SIZEOF_ETH_HDR);
186
187                // ETH header
188                memcpy(&myeth->dest, &arphdr->shwaddr, ETHARP_HWADDR_LEN);
189                memcpy(&myeth->src, &mymac, ETHARP_HWADDR_LEN);
190                myeth->type = htons(ETHTYPE_ARP);
191
192                // ARP header
193                myarp->hwtype = htons(1);
194                myarp->proto = htons(ETHTYPE_IP);
195                myarp->hwlen = 6;
196                myarp->protolen = 4;
197                myarp->opcode = htons(ARP_REPLY);
198                memcpy(&myarp->shwaddr, &mymac, ETHARP_HWADDR_LEN);
199                memcpy(&myarp->sipaddr, &arphdr->dipaddr, sizeof(myarp->sipaddr));
200                memcpy(&myarp->dhwaddr, &arphdr->shwaddr, ETHARP_HWADDR_LEN);
201                memcpy(&myarp->dipaddr, &arphdr->sipaddr, sizeof(myarp->dipaddr));
202
203                outp->len = p->len;
204                packet_output(outp);
205            }
206        }
207        break;
208
209    case ETHTYPE_IP:
210        {
211            struct ip_hdr *iphdr = (struct ip_hdr *)(p->payload + SIZEOF_ETH_HDR);
212
213            /* printf("Is an IP packet, type %x\n", IPH_PROTO(iphdr)); */
214
215            if(IPH_PROTO(iphdr) == IP_PROTO_UDP) {
216                struct udp_hdr *udphdr = (struct udp_hdr *)(p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4));
217                uint8_t *payload = p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4) + sizeof(struct udp_hdr);
218
219                /* printf("Got UDP packet, dest IP %x, dest port %u\n", */
220                /*        iphdr->dest.addr, udphdr->dest); */
221
222                if(htonl(iphdr->dest.addr) != 0x80d00643 ||
223                   htons(udphdr->dest) != 1234) {
224                    goto out;
225                }
226
227                /* printf("payload '%s'\n", payload); */
228
229                struct packet *outp = get_tx_packet();
230                struct eth_hdr *myeth = (struct eth_hdr *)outp->payload;
231                struct ip_hdr *myip = (struct ip_hdr *)(outp->payload + SIZEOF_ETH_HDR);
232                struct udp_hdr *myudp = (struct udp_hdr *)(outp->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4));
233                uint8_t *mypayload = outp->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4) + sizeof(struct udp_hdr);
234
235                // ETH header
236                memcpy(&myeth->dest, &ethhdr->src, ETHARP_HWADDR_LEN);
237                memcpy(&myeth->src, &ethhdr->dest, ETHARP_HWADDR_LEN);
238                myeth->type = htons(ETHTYPE_IP);
239
240                // IP header
241                memcpy(myip, iphdr, sizeof(struct ip_hdr));
242                memcpy(&myip->src, &iphdr->dest, sizeof(ip_addr_p_t));
243                memcpy(&myip->dest, &iphdr->src, sizeof(ip_addr_p_t));
244
245                // UDP header
246                memcpy(myudp, udphdr, sizeof(struct udp_hdr));
247                myudp->src = udphdr->dest;
248                myudp->dest = udphdr->src;
249
250                // Payload
251                memcpy(mypayload, payload, htons(udphdr->len) - 8);
252
253                outp->len = p->len;
254                packet_output(outp);
255
256                uint64_t now = rdtsc();
257                tstamp[stamps] = now - instamp;
258
259                /* printf("got packet %d\n", stamps); */
260
261                stamps++;
262                if(stamps == MAX_STAMPS) {
263                    printf("latencies:\n");
264                    for(int i = 0; i < MAX_STAMPS; i++) {
265                        printf("%" PRIu64 " cycles\n", tstamp[i]);
266                    }
267                    stamps = 0;
268                }
269
270            }
271        }
272        break;
273
274    default:
275        break;
276    }
277
278 out:
279    {
280        //now we have consumed the preregistered pbuf containing a received packet
281        //which was processed in this function. Therefore we have to register a new
282        //free buffer for receiving packets.
283        errval_t err = rx_register_buffer_fn_ptr(p->pa, p->payload, p);
284        assert(err_is_ok(err));
285    }
286}
287
288bool handle_tx_done(void *opaque)
289{
290    struct packet *p = opaque;
291    p->len = 0;
292    return true;
293}
294
295/* allocate a single frame, mapping it into our vspace with given attributes */
296static void *alloc_map_frame(vregion_flags_t attr, size_t size, struct capref *retcap)
297{
298    struct capref frame;
299    errval_t r;
300
301    r = frame_alloc(&frame, size, NULL);
302    assert(err_is_ok(r));
303    void *va;
304    r = vspace_map_one_frame_attr(&va, size, frame, attr,
305                                  NULL, NULL);
306    if (err_is_fail(r)) {
307        DEBUG_ERR(r, "vspace_map_one_frame failed");
308        return NULL;
309    }
310
311    if (retcap != NULL) {
312        *retcap = frame;
313    }
314
315    return va;
316}
317
318int main(int argc, char *argv[])
319{
320    uint8_t mac[6];
321
322    printf("Starting e10k test program...\n");
323
324    e1000n_driver_init(argc, argv);
325
326    ether_get_mac_address_ptr(mac);
327    printf("e10ktest MAC address %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
328           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
329
330    struct capref frame;
331    uint8_t *ram_base = alloc_map_frame(VREGION_FLAGS_READ_WRITE,
332                                        MAX_PACKETS * PACKET_SIZE, &frame);
333    assert(ram_base != NULL);
334
335    struct frame_identity id;
336    errval_t err = invoke_frame_identify(frame, &id);
337    assert(err_is_ok(err));
338
339    // Add buffers to RX ring for packet reception
340    for(int i = 0; i < MAX_PACKETS; i++) {
341        struct packet *p = &rx_packets[i];
342
343        p->payload = ram_base + (i * PACKET_SIZE);
344        p->pa = id.base + (i * PACKET_SIZE);
345        p->len = PACKET_SIZE;
346
347        err = rx_register_buffer_fn_ptr(p->pa, p->payload, p);
348        assert(err_is_ok(err));
349    }
350
351    // Setup TX packets
352    ram_base = alloc_map_frame(VREGION_FLAGS_READ_WRITE,
353                               MAX_PACKETS * PACKET_SIZE, &frame);
354    assert(ram_base != NULL);
355    err = invoke_frame_identify(frame, &id);
356    assert(err_is_ok(err));
357    for(int i = 0; i < MAX_PACKETS; i++) {
358        struct packet *p = &tx_packets[i];
359        p->payload = ram_base + (i * PACKET_SIZE);
360        p->pa = id.base + (i * PACKET_SIZE);
361        p->len = 0;
362    }
363
364    for(;;) {
365        e1000n_polling_loop(get_default_waitset());
366    }
367
368    return 0;
369}
370