libnet: refactor initialization code
[barrelfish] / lib / net / net.c
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, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 // stdlib includes
11
12 // barrelfish includes
13
14 // lwip includes
15 #include "lwip/init.h"
16 #include "lwip/netif.h"
17 #include "lwip/ip.h"
18 #include "lwip/dhcp.h"
19 #include "lwip/prot/ethernet.h"
20
21 #include <barrelfish/deferred.h>
22
23
24 #include <net_interfaces/flags.h>
25 #include "networking_internal.h"
26
27 struct net_state state = {0};
28
29 #define NETWORKING_DEFAULT_QUEUE_ID 0
30 #define NETWORKING_BUFFER_COUNT (4096 * 3)
31 #define NETWORKING_BUFFER_RX_POPULATE (4096 - 10)
32 #define NETWORKING_BUFFER_SIZE  2048
33
34
35
36
37 #define NET_USE_INTERRUPTS 1
38
39
40 #define NETDEBUG_SUBSYSTEM "net"
41
42 /**
43  * @brief obtains the default setting for initializaion of the driver
44  *
45  * @param queue     returns the queue to be used
46  * @param cardname  returns the card name to be used
47  *
48  * @return SYS_ERR_OK on success, SKB_ERR_* on failure
49  */
50 errval_t networking_get_defaults(uint64_t *queue, const char **cardname, uint32_t *flags)
51 {
52     /* TODO: get the values from the SKB */
53
54     *queue = NETWORKING_DEFAULT_QUEUE_ID;
55     *cardname = "sfn5122f";
56     *flags = NET_FLAGS_DEFAULTS;
57
58     return SYS_ERR_OK;
59 }
60
61 static void int_handler(void* args)
62 {
63     struct net_state *st = devq_get_state(args);
64
65     net_if_poll(&st->netif);
66 }
67
68 static errval_t create_loopback_queue (uint64_t queueid, struct devq **retqueue)
69 {
70     errval_t err;
71
72     debug_printf("net: creating loopback queue.\n");
73
74     err = loopback_queue_create((struct loopback_queue **)retqueue);
75     if (err_is_fail(err)) {
76         return err;
77     }
78
79     return SYS_ERR_OK;
80 }
81
82 static errval_t create_driver_queue (uint64_t queueid, struct devq **retqueue)
83 {
84     return SYS_ERR_OK;
85 }
86
87
88 static errval_t create_e10k_queue (uint64_t queueid, struct devq **retqueue)
89 {
90     return SYS_ERR_OK;
91 }
92
93 static errval_t create_sfn5122f_queue (uint64_t queueid, struct devq **retqueue)
94 {
95
96     return sfn5122f_queue_create((struct sfn5122f_queue**)retqueue, int_handler,
97                                 false /*userlevel network feature*/,
98                                 NET_USE_INTERRUPTS /* user interrupts*/);
99 }
100
101
102 typedef errval_t (*queue_create_fn)(uint64_t queueid, struct devq **retqueue);
103 struct networking_card
104 {
105     char *cardname;
106     queue_create_fn createfn;
107 } networking_cards [] = {
108     { "loopback", create_loopback_queue},
109     { "e1000", create_driver_queue},
110     { "e10k", create_e10k_queue},
111     { "sfn5122f", create_sfn5122f_queue},
112     { NULL, NULL}
113 };
114
115
116 /**
117  * @brief creates a queue to the given card and the queueid
118  *
119  * @param cardname  network card to create the queue for
120  * @param queueid   queueid of the network card
121  * @param retqueue  returns the pointer to the queue
122  *
123  * @return SYS_ERR_OK on success, errval on failure
124  */
125 errval_t networking_create_queue(const char *cardname, uint64_t queueid,
126                                  struct devq **retqueue)
127 {
128     debug_printf("net: creating queue for card='%s', queueid=%" PRIu64 "...\n",
129                   cardname, queueid);
130
131     struct networking_card *nc = networking_cards;
132     while(nc->cardname != NULL) {
133         if (strncmp(cardname, nc->cardname, strlen(nc->cardname)) == 0) {
134             return nc->createfn(queueid, retqueue);
135         }
136         nc++;
137     }
138
139     debug_printf("net: ERROR unknown queue. card='%s', queueid=%" PRIu64 "\n",
140                   cardname, queueid);
141
142     return -1;
143 }
144
145 errval_t networking_get_mac(struct devq *q, uint8_t *hwaddr, uint8_t hwaddrlen) {
146     debug_printf("net: obtaining MAC address for card.\n");
147     errval_t err;
148
149     uint64_t card_mac;
150     err = devq_control(q, 0, 0, &card_mac);
151     if (err_is_fail(err)) {
152         return err;
153     }
154
155     memcpy(hwaddr, &card_mac, hwaddrlen);
156
157     SMEMCPY(hwaddr, &card_mac, hwaddrlen);
158
159     debug_printf("got mac: %x:%x:%x:%x:%x:%x\n",
160                  hwaddr[0], hwaddr[1],hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
161
162     return SYS_ERR_OK;
163 }
164
165 errval_t networking_poll(void)
166 {
167
168 #if NET_USE_INTERRUPTS
169     return event_dispatch_non_block(get_default_waitset());
170 #else
171     struct net_state *st = &state;
172     return net_if_poll(&st->netif);
173 #endif
174 }
175
176
177
178
179 /**
180  * @brief initializes the netowrking library with a given device queue
181  *
182  * @param q         the device queue to initialize the networking on
183  * @param flags     supplied initialization flags
184  *
185  * @return SYS_ERR_OK on success, errval on failure
186  */
187 errval_t networking_init_with_queue(struct devq *q, net_flags_t flags)
188 {
189     errval_t err;
190
191     struct net_state *st = &state;
192
193     NETDEBUG("initializing networking with devq=%p, flags=%" PRIx32 "...\n", q,
194              flags);
195
196     if(st->initialized) {
197         debug_printf("WARNING. initialize called twice. Ignoring\n");
198         return SYS_ERR_OK;
199     }
200
201     /* set the variables */
202     st->flags = flags;
203     st->queue = q;
204     st->initialized = true;
205     st->waitset = get_default_waitset();
206
207     /* associate the net state with the device queue */
208     devq_set_state(st->queue, st);
209
210
211     /* initialize the device queue */
212     NETDEBUG("initializing LWIP...\n");
213     lwip_init();
214
215     /* create the LWIP network interface and initialize it */
216     NETDEBUG("creating netif for LWIP...\n");
217     err = net_if_init_devq(&st->netif, st->queue);
218     if (err_is_fail(err)) {
219         goto out_err1;
220     }
221
222     err = net_if_add(&st->netif, st);
223     if (err_is_fail(err)) {
224         goto out_err1;
225     }
226
227
228     /* create buffers and add them to the interface*/
229     err = net_buf_pool_alloc(st->queue, NETWORKING_BUFFER_COUNT,
230                              NETWORKING_BUFFER_SIZE, &st->pool);
231     if (err_is_fail(err)) {
232         //net_if_destroy(&st->netif);
233         goto out_err1;
234     }
235
236     NETDEBUG("adding RX buffers\n");
237     for (int i = 0; i < NETWORKING_BUFFER_RX_POPULATE; i++) {
238         struct pbuf *p = net_buf_alloc(st->pool);
239         if (p == NULL) {
240             NETDEBUG("net: WARNING there was no buffer\n");
241             break;
242         }
243         err = net_if_add_rx_buf(&st->netif, p);
244         if (err_is_fail(err)) {
245             break;
246         }
247     }
248
249
250     if (flags & NET_FLAGS_DO_DHCP) {
251         err = dhcpd_start(flags);
252         if (err_is_fail(err)) {
253             DEBUG_ERR(err, "failed to start DHCP.\n");
254         }
255     } else {
256         /* get IP from dhcpd */
257         err = dhcpd_query(flags);
258     }
259
260     NETDEBUG("initialization complete.\n");
261
262     return SYS_ERR_OK;
263
264     out_err1:
265     st->initialized = false;
266
267     return err;
268
269 }
270
271
272 /**
273  * @brief initializes the networking library
274  *
275  * @param nic       the nic to use with the networking library
276  * @param flags     flags to use to initialize the networking library
277  *
278  * @return SYS_ERR_OK on success, errval on failure
279  */
280 errval_t networking_init(const char *nic, net_flags_t flags)
281 {
282     errval_t err;
283
284     struct net_state *st = &state;
285
286     NETDEBUG("initializing networking with nic=%s, flags=%" PRIx32 "...\n", nic,
287              flags);
288
289     if(st->initialized) {
290         NETDEBUG("WARNING. initialize called twice. Ignoring\n");
291         return SYS_ERR_OK;
292     }
293
294     st->cardname = nic;
295
296     /* create the queue wit the given nic and card name */
297     err = networking_create_queue(st->cardname, st->queueid, &st->queue);
298     if (err_is_fail(err)) {
299         return err;
300     }
301
302     err = networking_init_with_queue(st->queue, flags);
303     if (err_is_fail(err)) {
304        // devq_destroy(st->queue);
305     }
306
307     return err;
308 }
309
310
311
312 /**
313  * @brief initializes the networking with the defaults
314  *
315  * @return SYS_ERR_OK on sucess, errval on failure
316  */
317 errval_t networking_init_default(void)
318 {
319     errval_t err;
320
321     struct net_state *st = &state;
322
323     NETDEBUG("initializing networking with default options...\n");
324
325     if(st->initialized) {
326         NETDEBUG("WARNING. initialize called twice. Ignoring\n");
327         return SYS_ERR_OK;
328     }
329
330     // obtain the settings to create the queue
331     err = networking_get_defaults(&st->queueid, &st->cardname, &st->flags);
332     if (err_is_fail(err)) {
333         return err;
334     }
335
336     return networking_init(st->cardname, st->flags);
337 }