1254721Semaste/**
2254721Semaste * \file
3254721Semaste * \brief LWIP test/demo code
4254721Semaste */
5254721Semaste
6254721Semaste/*
7254721Semaste * Copyright (c) 2013, University of Washington.
8254721Semaste * All rights reserved.
9254721Semaste *
10254721Semaste * This file is distributed under the terms in the attached LICENSE file.
11254721Semaste * If you do not find this file, copies can be found by writing to:
12254721Semaste * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13254721Semaste */
14254721Semaste
15254721Semaste#include <stdio.h>
16254721Semaste#include <assert.h>
17254721Semaste#include <barrelfish/barrelfish.h>
18254721Semaste#include <netif/e1000.h>
19254721Semaste#include <netif/etharp.h>
20254721Semaste#include <lwip/ip.h>
21254721Semaste#include <lwip/udp.h>
22254721Semaste
23254721Semastestatic ether_terminate_queue ether_terminate_queue_ptr = NULL;
24254721Semastestatic ether_get_mac_address_t ether_get_mac_address_ptr = NULL;
25254721Semastestatic ether_transmit_pbuf_list_t ether_transmit_pbuf_list_ptr = NULL;
26254721Semastestatic ether_get_tx_free_slots tx_free_slots_fn_ptr = NULL;
27254721Semastestatic ether_handle_free_TX_slot handle_free_tx_slot_fn_ptr = NULL;
28254721Semastestatic ether_rx_register_buffer rx_register_buffer_fn_ptr = NULL;
29254721Semastestatic ether_rx_get_free_slots rx_get_free_slots_fn_ptr = NULL;
30254721Semaste
31254721Semasteuint64_t interrupt_counter = 0;
32254721Semasteuint64_t total_rx_p_count = 0;
33254721Semasteuint64_t total_rx_datasize = 0;
34254721Semastestruct client_closure *g_cl = NULL;
35254721Semaste
36254721Semaste#define MAX_PACKETS     256
37254721Semaste#define PACKET_SIZE     2048
38254721Semaste
39254721Semastestruct packet {
40254721Semaste    uint8_t     *payload;
41254721Semaste    lpaddr_t    pa;
42254721Semaste    size_t      len;
43254721Semaste};
44254721Semaste
45254721Semastestatic struct packet rx_packets[MAX_PACKETS], tx_packets[MAX_PACKETS];
46254721Semaste
47254721Semastevoid ethernetif_backend_init(char *service_name, uint64_t queueid,
48254721Semaste                             ether_get_mac_address_t get_mac_ptr,
49254721Semaste                             ether_terminate_queue terminate_queue_ptr,
50254721Semaste                             ether_transmit_pbuf_list_t transmit_ptr,
51254721Semaste                             ether_get_tx_free_slots tx_free_slots_ptr,
52254721Semaste                             ether_handle_free_TX_slot handle_free_tx_slot_ptr,
53254721Semaste                             size_t rx_bufsz,
54254721Semaste                             ether_rx_register_buffer rx_register_buffer_ptr,
55254721Semaste                             ether_rx_get_free_slots rx_get_free_slots_ptr)
56254721Semaste{
57254721Semaste    ether_terminate_queue_ptr = terminate_queue_ptr;
58254721Semaste    ether_get_mac_address_ptr = get_mac_ptr;
59254721Semaste    ether_transmit_pbuf_list_ptr = transmit_ptr;
60254721Semaste    tx_free_slots_fn_ptr = tx_free_slots_ptr;
61254721Semaste    handle_free_tx_slot_fn_ptr = handle_free_tx_slot_ptr;
62254721Semaste    rx_register_buffer_fn_ptr = rx_register_buffer_ptr;
63254721Semaste    rx_get_free_slots_fn_ptr = rx_get_free_slots_ptr;
64254721Semaste    /* printf("PBUF_POOL_BUFSIZE = %u, rx buffer size = %zu\n", PBUF_POOL_BUFSIZE, */
65254721Semaste    /*        rx_bufsz); */
66254721Semaste}
67254721Semaste
68254721Semastestatic struct packet *get_tx_packet(void)
69254721Semaste{
70254721Semaste    static unsigned int idx = 0;
71254721Semaste    struct packet *p = &tx_packets[idx];
72254721Semaste
73254721Semaste    // Busy-wait until packet not in flight
74254721Semaste    while(p->len != 0) {
75254721Semaste        handle_free_tx_slot_fn_ptr();
76254721Semaste    }
77254721Semaste
78254721Semaste    idx = (idx + 1) % MAX_PACKETS;
79254721Semaste    return p;
80254721Semaste}
81254721Semaste
82254721Semastestatic void packet_output(struct packet *p)
83254721Semaste{
84254721Semaste    struct driver_buffer buf;
85254721Semaste
86254721Semaste    buf.pa = p->pa;
87254721Semaste    buf.va = p->payload;
88254721Semaste    buf.len = p->len;
89254721Semaste    buf.flags = 0;
90254721Semaste    buf.opaque = p;
91254721Semaste
92254721Semaste    errval_t err = ether_transmit_pbuf_list_ptr(&buf, 1);
93254721Semaste    assert(err_is_ok(err));
94254721Semaste}
95254721Semaste
96254721Semaste#include <barrelfish/sys_debug.h>
97254721Semaste
98254721Semaste// This is roughly Mon Apr 25 13:50 CEST 2011
99254721Semaste#define TOD_OFFSET      1303732456ULL
100254721Semaste
101254721Semasteint gettimeofday(struct timeval *tv, struct timezone *tz)
102254721Semaste{
103254721Semaste    uint64_t now = rdtsc();
104254721Semaste    static uint64_t tscperms = 0;
105254721Semaste
106254721Semaste    if(tscperms == 0) {
107254721Semaste        errval_t err = sys_debug_get_tsc_per_ms(&tscperms);
108254721Semaste        assert(err_is_ok(err));
109254721Semaste        assert(tscperms >= 1000);
110254721Semaste    }
111254721Semaste
112254721Semaste    uint64_t tod_us = (TOD_OFFSET * 1000000) + (now / (tscperms / 1000));
113254721Semaste
114254721Semaste    if(tv != NULL) {
115254721Semaste        tv->tv_sec = tod_us / 1000000;
116254721Semaste        tv->tv_usec = tod_us % 1000000;
117254721Semaste    }
118254721Semaste
119254721Semaste    assert(tz == NULL);
120254721Semaste    if(tz != NULL) {
121254721Semaste    }
122254721Semaste
123254721Semaste    return 0;
124254721Semaste}
125254721Semaste
126254721Semaste#define MAX_STAMPS      10000
127254721Semaste
128254721Semastestatic uint64_t tstamp[MAX_STAMPS];
129254721Semastestatic int stamps = 0;
130254721Semaste
131254721Semastevoid process_received_packet(struct driver_rx_buffer *buffer, size_t count,
132254721Semaste                             uint64_t flags)
133254721Semaste{
134254721Semaste    uint64_t instamp = rdtsc();
135254721Semaste
136254721Semaste    struct packet *p = buffer->opaque;
137254721Semaste    assert(p != NULL);
138254721Semaste    assert(count == 1);
139254721Semaste    p->len = buffer->len;
140254721Semaste
141254721Semaste    /* printf("Incoming packet\n"); */
142254721Semaste
143254721Semaste    // Drop packets with invalid checksums
144254721Semaste    if(flags & NETIF_RXFLAG_IPCHECKSUM) {
145254721Semaste        if(!(flags & NETIF_RXFLAG_IPCHECKSUM_GOOD)) {
146254721Semaste            goto out;
147254721Semaste        }
148254721Semaste    }
149254721Semaste
150254721Semaste    if(flags & NETIF_RXFLAG_L4CHECKSUM) {
151254721Semaste        if(!(flags & NETIF_RXFLAG_L4CHECKSUM_GOOD)) {
152254721Semaste            goto out;
153254721Semaste        }
154254721Semaste    }
155254721Semaste
156254721Semaste    /* printf("Checksum good\n"); */
157254721Semaste
158254721Semaste    struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
159254721Semaste    switch (htons(ethhdr->type)) {
160254721Semaste    case ETHTYPE_ARP:
161254721Semaste        {
162254721Semaste            /* printf("Is an ARP packet\n"); */
163254721Semaste            struct etharp_hdr *arphdr = (struct etharp_hdr *)(p->payload + SIZEOF_ETH_HDR);
164254721Semaste            struct eth_addr mymac;
165254721Semaste            bool ourarp = false;
166254721Semaste
167254721Semaste            if(htons(arphdr->opcode) == ARP_REQUEST) {
168254721Semaste                // 10.0.2.15
169254721Semaste                if(htons(arphdr->dipaddr.addrw[0]) == 0x0a00 &&
170254721Semaste                   htons(arphdr->dipaddr.addrw[1]) == 0x020f) {
171254721Semaste                    memcpy(&mymac.addr, "\x52\x54\x00\x12\x34\x56", ETHARP_HWADDR_LEN);
172254721Semaste                    ourarp = true;
173254721Semaste                } else if(htons(arphdr->dipaddr.addrw[0]) == 0x80d0 &&
174254721Semaste                          htons(arphdr->dipaddr.addrw[1]) == 0x0643) {
175254721Semaste                    memcpy(&mymac.addr, "\xa0\x36\x9f\x10\x00\xa6", ETHARP_HWADDR_LEN);
176254721Semaste                    ourarp = true;
177254721Semaste                }
178254721Semaste            }
179254721Semaste
180254721Semaste            if(ourarp) {
181254721Semaste                /* printf("ARP request for us\n"); */
182254721Semaste                // Send reply
183254721Semaste                struct packet *outp = get_tx_packet();
184254721Semaste                struct eth_hdr *myeth = (struct eth_hdr *)outp->payload;
185254721Semaste                struct etharp_hdr *myarp = (struct etharp_hdr *)(outp->payload + SIZEOF_ETH_HDR);
186254721Semaste
187254721Semaste                // ETH header
188254721Semaste                memcpy(&myeth->dest, &arphdr->shwaddr, ETHARP_HWADDR_LEN);
189254721Semaste                memcpy(&myeth->src, &mymac, ETHARP_HWADDR_LEN);
190254721Semaste                myeth->type = htons(ETHTYPE_ARP);
191254721Semaste
192254721Semaste                // ARP header
193254721Semaste                myarp->hwtype = htons(1);
194254721Semaste                myarp->proto = htons(ETHTYPE_IP);
195254721Semaste                myarp->hwlen = 6;
196254721Semaste                myarp->protolen = 4;
197254721Semaste                myarp->opcode = htons(ARP_REPLY);
198254721Semaste                memcpy(&myarp->shwaddr, &mymac, ETHARP_HWADDR_LEN);
199254721Semaste                memcpy(&myarp->sipaddr, &arphdr->dipaddr, sizeof(myarp->sipaddr));
200254721Semaste                memcpy(&myarp->dhwaddr, &arphdr->shwaddr, ETHARP_HWADDR_LEN);
201254721Semaste                memcpy(&myarp->dipaddr, &arphdr->sipaddr, sizeof(myarp->dipaddr));
202254721Semaste
203254721Semaste                outp->len = p->len;
204254721Semaste                packet_output(outp);
205254721Semaste            }
206254721Semaste        }
207254721Semaste        break;
208254721Semaste
209254721Semaste    case ETHTYPE_IP:
210254721Semaste        {
211254721Semaste            struct ip_hdr *iphdr = (struct ip_hdr *)(p->payload + SIZEOF_ETH_HDR);
212254721Semaste
213254721Semaste            /* printf("Is an IP packet, type %x\n", IPH_PROTO(iphdr)); */
214254721Semaste
215254721Semaste            if(IPH_PROTO(iphdr) == IP_PROTO_UDP) {
216254721Semaste                struct udp_hdr *udphdr = (struct udp_hdr *)(p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4));
217254721Semaste                uint8_t *payload = p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4) + sizeof(struct udp_hdr);
218254721Semaste
219254721Semaste                /* printf("Got UDP packet, dest IP %x, dest port %u\n", */
220254721Semaste                /*        iphdr->dest.addr, udphdr->dest); */
221254721Semaste
222254721Semaste                if(htonl(iphdr->dest.addr) != 0x80d00643 ||
223254721Semaste                   htons(udphdr->dest) != 1234) {
224254721Semaste                    goto out;
225254721Semaste                }
226254721Semaste
227254721Semaste                /* printf("payload '%s'\n", payload); */
228254721Semaste
229254721Semaste                struct packet *outp = get_tx_packet();
230254721Semaste                struct eth_hdr *myeth = (struct eth_hdr *)outp->payload;
231254721Semaste                struct ip_hdr *myip = (struct ip_hdr *)(outp->payload + SIZEOF_ETH_HDR);
232254721Semaste                struct udp_hdr *myudp = (struct udp_hdr *)(outp->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4));
233254721Semaste                uint8_t *mypayload = outp->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4) + sizeof(struct udp_hdr);
234254721Semaste
235254721Semaste                // ETH header
236254721Semaste                memcpy(&myeth->dest, &ethhdr->src, ETHARP_HWADDR_LEN);
237254721Semaste                memcpy(&myeth->src, &ethhdr->dest, ETHARP_HWADDR_LEN);
238254721Semaste                myeth->type = htons(ETHTYPE_IP);
239254721Semaste
240254721Semaste                // IP header
241254721Semaste                memcpy(myip, iphdr, sizeof(struct ip_hdr));
242254721Semaste                memcpy(&myip->src, &iphdr->dest, sizeof(ip_addr_p_t));
243254721Semaste                memcpy(&myip->dest, &iphdr->src, sizeof(ip_addr_p_t));
244254721Semaste
245254721Semaste                // UDP header
246254721Semaste                memcpy(myudp, udphdr, sizeof(struct udp_hdr));
247254721Semaste                myudp->src = udphdr->dest;
248254721Semaste                myudp->dest = udphdr->src;
249254721Semaste
250254721Semaste                // Payload
251254721Semaste                memcpy(mypayload, payload, htons(udphdr->len) - 8);
252254721Semaste
253254721Semaste                outp->len = p->len;
254254721Semaste                packet_output(outp);
255254721Semaste
256254721Semaste                uint64_t now = rdtsc();
257254721Semaste                tstamp[stamps] = now - instamp;
258254721Semaste
259254721Semaste                /* printf("got packet %d\n", stamps); */
260254721Semaste
261254721Semaste                stamps++;
262254721Semaste                if(stamps == MAX_STAMPS) {
263254721Semaste                    printf("latencies:\n");
264254721Semaste                    for(int i = 0; i < MAX_STAMPS; i++) {
265254721Semaste                        printf("%" PRIu64 " cycles\n", tstamp[i]);
266254721Semaste                    }
267254721Semaste                    stamps = 0;
268254721Semaste                }
269254721Semaste
270254721Semaste            }
271254721Semaste        }
272254721Semaste        break;
273254721Semaste
274254721Semaste    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 = 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 = 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