1/*
2 * Copyright (c) 2017, 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, Universitaetstrasse 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <stdbool.h>
13#include <barrelfish/barrelfish.h>
14#include <barrelfish/waitset.h>
15#include <barrelfish/deferred.h>
16#include <devif/queue_interface.h>
17#include <devif/queue_interface_backend.h>
18#include <devif/backends/net/ip.h>
19#include <lwip/inet_chksum.h>
20#include <lwip/lwip/inet.h>
21#include <net_interfaces/flags.h>
22#include <net/net.h>
23#include <net/net_queue.h>
24#include <net/net_filter.h>
25#include <net/dhcp.h>
26#include <net/arp.h>
27#include "../headers.h"
28
29#include <bench/bench.h>
30
31#define MAX_NUM_REGIONS 64
32
33//#define DEBUG_ENABLED
34
35#if defined(DEBUG_ENABLED)
36#define DEBUG(x...) do { printf("IP_QUEUE: %s.%d:%s:%d: ", \
37            disp_name(), disp_get_core_id(), __func__, __LINE__); \
38                printf(x);\
39        } while (0)
40
41#else
42#define DEBUG(x...) ((void)0)
43#endif
44
45struct region_vaddr {
46    void* va;
47    regionid_t rid;
48};
49
50struct pkt_ip_headers {
51    struct eth_hdr eth;
52    struct ip_hdr ip;
53} __attribute__ ((packed));
54
55struct ip_q {
56    struct devq my_q;
57    struct devq* q;
58    struct capref filter_ep; // connection to cards filter interface
59    struct pkt_ip_headers header; // can fill in this header and reuse it by copying
60    struct region_vaddr regions[MAX_NUM_REGIONS];
61    struct net_filter_state* filter;
62    uint16_t hdr_len;
63
64    const char* name;
65#ifdef BENCH
66    bench_ctl_t en_rx;
67    bench_ctl_t en_tx;
68    bench_ctl_t deq_rx;
69    bench_ctl_t deq_tx;
70#endif
71};
72
73
74#ifdef DEBUG_ENABLED
75static void print_buffer(struct ip_q* q, void* start, uint64_t len)
76{
77    uint8_t* buf = (uint8_t*) start;
78    printf("Packet in region at address %p len %zu \n",
79           buf, len);
80    for (int i = 0; i < len; i+=2) {
81        if (((i % 16) == 0) && i > 0) {
82            printf("\n");
83        }
84        printf("%2X", buf[i]);
85        printf("%2X ", buf[i+1]);
86    }
87    printf("\n");
88}
89#endif
90
91static errval_t ip_register(struct devq* q, struct capref cap,
92                            regionid_t rid)
93{
94
95    errval_t err;
96    struct frame_identity frameid = { .base = 0, .bytes = 0 };
97
98    struct ip_q* que = (struct ip_q*) q;
99
100    // Map device registers
101    err = frame_identify(cap, &frameid);
102    assert(err_is_ok(err));
103
104    err = vspace_map_one_frame_attr(&que->regions[rid % MAX_NUM_REGIONS].va,
105                                    frameid.bytes, cap, VREGION_FLAGS_READ_WRITE,
106                                    NULL, NULL);
107    if (err_is_fail(err)) {
108        DEBUG_ERR(err, "vspace_map_one_frame failed");
109        return err;
110    }
111    que->regions[rid % MAX_NUM_REGIONS].rid = rid;
112    DEBUG("id-%d va-%p \n", que->regions[rid % MAX_NUM_REGIONS].rid,
113          que->regions[rid % MAX_NUM_REGIONS].va);
114
115    return que->q->f.reg(que->q, cap, rid);
116}
117
118static errval_t ip_deregister(struct devq* q, regionid_t rid)
119{
120
121    struct ip_q* que = (struct ip_q*) q;
122    que->regions[rid % MAX_NUM_REGIONS].va = NULL;
123    que->regions[rid % MAX_NUM_REGIONS].rid = 0;
124    return que->q->f.dereg(que->q, rid);
125}
126
127
128static errval_t ip_control(struct devq* q, uint64_t cmd, uint64_t value,
129                           uint64_t* result)
130{
131    struct ip_q* que = (struct ip_q*) q;
132    return que->q->f.ctrl(que->q, cmd, value, result);
133}
134
135
136static errval_t ip_notify(struct devq* q)
137{
138    struct ip_q* que = (struct ip_q*) q;
139    return que->q->f.notify(que->q);
140}
141
142static errval_t ip_enqueue(struct devq* q, regionid_t rid,
143                           genoffset_t offset, genoffset_t length,
144                           genoffset_t valid_data, genoffset_t valid_length,
145                           uint64_t flags)
146{
147
148    // for now limit length
149    //  TODO fragmentation
150
151    struct ip_q* que = (struct ip_q*) q;
152    if (flags & NETIF_TXFLAG) {
153
154        DEBUG("TX rid: %d offset %ld length %ld valid_length %ld \n", rid, offset,
155              length, valid_length);
156        assert(valid_length <= 1500);
157        que->header.ip._len = htons(valid_length + IP_HLEN);
158        que->header.ip._chksum = inet_chksum(&que->header, IP_HLEN);
159
160        assert(que->regions[rid % MAX_NUM_REGIONS].va != NULL);
161
162        uint8_t* start = (uint8_t*) que->regions[rid % MAX_NUM_REGIONS].va +
163                         offset + valid_data;
164
165        memcpy(start, &que->header, sizeof(que->header));
166
167#ifdef BENCH
168        uint64_t b_start, b_end;
169        errval_t err;
170
171        b_start = rdtscp();
172        err = que->q->f.enq(que->q, rid, offset, length, valid_data,
173                            valid_length+sizeof(struct pkt_ip_headers), flags);
174        b_end = rdtscp();
175        if (err_is_ok(err)) {
176            uint64_t res = b_end - b_start;
177            bench_ctl_add_run(&que->en_tx, &res);
178        }
179        return err;
180#else
181        return que->q->f.enq(que->q, rid, offset, length, valid_data,
182                             valid_length+sizeof(struct pkt_ip_headers), flags);
183#endif
184    }
185
186    if (flags & NETIF_RXFLAG) {
187        assert(valid_length <= 2048);
188        DEBUG("RX rid: %d offset %ld length %ld valid_length %ld \n", rid, offset,
189              length, valid_length);
190#ifdef BENCH
191        uint64_t start, end;
192        errval_t err;
193
194        start = rdtscp();
195        err = que->q->f.enq(que->q, rid, offset, length, valid_data,
196                             valid_length, flags);
197        end = rdtscp();
198        if (err_is_ok(err)) {
199            uint64_t res = end - start;
200            bench_ctl_add_run(&que->en_rx, &res);
201        }
202        return err;
203#else
204        return que->q->f.enq(que->q, rid, offset, length, valid_data,
205                             valid_length, flags);
206#endif
207    }
208
209    return NET_QUEUE_ERR_UNKNOWN_BUF_TYPE;
210}
211
212static errval_t ip_dequeue(struct devq* q, regionid_t* rid, genoffset_t* offset,
213                           genoffset_t* length, genoffset_t* valid_data,
214                           genoffset_t* valid_length, uint64_t* flags)
215{
216    errval_t err;
217    struct ip_q* que = (struct ip_q*) q;
218
219#ifdef BENCH
220    uint64_t start, end;
221    start = rdtscp();
222    err = que->q->f.deq(que->q, rid, offset, length, valid_data, valid_length, flags);
223    end = rdtscp();
224    if (err_is_fail(err)) {
225        return err;
226    }
227#else
228    err = que->q->f.deq(que->q, rid, offset, length, valid_data, valid_length, flags);
229    if (err_is_fail(err)) {
230        return err;
231    }
232#endif
233
234    if (*flags & NETIF_RXFLAG) {
235        DEBUG("RX rid: %d offset %ld valid_data %ld length %ld va %p \n", *rid,
236              *offset, *valid_data,
237              *valid_length, que->regions[*rid % MAX_NUM_REGIONS].va + *offset + *valid_data);
238
239        struct pkt_ip_headers* header = (struct pkt_ip_headers*)
240                                         (que->regions[*rid % MAX_NUM_REGIONS].va +
241                                         *offset + *valid_data);
242
243        // IP checksum
244        if (header->ip._chksum == inet_chksum(&header->ip, IP_HLEN)) {
245            printf("IP queue: dropping packet wrong checksum \n");
246            err = que->q->f.enq(que->q, *rid, *offset, *length, 0, 0, NETIF_RXFLAG);
247            return err_push(err, NET_QUEUE_ERR_CHECKSUM);
248        }
249
250        // Correct ip for this queue?
251        if (header->ip.src != que->header.ip.dest) {
252            printf("IP queue: dropping packet, wrong IP is %"PRIu32" should be %"PRIu32"\n",
253                   header->ip.src, que->header.ip.dest);
254            err = que->q->f.enq(que->q, *rid, *offset, *length, 0, 0, NETIF_RXFLAG);
255            return err_push(err, NET_QUEUE_ERR_WRONG_IP);
256        }
257
258#ifdef DEBUG_ENABLED
259        print_buffer(que, que->regions[*rid % MAX_NUM_REGIONS].va + *offset, *valid_length);
260#endif
261
262        *valid_data = IP_HLEN + ETH_HLEN;
263        *valid_length = ntohs(header->ip._len) - IP_HLEN;
264        //print_buffer(que, que->regions[*rid % MAX_NUM_REGIONS].va + *offset+ *valid_data, *valid_length);
265        //
266
267#ifdef BENCH
268        uint64_t res = end - start;
269        bench_ctl_add_run(&que->deq_rx, &res);
270#endif
271        return SYS_ERR_OK;
272    }
273
274    DEBUG("TX rid: %d offset %ld length %ld \n", *rid, *offset,
275          *valid_length);
276
277#ifdef BENCH
278        uint64_t res = end - start;
279        bench_ctl_add_run(&que->deq_tx, &res);
280#endif
281
282    return SYS_ERR_OK;
283}
284
285/*
286 * Public functions
287 *
288 */
289errval_t ip_create(struct ip_q** q, const char* card_name, uint64_t* qid,
290                   uint8_t prot, uint32_t dst_ip, inthandler_t interrupt, bool poll)
291{
292    errval_t err;
293    struct ip_q* que;
294    que = calloc(1, sizeof(struct ip_q));
295    que->name = card_name;
296    assert(que);
297
298    // init other queue
299    err = net_queue_create(interrupt, card_name, NULL, qid, poll, &que->filter_ep, &que->q);
300    if (err_is_fail(err)) {
301        return err;
302    }
303
304    err = devq_init(&que->my_q, false);
305    if (err_is_fail(err)) {
306        // TODO net queue destroy
307        return err;
308    }
309
310    uint64_t src_mac;
311    err = devq_control(que->q, 0, 0, &src_mac);
312    if (err_is_fail(err)) {
313        return err;
314    }
315
316    uint32_t src_ip;
317    err = net_config_current_ip_query(NET_FLAGS_BLOCKING_INIT, &src_ip);
318    if (err_is_fail(err)) {
319        return err;
320    }
321
322    uint64_t mac;
323    err = arp_service_get_mac(htonl(dst_ip), &mac);
324    if (err_is_fail(err)) {
325        return err;
326    }
327
328    // fill in header that is reused for each packet
329    // Ethernet
330    memcpy(&(que->header.eth.dest.addr), &mac, ETH_HWADDR_LEN);
331    memcpy(&(que->header.eth.src.addr), &src_mac, ETH_HWADDR_LEN);
332    que->header.eth.type = htons(ETHTYPE_IP);
333
334    // IP
335    que->header.ip._v_hl = 69;
336    IPH_TOS_SET(&que->header.ip, 0x0);
337    IPH_ID_SET(&que->header.ip, htons(0x3));
338    que->header.ip._offset = htons(IP_DF);
339    que->header.ip._proto = 0x11; // IP
340    que->header.ip._ttl = 0x40; // 64
341    que->header.ip.src = src_ip;
342    que->header.ip.dest = htonl(dst_ip);
343
344    que->my_q.f.reg = ip_register;
345    que->my_q.f.dereg = ip_deregister;
346    que->my_q.f.ctrl = ip_control;
347    que->my_q.f.notify = ip_notify;
348    que->my_q.f.enq = ip_enqueue;
349    que->my_q.f.deq = ip_dequeue;
350    *q = que;
351
352    /*
353    switch(prot) {
354        case UDP_PROT:
355            que->hdr_len = IP_HLEN + sizeof(struct udp_hdr);
356            break;
357        case TCP_PROT:
358            // TODO
359            break;
360        default:
361            USER_PANIC("Unkown protocol specified when creating IP queue \n");
362
363    }
364    */
365
366#ifdef BENCH
367    bench_init();
368
369    que->en_tx.mode = BENCH_MODE_FIXEDRUNS;
370    que->en_tx.result_dimensions = 1;
371    que->en_tx.min_runs = BENCH_SIZE;
372    que->en_tx.data = calloc(que->en_tx.min_runs * que->en_tx.result_dimensions,
373                       sizeof(*que->en_tx.data));
374
375    que->en_rx.mode = BENCH_MODE_FIXEDRUNS;
376    que->en_rx.result_dimensions = 1;
377    que->en_rx.min_runs = BENCH_SIZE;
378    que->en_rx.data = calloc(que->en_rx.min_runs * que->en_rx.result_dimensions,
379                       sizeof(*que->en_rx.data));
380
381    que->deq_rx.mode = BENCH_MODE_FIXEDRUNS;
382    que->deq_rx.result_dimensions = 1;
383    que->deq_rx.min_runs = BENCH_SIZE;
384    que->deq_rx.data = calloc(que->deq_rx.min_runs * que->deq_rx.result_dimensions,
385                       sizeof(*que->deq_rx.data));
386
387    que->deq_tx.mode = BENCH_MODE_FIXEDRUNS;
388    que->deq_tx.result_dimensions = 1;
389    que->deq_tx.min_runs = BENCH_SIZE;
390    que->deq_tx.data = calloc(que->deq_tx.min_runs * que->deq_tx.result_dimensions,
391                       sizeof(*que->deq_tx.data));
392#endif
393
394    return SYS_ERR_OK;
395}
396
397errval_t ip_destroy(struct ip_q* q)
398{
399    // TODO destroy q->q;
400    free(q);
401
402    return SYS_ERR_OK;
403}
404
405void ip_get_netfilter_ep(struct ip_q* q, struct capref* ep)
406{
407    *ep = q->filter_ep;
408}
409
410struct bench_ctl* ip_get_benchmark_data(struct ip_q* q, uint8_t type)
411{
412    switch (type) {
413#ifdef BENCH
414        case 0:
415            return &q->en_rx;
416        case 1:
417            return &q->en_tx;
418        case 2:
419            return &q->deq_rx;
420        case 3:
421            return &q->deq_tx;
422#endif
423        case 4:
424            return net_queue_get_bench_data((struct devq*) q->q, q->name, 0);
425        case 5:
426            return net_queue_get_bench_data((struct devq*) q->q, q->name, 1);
427        case 6:
428            return net_queue_get_bench_data((struct devq*) q->q, q->name, 2);
429        case 7:
430            return net_queue_get_bench_data((struct devq*) q->q, q->name, 3);
431        default:
432            return NULL;
433    }
434    return NULL;
435}
436
437