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