6ae53f140c4e8ddf0913e82cc7101fb7c55a23ce
[akaros.git] / kern / src / net / netlog.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 enum {
17         Nlog = 4 * 1024,
18 };
19
20 /*
21  *  action log
22  */
23 struct Netlog {
24         spinlock_t lock;
25         int opens;
26         char *buf;
27         char *end;
28         char *rptr;
29         int len;
30
31         int logmask;                            /* mask of things to debug */
32         uint8_t iponly[IPaddrlen];      /* ip address to print debugging for */
33         int iponlyset;
34
35         qlock_t qlock;
36         struct rendez r;
37 };
38
39 typedef struct Netlogflag {
40         char *name;
41         int mask;
42 } Netlogflag;
43
44 static Netlogflag flags[] = {
45         {"ppp", Logppp,},
46         {"ip", Logip,},
47         {"fs", Logfs,},
48         {"tcp", Logtcp,},
49         {"il", Logil,},
50         {"icmp", Logicmp,},
51         {"udp", Logudp,},
52         {"compress", Logcompress,},
53         {"ilmsg", Logil | Logilmsg,},
54         {"gre", Loggre,},
55         {"tcpwin", Logtcp | Logtcpwin,},
56         {"tcprxmt", Logtcp | Logtcprxmt,},
57         {"udpmsg", Logudp | Logudpmsg,},
58         {"ipmsg", Logip | Logipmsg,},
59         {"esp", Logesp,},
60         {NULL, 0,},
61 };
62
63 char Ebadnetctl[] = "too few arguments for netlog control message";
64
65 enum {
66         CMset,
67         CMclear,
68         CMonly,
69 };
70
71 static
72 struct cmdtab routecmd[] = {
73         {CMset, "set", 0},
74         {CMclear, "clear", 0},
75         {CMonly, "only", 0},
76 };
77
78 void netloginit(struct Fs *f)
79 {
80         f->alog = kzmalloc(sizeof(struct Netlog), 0);
81         spinlock_init(&f->alog->lock);
82         qlock_init(&f->alog->qlock);
83         rendez_init(&f->alog->r);
84 }
85
86 void netlogopen(struct Fs *f)
87 {
88         ERRSTACK(1);
89         spin_lock(&f->alog->lock);
90         if (waserror()) {
91                 spin_unlock(&f->alog->lock);
92                 nexterror();
93         }
94         if (f->alog->opens == 0) {
95                 if (f->alog->buf == NULL)
96                         f->alog->buf = kzmalloc(Nlog, 0);
97                 f->alog->rptr = f->alog->buf;
98                 f->alog->end = f->alog->buf + Nlog;
99         }
100         f->alog->opens++;
101         spin_unlock(&f->alog->lock);
102         poperror();
103 }
104
105 void netlogclose(struct Fs *f)
106 {
107         ERRSTACK(1);
108         spin_lock(&f->alog->lock);
109         if (waserror()) {
110                 spin_unlock(&f->alog->lock);
111                 nexterror();
112         }
113         f->alog->opens--;
114         if (f->alog->opens == 0) {
115                 kfree(f->alog->buf);
116                 f->alog->buf = NULL;
117         }
118         spin_unlock(&f->alog->lock);
119         poperror();
120 }
121
122 static int netlogready(void *a)
123 {
124         struct Fs *f = a;
125
126         return f->alog->len;
127 }
128
129 long netlogread(struct Fs *f, void *a, uint32_t unused, long n)
130 {
131         ERRSTACK(1);
132         int i, d;
133         char *p, *rptr;
134
135         qlock(&f->alog->qlock);
136         if (waserror()) {
137                 qunlock(&f->alog->qlock);
138                 nexterror();
139         }
140
141         for (;;) {
142                 spin_lock(&f->alog->lock);
143                 if (f->alog->len) {
144                         if (n > f->alog->len)
145                                 n = f->alog->len;
146                         d = 0;
147                         rptr = f->alog->rptr;
148                         f->alog->rptr += n;
149                         if (f->alog->rptr >= f->alog->end) {
150                                 d = f->alog->rptr - f->alog->end;
151                                 f->alog->rptr = f->alog->buf + d;
152                         }
153                         f->alog->len -= n;
154                         spin_unlock(&f->alog->lock);
155
156                         i = n - d;
157                         p = a;
158                         memmove(p, rptr, i);
159                         memmove(p + i, f->alog->buf, d);
160                         break;
161                 } else
162                         spin_unlock(&f->alog->lock);
163
164                 rendez_sleep(&f->alog->r, netlogready, f);
165         }
166
167         qunlock(&f->alog->qlock);
168         poperror();
169
170         return n;
171 }
172
173 void netlogctl(struct Fs *f, char *s, int n)
174 {
175         ERRSTACK(1);
176         int i, set = 0;
177         Netlogflag *fp;
178         struct cmdbuf *cb;
179         struct cmdtab *ct;
180
181         cb = parsecmd(s, n);
182         if (waserror()) {
183                 kfree(cb);
184                 nexterror();
185         }
186
187         if (cb->nf < 2)
188                 error(Ebadnetctl);
189
190         ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
191
192         switch (ct->index) {
193                 case CMset:
194                         set = 1;
195                         break;
196
197                 case CMclear:
198                         set = 0;
199                         break;
200
201                 case CMonly:
202                         parseip(f->alog->iponly, cb->f[1]);
203                         if (ipcmp(f->alog->iponly, IPnoaddr) == 0)
204                                 f->alog->iponlyset = 0;
205                         else
206                                 f->alog->iponlyset = 1;
207                         kfree(cb);
208                         poperror();
209                         return;
210
211                 default:
212                         cmderror(cb, "unknown ip control message");
213         }
214
215         for (i = 1; i < cb->nf; i++) {
216                 for (fp = flags; fp->name; fp++)
217                         if (strcmp(fp->name, cb->f[i]) == 0)
218                                 break;
219                 if (fp->name == NULL)
220                         continue;
221                 if (set)
222                         f->alog->logmask |= fp->mask;
223                 else
224                         f->alog->logmask &= ~fp->mask;
225         }
226
227         kfree(cb);
228         poperror();
229 }
230
231 void netlog(struct Fs *f, int mask, char *fmt, ...)
232 {
233         char buf[128], *t, *fp;
234         int i, n;
235         va_list arg;
236
237         if (!(f->alog->logmask & mask))
238                 return;
239
240         if (f->alog->opens == 0)
241                 return;
242
243         va_start(arg, fmt);
244         n = vsnprintf(buf, sizeof(buf), fmt, arg);
245         va_end(arg);
246
247         spin_lock(&f->alog->lock);
248         i = f->alog->len + n - Nlog;
249         if (i > 0) {
250                 f->alog->len -= i;
251                 f->alog->rptr += i;
252                 if (f->alog->rptr >= f->alog->end)
253                         f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
254         }
255         t = f->alog->rptr + f->alog->len;
256         fp = buf;
257         f->alog->len += n;
258         while (n-- > 0) {
259                 if (t >= f->alog->end)
260                         t = f->alog->buf + (t - f->alog->end);
261                 *t++ = *fp++;
262         }
263         spin_unlock(&f->alog->lock);
264
265         rendez_wakeup(&f->alog->r);
266 }