Overhaul lock_test.R
[akaros.git] / kern / src / net / netlog.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <slab.h>
30 #include <kmalloc.h>
31 #include <kref.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <assert.h>
35 #include <error.h>
36 #include <cpio.h>
37 #include <pmap.h>
38 #include <smp.h>
39 #include <net/ip.h>
40
41 enum {
42         Nlog = 4 * 1024,
43 };
44
45 /*
46  *  action log
47  */
48 struct Netlog {
49         spinlock_t lock;
50         int opens;
51         char *buf;
52         char *end;
53         char *rptr;
54         int len;
55
56         int logmask;                    /* mask of things to debug */
57         uint8_t iponly[IPaddrlen];      /* ip address to print debugging for */
58         int iponlyset;
59
60         qlock_t qlock;
61         struct rendez r;
62 };
63
64 typedef struct Netlogflag {
65         char *name;
66         int mask;
67 } Netlogflag;
68
69 static Netlogflag flags[] = {
70         {"ppp", Logppp,},
71         {"ip", Logip,},
72         {"fs", Logfs,},
73         {"tcp", Logtcp,},
74         {"il", Logil,},
75         {"icmp", Logicmp,},
76         {"udp", Logudp,},
77         {"compress", Logcompress,},
78         {"ilmsg", Logil | Logilmsg,},
79         {"gre", Loggre,},
80         {"tcpreset", Logtcp | Logtcpreset,},
81         {"tcprxmt", Logtcp | Logtcprxmt,},
82         {"tcpall", Logtcp | Logtcpreset | Logtcprxmt | Logtcpverbose,},
83         {"udpmsg", Logudp | Logudpmsg,},
84         {"ipmsg", Logip | Logipmsg,},
85         {"esp", Logesp,},
86         {NULL, 0,},
87 };
88
89 enum {
90         CMset,
91         CMclear,
92         CMonly,
93 };
94
95 static struct cmdtab routecmd[] = {
96         {CMset, "set", 0},
97         {CMclear, "clear", 0},
98         {CMonly, "only", 0},
99 };
100
101 void netloginit(struct Fs *f)
102 {
103         f->alog = kzmalloc(sizeof(struct Netlog), 0);
104         spinlock_init(&f->alog->lock);
105         qlock_init(&f->alog->qlock);
106         rendez_init(&f->alog->r);
107 }
108
109 void netlogopen(struct Fs *f)
110 {
111         ERRSTACK(1);
112         spin_lock(&f->alog->lock);
113         if (waserror()) {
114                 spin_unlock(&f->alog->lock);
115                 nexterror();
116         }
117         if (f->alog->opens == 0) {
118                 if (f->alog->buf == NULL)
119                         f->alog->buf = kzmalloc(Nlog, 0);
120                 f->alog->rptr = f->alog->buf;
121                 f->alog->end = f->alog->buf + Nlog;
122         }
123         f->alog->opens++;
124         spin_unlock(&f->alog->lock);
125         poperror();
126 }
127
128 void netlogclose(struct Fs *f)
129 {
130         ERRSTACK(1);
131         spin_lock(&f->alog->lock);
132         if (waserror()) {
133                 spin_unlock(&f->alog->lock);
134                 nexterror();
135         }
136         f->alog->opens--;
137         if (f->alog->opens == 0) {
138                 kfree(f->alog->buf);
139                 f->alog->buf = NULL;
140         }
141         spin_unlock(&f->alog->lock);
142         poperror();
143 }
144
145 static int netlogready(void *a)
146 {
147         struct Fs *f = a;
148
149         return f->alog->len;
150 }
151
152 long netlogread(struct Fs *f, void *a, uint32_t unused, long n)
153 {
154         ERRSTACK(1);
155         int i, d;
156         char *p, *rptr;
157
158         qlock(&f->alog->qlock);
159         if (waserror()) {
160                 qunlock(&f->alog->qlock);
161                 nexterror();
162         }
163
164         for (;;) {
165                 spin_lock(&f->alog->lock);
166                 if (f->alog->len) {
167                         if (n > f->alog->len)
168                                 n = f->alog->len;
169                         d = 0;
170                         rptr = f->alog->rptr;
171                         f->alog->rptr += n;
172                         if (f->alog->rptr >= f->alog->end) {
173                                 d = f->alog->rptr - f->alog->end;
174                                 f->alog->rptr = f->alog->buf + d;
175                         }
176                         f->alog->len -= n;
177                         spin_unlock(&f->alog->lock);
178
179                         i = n - d;
180                         p = a;
181                         memmove(p, rptr, i);
182                         memmove(p + i, f->alog->buf, d);
183                         break;
184                 } else
185                         spin_unlock(&f->alog->lock);
186
187                 rendez_sleep(&f->alog->r, netlogready, f);
188         }
189
190         qunlock(&f->alog->qlock);
191         poperror();
192
193         return n;
194 }
195
196 void netlogctl(struct Fs *f, char *s, size_t n)
197 {
198         ERRSTACK(1);
199         int i, set = 0;
200         Netlogflag *fp;
201         struct cmdbuf *cb;
202         struct cmdtab *ct;
203
204         cb = parsecmd(s, n);
205         if (waserror()) {
206                 kfree(cb);
207                 nexterror();
208         }
209
210         if (cb->nf < 2)
211                 error(EINVAL, ERROR_FIXME);
212
213         ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
214
215         switch (ct->index) {
216         case CMset:
217                 set = 1;
218                 break;
219
220         case CMclear:
221                 set = 0;
222                 break;
223
224         case CMonly:
225                 parseip(f->alog->iponly, cb->f[1]);
226                 if (ipcmp(f->alog->iponly, IPnoaddr) == 0)
227                         f->alog->iponlyset = 0;
228                 else
229                         f->alog->iponlyset = 1;
230                 kfree(cb);
231                 poperror();
232                 return;
233
234         default:
235                 cmderror(cb, "unknown ip control message");
236         }
237
238         for (i = 1; i < cb->nf; i++) {
239                 for (fp = flags; fp->name; fp++)
240                         if (strcmp(fp->name, cb->f[i]) == 0)
241                                 break;
242                 if (fp->name == NULL)
243                         continue;
244                 if (set)
245                         f->alog->logmask |= fp->mask;
246                 else
247                         f->alog->logmask &= ~fp->mask;
248         }
249
250         kfree(cb);
251         poperror();
252 }
253
254 void netlog(struct Fs *f, int mask, char *fmt, ...)
255 {
256         char buf[256], *t, *fp;
257         int i, n;
258         va_list arg;
259         struct timespec ts_now;
260
261         if (!(f->alog->logmask & mask))
262                 return;
263
264         if (f->alog->opens == 0)
265                 return;
266
267         /* Same style as trace_printk */
268         if (likely(__proc_global_info.tsc_freq))
269                 ts_now = tsc2timespec(read_tsc());
270         n = snprintf(buf, sizeof(buf), "[%lu.%09lu]: ",
271                      ts_now.tv_sec, ts_now.tv_nsec);
272
273         va_start(arg, fmt);
274         n += vsnprintf(buf + n, sizeof(buf) - n, fmt, arg);
275         va_end(arg);
276
277         spin_lock(&f->alog->lock);
278         i = f->alog->len + n - Nlog;
279         if (i > 0) {
280                 f->alog->len -= i;
281                 f->alog->rptr += i;
282                 if (f->alog->rptr >= f->alog->end)
283                         f->alog->rptr = f->alog->buf + (f->alog->rptr -
284                                                         f->alog->end);
285         }
286         t = f->alog->rptr + f->alog->len;
287         fp = buf;
288         f->alog->len += n;
289         while (n-- > 0) {
290                 if (t >= f->alog->end)
291                         t = f->alog->buf + (t - f->alog->end);
292                 *t++ = *fp++;
293         }
294         spin_unlock(&f->alog->lock);
295
296         rendez_wakeup(&f->alog->r);
297 }