AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
netif.c
Go to the documentation of this file.
1
16
17#include <core/system.h>
18#include <core/arch.h>
19#include <core/kargs.h>
20#include <core/module.h>
21#include <core/panic.h>
22#include <core/printk.h>
23#include <core/string.h>
24#include <net/byteorder.h>
25#include <net/netif.h>
26#include <net/inet.h>
27#include <sys/callout.h>
28#include <sys/kthread.h>
29#include <sys/sched.h>
30
31#define NET_BUDGET 32 /* frames handled before other threads run */
32#define NET_BACKLOG 256 /* the most frames that may wait */
33
34struct netif *netifs;
35static int ethers_nr;
36
37static struct netif loopback;
38
39static struct thread *net_thread;
40static struct waitq net_wait;
41
42static struct netbuf *rx_head, *rx_tail;
43static size_t rx_count;
44
46
49static int parse_ipv4(const char **s, uint32_t *ip)
50{
51 uint32_t addr = 0;
52
53 for (int i = 0; i < 4; ++i) {
54 if (**s < '0' || **s > '9')
55 return -1;
56
57 uint32_t byte = 0;
58 while (**s >= '0' && **s <= '9')
59 byte = byte * 10 + (*(*s)++ - '0');
60
61 if (byte > 255 || (i < 3 && *(*s)++ != '.'))
62 return -1;
63
64 addr = addr << 8 | byte;
65 }
66
67 *ip = htonl(addr);
68 return 0;
69}
70
73static void netif_config(struct netif *netif)
74{
75 const char *s = NULL;
76
77 if (kargs_get("ip", &s) || !s)
78 return;
79
80 uint32_t ip, gateway = 0, prefix = 24;
81
82 if (parse_ipv4(&s, &ip))
83 goto bad;
84
85 if (*s == '/') {
86 ++s;
87 prefix = 0;
88 while (*s >= '0' && *s <= '9')
89 prefix = prefix * 10 + (*s++ - '0');
90
91 if (prefix > 32)
92 goto bad;
93 }
94
95 if (*s == ':' && (++s, parse_ipv4(&s, &gateway)))
96 goto bad;
97
98 netif->ip = ip;
99 netif->netmask = htonl(prefix ? ~0U << (32 - prefix) : 0);
100 netif->gateway = gateway;
101 netif->flags |= NETIF_UP;
102
103 uint32_t a = ntohl(ip), g = ntohl(gateway);
104 printk("net: %s %d.%d.%d.%d/%d, gateway %d.%d.%d.%d\n", netif->name,
105 a >> 24, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff, prefix,
106 g >> 24, (g >> 16) & 0xff, (g >> 8) & 0xff, g & 0xff);
107 return;
108
109bad:
110 printk("net: ip=: not <address>/<prefix length>[:<gateway>]\n");
111}
112
115static char *mac_string(const uint8_t mac[6], char buf[18])
116{
117 static const char digits[] = "0123456789abcdef";
118
119 for (int i = 0; i < 6; ++i) {
120 buf[i * 3] = digits[mac[i] >> 4];
121 buf[i * 3 + 1] = digits[mac[i] & 0xf];
122 buf[i * 3 + 2] = i < 5 ? ':' : '\0';
123 }
124
125 return buf;
126}
127
137void net_callout_set(struct callout *c, uint64_t ns, void (*fn)(void *), void *arg)
138{
139 callout_set_on(&net_callouts, c, ns, fn, arg);
140
141 /* the thread may be sleeping until a later callout */
142 if (net_thread)
144}
145
149static void net_main(void *arg __unused)
150{
151 for (;;) {
152 for (int n = 0; rx_head && n < NET_BUDGET; ++n) {
153 struct netbuf *nb = rx_head;
154
155 rx_head = nb->next;
156 if (!rx_head)
157 rx_tail = NULL;
158
159 rx_count--;
160 nb->next = NULL;
161
162 if (nb->loopback)
163 ipv4_input(nb->netif, nb, nb->netif->mac);
164 else
165 ether_input(nb->netif, nb);
166 }
167
169
170 /* if more frames wait, let the other threads run first */
171 if (rx_head) {
172 arch_yield();
173 continue;
174 }
175
177 }
178}
179
186struct netif *netif_find(const char *name)
187{
188 for (struct netif *netif = netifs; netif; netif = netif->next)
189 if (!strncmp(netif->name, name, 16))
190 return netif;
191
192 return NULL;
193}
194
195static void loopback_init(void);
196
207{
208 /* lo comes first */
209 if (netif != &loopback && !loopback.transmit)
211
212 if (!net_thread) {
213 if (kthread_create("net", net_main, NULL, &net_thread))
214 panic("net: can't make the network's thread");
215
216 net_thread->urgent = 1;
217 }
218
219 int n = -1;
220
221 if (!netif->name[0]) {
222 n = ethers_nr++;
223 snprintf(netif->name, sizeof(netif->name), "eth%d", n);
224 }
225
226 if (!netif->mtu)
227 netif->mtu = 1500;
228
229 /* add it at the end, in the order they come */
230 struct netif **p = &netifs;
231
232 while (*p)
233 p = &(*p)->next;
234
235 netif->next = NULL;
236 *p = netif;
237
238 char mac[18];
239
241 printk("net: %s: loopback, 127.0.0.1/8\n", netif->name);
242 else
243 printk("net: %s: %s\n", netif->name, mac_string(netif->mac, mac));
244
245 /* ip= configures the first Ethernet interface */
246 if (n == 0)
248
249 return 0;
250}
251
255static int loopback_transmit(struct netif *netif, struct netbuf *nb)
256{
257 struct netbuf *copy = netbuf_alloc();
258
259 if (!copy)
260 return -ENOBUFS;
261
262 memcpy(netbuf_put(copy, nb->len), nb->data, nb->len);
263 netif_input(netif, copy);
264 return 0;
265}
266
268static void loopback_init(void)
269{
270 if (loopback.transmit)
271 return;
272
273 strcpy(loopback.name, "lo");
274 loopback.ip = htonl(0x7f000001);
275 loopback.netmask = htonl(0xff000000);
277 loopback.mtu = 1500; /* about what a netbuf holds */
279
281}
282
284static int loopback_module_init(void)
285{
287 return 0;
288}
289
291
292
294static void rx_queue(struct netif *netif, struct netbuf *nb)
295{
296 if (!(netif->flags & NETIF_UP) || rx_count >= NET_BACKLOG) {
297 netif->stats.rx_dropped++;
298 netbuf_free(nb);
299 return;
300 }
301
302 /* add it to the queue of the network's thread */
303 nb->next = NULL;
304
305 if (rx_tail)
306 rx_tail->next = nb;
307 else
308 rx_head = nb;
309
310 rx_tail = nb;
311 rx_count++;
312
314}
315
323void netif_input(struct netif *netif, struct netbuf *nb)
324{
325 netif->stats.rx_packets++;
326 netif->stats.rx_bytes += nb->len;
327 nb->netif = netif;
328 nb->loopback = 0;
329
330 rx_queue(netif, nb);
331}
332
340void netif_loopback(struct netif *netif, struct netbuf *nb)
341{
342 netif->stats.rx_packets++;
343 netif->stats.rx_bytes += nb->len;
344 nb->netif = netif;
345 nb->loopback = 1;
346
347 rx_queue(netif, nb);
348}
349
358int netif_output(struct netif *netif, struct netbuf *nb)
359{
360 int err = netif->transmit(netif, nb);
361
362 if (err) {
363 netif->stats.tx_errors++;
364 return err;
365 }
366
367 netif->stats.tx_packets++;
368 netif->stats.tx_bytes += nb->len;
369 return 0;
370}
void arch_yield(void)
Puts the current thread at the end of the ready list, and runs the next ready thread.
Definition sched.c:94
#define panic(s)
Definition panic.h:15
#define ntohl(x)
Definition byteorder.h:18
#define htonl(x)
Definition byteorder.h:11
void callout_list_run(struct callout_list *list, uint64_t now)
Calls the callouts of a list that are due, taking each off the list first.
Definition callout.c:86
uint64_t callout_list_next(struct callout_list *list)
Finds when the first callout of a list is due.
Definition callout.c:115
void callout_set_on(struct callout_list *list, struct callout *c, uint64_t ns, void(*fn)(void *), void *arg)
Sets a callout on a list: fn(arg) will be called once ns ns have passed, by whoever runs the list.
Definition callout.c:50
void ether_input(struct netif *netif, struct netbuf *nb)
Takes in a frame that an interface received, and passes it to ARP or IPv4.
Definition ether.c:21
void ipv4_input(struct netif *netif, struct netbuf *nb, const uint8_t src_mac[6])
Takes in an IPv4 packet that an interface received, and passes it to its protocol.
Definition ipv4.c:84
int kargs_get(const char *key, const char **value)
Looks up an argument of the kernel's command line.
Definition kargs.c:73
int kthread_create(const char *name, void(*fn)(void *), void *arg, struct thread **ref)
Makes a kernel thread, and makes it ready to run.
Definition kthread.c:71
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
#define MODULE_INIT(name, i, f)
Definition module.h:10
struct netbuf * netbuf_alloc(void)
Allocates a netbuf, empty, with room for the headers that will be put in front of its data.
Definition netbuf.c:58
static struct thread * net_thread
Definition netif.c:39
static int loopback_transmit(struct netif *netif, struct netbuf *nb)
Sends a frame on lo: a copy of it comes back in.
Definition netif.c:255
static struct netif loopback
Definition netif.c:37
static void net_main(void *arg)
Runs the network's thread: it takes the received frames up the stack and runs the network's callouts,...
Definition netif.c:149
static struct netbuf * rx_head
Definition netif.c:42
#define NET_BACKLOG
Definition netif.c:32
static int parse_ipv4(const char **s, uint32_t *ip)
Parses an address "a.b.c.d" at *s into *ip, in network byte order, and moves *s past it.
Definition netif.c:49
static size_t rx_count
Definition netif.c:43
static void netif_config(struct netif *netif)
Configures the first Ethernet interface from the kernel's command line: ip=address/prefix-length[:gat...
Definition netif.c:73
static int ethers_nr
Definition netif.c:35
static void loopback_init(void)
Sets up lo, the loopback interface, once.
Definition netif.c:268
#define NET_BUDGET
Definition netif.c:31
static struct netbuf * rx_tail
Definition netif.c:42
static void rx_queue(struct netif *netif, struct netbuf *nb)
Queues a received frame for the network's thread, and wakes it up.
Definition netif.c:294
static struct waitq net_wait
Definition netif.c:40
static char * mac_string(const uint8_t mac[6], char buf[18])
Writes a MAC address into buf as "xx:xx:xx:xx:xx:xx" (printk() has no field widths) and returns buf.
Definition netif.c:115
static struct callout_list net_callouts
Definition netif.c:45
static int loopback_module_init(void)
Sets up lo at boot, so that it is there even without a network card.
Definition netif.c:284
int netif_register(struct netif *netif)
Registers a network interface.
Definition netif.c:206
#define NETIF_LOOPBACK
Definition netif.h:10
#define NETIF_UP
Definition netif.h:8
struct netif * netif_find(const char *name)
Finds an interface by its name.
Definition netif.c:186
#define NETIF_RUNNING
Definition netif.h:9
int netif_output(struct netif *netif, struct netbuf *nb)
Sends a frame through an interface's driver.
Definition netif.c:358
void net_callout_set(struct callout *c, uint64_t ns, void(*fn)(void *), void *arg)
Sets a callout that the network's thread runs: fn(arg) is called once ns ns have passed.
Definition netif.c:137
struct netif * netifs
Definition netif.c:34
void netif_loopback(struct netif *netif, struct netbuf *nb)
Hands the stack an IPv4 packet sent to one of our own addresses, as if it had come in through an inte...
Definition netif.c:340
void netif_input(struct netif *netif, struct netbuf *nb)
Hands the stack a frame that a driver received, possibly from an interrupt.
Definition netif.c:323
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
int sched_wait(struct waitq *waitq, uint64_t until)
Puts the current thread to sleep on a wait queue until it is woken up, a signal ends the sleep,...
Definition sched.c:187
int snprintf(char *s, size_t n, const char *fmt,...)
Formats a string into a buffer.
Definition snprintf.c:226
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned long long int uint64_t
Definition stddef.h:23
A list of callouts called from one context: the timer's interrupt (callout_set()),...
Definition callout.h:24
A function to call later, with its argument.
Definition callout.h:13
A packet (net/netbuf.c).
Definition netbuf.h:16
int loopback
Definition netbuf.h:22
struct netif * netif
Definition netbuf.h:18
struct netbuf * next
Definition netbuf.h:17
uint8_t * data
Definition netbuf.h:19
size_t len
Definition netbuf.h:20
A network interface (net/netif.c): a device that sends and receives Ethernet frames,...
Definition netif.h:16
int flags
Definition netif.h:20
uint32_t ip
Definition netif.h:24
uint32_t netmask
Definition netif.h:24
int(*) transmit(struct netif *netif, struct netbuf *nb)
Definition netif.h:28
char name[8]
Definition netif.h:17
struct netif::@020302303320120142126121344055047003105154122231 stats
uint32_t gateway
Definition netif.h:24
uint8_t mac[6]
Definition netif.h:18
uint16_t mtu
Definition netif.h:19
struct netif * next
Definition netif.h:37
A thread.
Definition thread.h:23
int urgent
it runs before the others once woken, as soon as the interrupt that woke it returns (sched_thread_wak...
Definition thread.h:91
Definition waitq.h:19
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.
Definition timer.c:56
void thread_wakeup(struct thread *thread)
Wakes up one thread, if it is sleeping on a wait queue.
Definition waitq.c:216