a0f841ecde7e6e1e2a99d0227f289e20b4c24d13
[barrelfish] / lib / lwip / src / netif / bfeth.c
1 /**
2  * \file
3  * Barrelfish standard ethernet interface
4  */
5
6 /*
7  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  *
32  * This file is part of the lwIP TCP/IP stack.
33  *
34  * Author: Adam Dunkels <adam@sics.se>
35  *
36  */
37
38 /*
39  * Copyright (c) 2007, 2008, ETH Zurich.
40  * All rights reserved.
41  *
42  * This file is distributed under the terms in the attached LICENSE file.
43  * If you do not find this file, copies can be found by writing to:
44  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
45  */
46
47 /*
48  * This file is a skeleton for developing Ethernet network interface
49  * drivers for lwIP. Add code to the low_level functions and do a
50  * search-and-replace for the word "ethernetif" to replace it with
51  * something that better describes your network interface.
52  */
53
54 #include "lwip/opt.h"
55 #include "lwip/def.h"
56 #include "lwip/init.h"
57 #include "lwip/mem.h"
58 #include "lwip/pbuf.h"
59 #include "lwip/sys.h"
60 #include <lwip/stats.h>
61 #include <lwip/snmp.h>
62 #include "netif/etharp.h"
63 #include <assert.h>
64
65 #include <netif/bfeth.h>
66
67 #include <barrelfish/barrelfish.h>
68 #include <netbench/netbench.h>
69 #include <idc_barrelfish.h>
70 #include <mem_barrelfish.h>
71
72 // 10MBit interface
73 #define BFETH_NETSPEED  10000000
74
75 /* Define those to better describe your network interface. */
76 #define IFNAME0 'e'
77 #define IFNAME1 'n'
78
79
80 /**
81  * Helper struct to hold private data used to operate your ethernet interface.
82  * Keeping the ethernet address of the MAC in this struct is not necessary
83  * as it is already kept in the struct netif.
84  * But this is only an example, anyway...
85  */
86 struct bfeth {
87     struct eth_addr *ethaddr;
88     /* Add whatever per-interface state that is needed here. */
89 };
90
91 /**
92  * In this function, the hardware should be initialized.
93  * Called from bfeth_init().
94  *
95  * @param netif the already initialized lwip network interface structure
96  *        for this bfeth
97  */
98 static void low_level_init(struct netif *netif)
99 {
100     /* set MAC hardware address length */
101     netif->hwaddr_len = ETHARP_HWADDR_LEN;
102
103     /* set MAC hardware address */
104     idc_get_mac_address(netif->hwaddr);
105
106     /* maximum transfer unit */
107     netif->mtu = 1500;
108
109     /* device capabilities */
110     netif->flags =
111       NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
112 }
113
114 /**
115  * This function should do the actual transmission of the packet. The packet is
116  * contained in the pbuf that is passed to the function. This pbuf
117  * might be chained.
118  *
119  * @param netif the lwip network interface structure for this bfeth
120  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
121  * @return ERR_OK if the packet could be sent
122  *         an err_t value if the packet couldn't be sent
123  *
124  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
125  *       strange results. You might consider waiting for space in the DMA queue
126  *       to become availale since the stack doesn't retry to send a packet
127  *       dropped because of memory failure (except for the TCP timers).
128  */
129
130 static err_t low_level_output(struct netif *netif, struct pbuf *p)
131 {
132     uint8_t numpbuf = 0;
133     //avoid that lwip frees this buffer before it has been sent by the network card.
134     for (struct pbuf * tmpp = p; tmpp != 0; tmpp = tmpp->next) {
135         pbuf_ref(tmpp);
136         ++numpbuf;
137     }
138 #if ETH_PAD_SIZE
139     pbuf_header(p, -ETH_PAD_SIZE);      /* drop the padding word */
140 #endif
141     //tell the network driver from which buffer and which offset to send the
142     //new data.
143     uint64_t ret = idc_send_packet_to_network_driver(p);
144
145 #if ETH_PAD_SIZE
146     pbuf_header(p, ETH_PAD_SIZE);       /* reclaim the padding word */
147 #endif
148
149     LINK_STATS_INC(link.xmit);
150
151     if (ret == numpbuf) {
152         return ERR_OK;
153     }
154     return ERR_IF;
155 }
156
157 uint64_t pbuf_free_tx_done_counter = 0;
158 static void bfeth_freeing_handler(struct pbuf *p)
159 {
160     assert(p != 0);
161     uint8_t freed_pbufs = pbuf_free(p);
162     pbuf_free_tx_done_counter += freed_pbufs;
163 }
164
165 typedef void (*packetfilter_func_t) (struct pbuf *, struct netif *, uint64_t);
166 static packetfilter_func_t packetfilter = NULL;
167 void bfeth_register_packetfilter(packetfilter_func_t filter);
168
169 void bfeth_register_packetfilter(packetfilter_func_t filter)
170 {
171     packetfilter = filter;
172 }
173
174
175
176 uint64_t pbuf_free_incoming_counter = 0;
177 /**
178  * This function should be called when a packet is ready to be read
179  * from the interface. It uses the function low_level_input() that
180  * should handle the actual reception of bytes from the network
181  * interface. Then the type of the received packet is determined and
182  * the appropriate input function is called.
183  *
184  * @param netif the lwip network interface structure for this bfeth
185  */
186 void
187 bfeth_input(struct netif *netif, uint64_t pbuf_id, uint64_t paddr, uint64_t len,
188             uint64_t packet_len, struct pbuf *pp)
189 {
190     struct bfeth *bfeth;
191     struct eth_hdr *ethhdr;
192     struct pbuf *p;
193
194     bfeth = netif->state;
195
196     //asq: low_level_input is not needed anymore, because p was preallocated
197     //and filled with an arrived packet by the network card driver.
198     //We only need to find the original vaddr of p according to the received
199     //index.
200     //We have to adjust the len and tot_len fields. The packet is
201     //most probably shorter than pbuf's size.
202     //LWIP is freeing the memory by looking at the type, not by the len or
203     //tot_len fields, so that should be fine.
204
205     //get vaddr of p and adjust the length according to the packet length.
206     p = mem_barrelfish_get_pbuf(pbuf_id);
207     //* Buffer has to be found
208     assert(p != 0);
209
210     assert(packet_len != 0);
211     p->len = packet_len;
212     p->tot_len = packet_len;
213     ethhdr = p->payload;
214
215     struct pbuf *replaced_pbuf = get_pbuf_for_packet();
216     if (replaced_pbuf == NULL) {
217        printf("%s:No free pbufs for replacement.  Assuming that packet is dropped\n", disp_name());
218         USER_PANIC("ERROR: No more free pbufs, aborting\n");
219         abort();
220         replaced_pbuf = p;
221 //        printf("pbuf stats: total len = %"PRIu16", len = %"PRIu16", buf len = %"PRIu16", ref count = %"PRIu16", \n",
222 //                p->tot_len, p->len, p->buff_len, p->ref);
223         replaced_pbuf->tot_len =  replaced_pbuf->buff_len;
224         replaced_pbuf->len =  replaced_pbuf->buff_len;
225         // Maybe I need to reset some pointers here!!
226     } else { // Now doing  packet processing
227
228         /* points to packet payload, which starts with an Ethernet header */
229
230         switch (htons(ethhdr->type)) {
231             /* IP or ARP packet? */
232             case ETHTYPE_IP:
233             case ETHTYPE_ARP:
234 #if PPPOE_SUPPORT
235                 /* PPPoE packet? */
236             case ETHTYPE_PPPOEDISC:
237             case ETHTYPE_PPPOE:
238 #endif                          /* PPPOE_SUPPORT */
239                 LWIP_DEBUGF(NETIF_DEBUG, ("bfeth_input: consuming the packet\n"));
240                 if (packetfilter != NULL) {
241                     packetfilter(p, netif, pbuf_id);
242                     return;
243                 } else {
244                     /* full packet send to tcpip_thread to process */
245                     assert(netif->input != NULL);
246                     if (netif->input(p, netif) != ERR_OK) {
247                         LWIP_DEBUGF(NETIF_DEBUG, ("bfeth_input: IP input error\n"));
248                         ++pbuf_free_incoming_counter;
249                         pbuf_free(p);
250                         p = NULL;
251                     }
252                 }
253                 break;
254
255             default:
256                 LWIP_DEBUGF(NETIF_DEBUG,
257                         ("unknown type %x!!!!!\n", htons(ethhdr->type)));
258                 ++pbuf_free_incoming_counter;
259                 pbuf_free(p);
260
261                 p = NULL;
262                 break;
263         }
264
265     }
266
267     //now we have consumed the preregistered pbuf containing a received packet
268     //which was processed in this function. Therefore we have to register a new
269     //free buffer for receiving packets. We can reuse the odl buffer's index
270     //and the corresponding data structures (i.e. array entries)
271     uint64_t ts = rdtsc();
272     errval_t err = mem_barrelfish_replace_pbuf(replaced_pbuf);
273     if (err != SYS_ERR_OK) {
274         printf("Can't replace received pbuf in RX ring\n");
275         pbuf_free(replaced_pbuf);
276         USER_PANIC("Can't replace received pbuf in RX ring\n");
277     }
278
279     netbench_record_event_simple(nb, RE_PBUF_REPLACE, ts);
280 }
281
282 static void bfeth_input_handler(void *data, uint64_t pbuf_id, uint64_t paddr,
283                                 uint64_t len, uint64_t packet_len,
284                                 struct pbuf *p)
285 {
286     bfeth_input((struct netif *) data, pbuf_id, paddr, len, packet_len, p);
287 }
288
289
290 /**
291  * Should be called at the beginning of the program to set up the
292  * network interface. It calls the function low_level_init() to do the
293  * actual setup of the hardware.
294  *
295  * This function should be passed as a parameter to netif_add().
296  *
297  * @param netif the lwip network interface structure for this bfeth
298  * @return ERR_OK if the loopif is initialized
299  *         ERR_MEM if private data couldn't be allocated
300  *         any other err_t on error
301  */
302 err_t bfeth_init(struct netif *netif)
303 {
304     struct bfeth *bfeth;
305
306     LWIP_ASSERT("netif != NULL", (netif != NULL));
307
308     bfeth = mem_malloc(sizeof(struct bfeth));
309     if (bfeth == NULL) {
310         LWIP_DEBUGF(NETIF_DEBUG, ("bfeth_init: out of memory\n"));
311         return ERR_MEM;
312     }
313 #if LWIP_NETIF_HOSTNAME
314     /* Initialize interface hostname */
315     netif->hostname = "lwip";
316 #endif                          /* LWIP_NETIF_HOSTNAME */
317
318     /*
319      * Initialize the snmp variables and counters inside the struct netif.
320      * The last argument should be replaced with your link speed, in units
321      * of bits per second.
322      */
323     NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, BFETH_NETSPEED);
324
325     netif->state = bfeth;
326     netif->name[0] = IFNAME0;
327     netif->name[1] = IFNAME1;
328     /* We directly use etharp_output() here to save a function call.
329      * You can instead declare your own function an call etharp_output()
330      * from it if you have to do some checks before sending (e.g. if link
331      * is available...) */
332     netif->output = etharp_output;
333     netif->linkoutput = low_level_output;
334
335     bfeth->ethaddr = (struct eth_addr *) &(netif->hwaddr[0]);
336
337     /* initialize the hardware */
338     low_level_init(netif);
339
340     // register a callback to get notified of arrived packets
341     idc_register_receive_callback(bfeth_input_handler, (void *) netif);
342
343     //register a function which is called if a transmit descriptor can be freed
344     //(which means the packet has been sent out of the network card and the buffer
345     //is free now)
346     idc_register_freeing_callback(bfeth_freeing_handler);
347
348     return ERR_OK;
349 }