1/**
2 * \file
3 * \brief Datapath Communication between LWIP and network driver
4 *
5 * This file manages and performs the datapath communication between LWIP
6 * and the network driver
7 */
8
9/*
10 * Copyright (c) 2007-11 ETH Zurich
11 * All rights reserved.
12 *
13 * This file is distributed under the terms in the attached LICENSE file.
14 * If you do not find this file, copies can be found by writing to:
15 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
16 */
17
18#include <barrelfish/barrelfish.h>
19#include <barrelfish/nameservice_client.h>
20#include <stdio.h>
21#include <assert.h>
22#include <trace/trace.h>
23#include <trace_definitions/trace_defs.h>
24#include <netbench/netbench.h>
25#include <procon/procon.h>
26#include "lwip/pbuf.h"
27#include "lwip/init.h"
28#include "lwip/sys.h"
29#include "mem_barrelfish.h"
30#include "idc_barrelfish.h"
31#include <if/net_queue_manager_defs.h>
32//#include <if/net_ports_defs.h>
33//#include <if/net_ports_defs.h>
34#include <barrelfish/bulk_transfer_arch.h>
35#include <net_interfaces/net_interfaces.h>
36
37#include "lwip_barrelfish_debug.h"
38
39/* Enable tracing based on the global settings. */
40#if CONFIG_TRACE && NETWORK_STACK_TRACE
41#define LWIP_TRACE_MODE 1
42#endif // CONFIG_TRACE && NETWORK_STACK_TRACE
43
44struct waitset *lwip_waitset;
45bool lwip_init_done = false;
46
47
48static int inflight_tx_requests = 0;
49static int inflight_tx_limit = 127;
50static int MAX_TRIES_TX = 200;
51
52uint64_t incoming_packet_count = 0;
53uint64_t incoming_tx_done_count = 0;
54uint64_t outgoing_packet_count = 0;
55uint64_t chained_pbuf_count = 0;
56
57
58/*************************************************************
59 * \defGroup LocalStates Local states
60 *
61 * @{
62 *
63 ****************************************************************/
64
65
66uint64_t lwip_queue_id = 0; // queue_id allocated to this application
67
68/**
69 * \brief
70 *
71 *
72 *
73 */
74static void (*lwip_rec_handler) (void *, uint64_t, uint64_t, uint64_t,
75                                 uint64_t, struct pbuf *) = NULL;
76
77
78/**
79 * \brief
80 *
81 *
82 *
83 */
84static void *lwip_rec_data;
85
86
87/**
88 * \brief
89 *
90 *
91 *
92 */
93static void (*lwip_free_handler) (struct pbuf *) = NULL;
94
95
96// Statistics about driver state
97static uint64_t driver_tx_slots_left = 0;
98
99uint64_t idc_check_driver_load(void)
100{
101    return driver_tx_slots_left;
102}
103
104uint64_t idc_get_packet_drop_count(void)
105{
106    return driver_tx_slots_left;
107}
108
109// checks if LWIP has any work to do, and does it without blocking
110// or waiting for any events.
111uint64_t perform_lwip_work(void)
112{
113    uint64_t ec = 0;
114    struct waitset *ws = get_default_waitset();
115    while (1) {
116        // check for any event without blocking
117        errval_t err = event_dispatch_non_block(ws);
118        if (err == LIB_ERR_NO_EVENT) {
119            break;
120        }
121        if (err_is_fail(err)) {
122            DEBUG_ERR(err, "in event_dispatch_nonblock");
123            break;
124        }
125        ++ec;
126    }
127    return ec;
128}
129
130uint64_t idc_send_packet_to_network_driver(struct pbuf *p)
131{
132    size_t idx;
133    ptrdiff_t offset;
134
135
136#if LWIP_TRACE_MODE
137        trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_LWIPTX, 0);
138#endif // LWIP_TRACE_MODE
139
140    LWIPBF_DEBUG("%s: idc_send_packet_to_network_driver: called\n", disp_name());
141
142    size_t pbuf_chain_len = pbuf_clen(p);
143    struct waitset *ws = get_default_waitset();
144    int counter = 0;
145    while (pbuf_chain_len >= (inflight_tx_limit - inflight_tx_requests)) {
146
147        errval_t err = event_dispatch(ws);
148        if (err_is_fail(err)) {
149            DEBUG_ERR(err, "in event_dispatch");
150            abort();
151            // I should push error LWIP_ERR_TXFULL on this before returning
152            return 0;
153        }
154
155        ++counter;
156        if (counter >= MAX_TRIES_TX) {
157            printf("send_packet waited for %d events, and now giving up\n",
158                    counter);
159            return 0;
160        }
161    } // end while
162
163
164    size_t more_chunks = false;
165    uint64_t pkt_count = 0;
166    while(p != NULL) {
167        // Note: since we are freeing each pbuf in the chain separately, we
168        // need to increment the reference count seperately, since lwip only
169        // incremented the first pbuf's reference counter
170        if (pkt_count != 0) {
171//            pbuf_ref(p);
172            ++chained_pbuf_count;
173        }
174
175        more_chunks = (p->next != NULL);
176        idx = mem_barrelfish_put_pbuf(p);
177
178        offset = p->payload - buffer_base;
179
180        ++inflight_tx_requests;
181        errval_t err = buffer_tx_add(idx, offset % buffer_size, p->len,
182                more_chunks, p->nicflags);
183        if (err != SYS_ERR_OK) {
184            printf("idc_send_packet_to_network_driver: failed\n");
185            USER_PANIC("idc_send_packet_to_network_driver: failed\n");
186            LWIPBF_DEBUG("idc_send_packet_to_network_driver: failed\n");
187            return 0;
188        }
189        if (pbuf_chain_len > 1) {
190            LWIPBF_DEBUG
191            //printf
192                ("%s:chained pbuf %"PRIu64" (idx %"PRIu64"): "
193                    "chain elem %"PRIu64" pbuf_ref = %"PRIu16" \n",
194                   disp_name(), outgoing_packet_count, idx, pkt_count, p->ref);
195       } else {
196            LWIPBF_DEBUG
197            //printf
198                ("%s:Packet pbuf %"PRIu64" (idx %"PRIu64"): "
199                    "chain elem %"PRIu64" pbuf_ref = %"PRIu16" \n",
200                   disp_name(), outgoing_packet_count, idx, pkt_count, p->ref);
201       }
202
203
204        LWIPBF_DEBUG("idc_send_packet_to_network_driver: terminated\n");
205        ++pkt_count;
206        p = p->next;
207        outgoing_packet_count++;
208    }
209    return pkt_count;
210} // end function: idc_send_packet_to_network_driver
211
212
213void debug_show_spp_status(int connection)
214{
215    assert(!"NYI");
216}
217
218
219int lwip_check_sp_capacity(int direction)
220{
221    assert(!"NYI");
222    return -1;
223}
224
225
226int idc_check_capacity(int direction)
227{
228    assert(!"NYI");
229    return -1;
230}
231
232
233void idc_get_mac_address(uint8_t * mac_client)
234{
235    benchmark_get_mac_address(mac_client);
236}
237
238
239void idc_print_statistics(void)
240{
241    LWIPBF_DEBUG("idc_print_statistics: called\n");
242    assert(!"NYI");
243    LWIPBF_DEBUG("idc_print_statistics: terminated\n");
244}
245
246
247void idc_print_cardinfo(void)
248{
249    printf("idc_print_cardinfo: Not yet Implemented\n");
250    // FIXME: It should send msg to device driver and not queue manager
251}
252
253
254void idc_benchmark_control(int connection, uint8_t state, uint64_t trigger,
255        uint64_t cl)
256{
257     LWIPBF_DEBUG("idc_debug_status:  called with status %x [%"PRIu64"]\n",
258     state, trigger);
259     assert(!"NYI");
260}
261
262
263/**
264 * \brief
265 *
266 *
267 *
268 */
269void idc_register_receive_callback(void (*f)
270                                    (void *, uint64_t, uint64_t, uint64_t,
271                                     uint64_t, struct pbuf *), void *data)
272{
273
274    LWIPBF_DEBUG("idc_register_receive_callback: called\n");
275
276    assert(f != 0);
277    lwip_rec_handler = f;
278    lwip_rec_data = data;
279
280    LWIPBF_DEBUG("idc_register_receive_callback: terminated\n");
281
282}
283
284
285void idc_register_freeing_callback(void (*f) (struct pbuf *))
286{
287
288    LWIPBF_DEBUG("idc_register_freeing_callback: called\n");
289
290    lwip_free_handler = f;
291
292    LWIPBF_DEBUG("idc_register_freeing_callback: terminated\n");
293
294}
295
296
297/*************************************************************
298 * \defGroup MessageHandlers Message Handlers
299 *
300 * (...)
301 *
302 * @{
303 *
304 ****************************************************************/
305
306uint8_t get_driver_benchmark_state(int direction,
307        uint64_t *delta, uint64_t *cl)
308{
309    assert(!"NYI");
310    return 0;
311}
312
313// antoinek: Might need to reenable this when we enable multi threaded lwip
314// again
315//bool lwip_in_packet_received = false;
316static void handle_incoming(size_t idx, size_t len, uint64_t more,
317                            uint64_t flags)
318{
319    struct pbuf *p;
320
321    assert(!more);
322#if LWIP_TRACE_MODE
323        trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_LWIPRX, 0);
324#endif // LWIP_TRACE_MODE
325
326    ++incoming_packet_count;
327    LWIPBF_DEBUG
328    //printf
329        ("%s:handle_incoming: incoming packet no %"PRIu64": len %"PRIu64"\n",
330            disp_name(), incoming_packet_count, len);
331
332    // Get the pbuf for this index
333    p = mem_barrelfish_get_pbuf(idx);
334    assert(p != NULL);
335
336    LWIPBF_DEBUG("handle_incoming: incoming packet: len %"PRIu64"\n", len);
337    p->nicflags = flags;
338    lwip_rec_handler(lwip_rec_data, idx, -1ULL, len, len, p);
339
340}
341
342static void handle_tx_done(size_t idx)
343{
344
345    // this TX request is finished, so reduce the number of inflight TX requests
346    --inflight_tx_requests;
347    ++incoming_tx_done_count;
348    struct pbuf *p = mem_barrelfish_get_pbuf(idx);
349    assert(p != NULL);
350
351    LWIPBF_DEBUG
352    //printf
353        ("%s:%s:TX_done %"PRIu64": for outgoing packet no %"PRIu64" "
354            "(idx=%"PRIu64"): pbuf_ref = %"PRIu16" \n",
355            disp_name(), __func__,  incoming_tx_done_count,
356            outgoing_packet_count, idx, p->ref);
357    lwip_free_handler(p);
358}
359
360
361
362
363// antoinek: We don't need to connect here, as the interface already did that
364// for us. Maybe some internal initialization?
365void idc_connect_to_driver(char *card_name, uint64_t queueid)
366{
367    lwip_queue_id = queueid;
368    net_if_init(card_name, queueid);
369}
370
371
372
373
374/*
375 * antoinek: FIXME: These should be renamed in some resonable manner
376 */
377
378void benchmark_rx_done(size_t idx, size_t len, uint64_t more, uint64_t flags)
379{
380    LWIPBF_DEBUG("benchmark_rx_done(%"PRIu64", %"PRIu64")\n", idx, len);
381    if (lwip_init_done) {
382        handle_incoming(idx, len, more, flags);
383    }
384}
385
386void benchmark_tx_done(size_t idx)
387{
388    LWIPBF_DEBUG("benchmark_tx_done(%"PRIu64")\n", idx);
389    handle_tx_done(idx);
390}
391
392void benchmark_do_pending_work(void)
393{
394
395}
396
397