blob: cac8ff56b8f298d242f4cf2cac58977854717252 [file] [log] [blame]
/* Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
* Portions Copyright © 1997-1999 Vita Nuova Limited
* Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
* (www.vitanuova.com)
* Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
*
* Modified for the Akaros operating system:
* Copyright (c) 2013-2014 The Regents of the University of California
* Copyright (c) 2013-2015 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <error.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
#include <net/ip.h>
enum {
Nlog = 4 * 1024,
};
/*
* action log
*/
struct Netlog {
spinlock_t lock;
int opens;
char *buf;
char *end;
char *rptr;
int len;
int logmask; /* mask of things to debug */
uint8_t iponly[IPaddrlen]; /* ip address to print debugging for */
int iponlyset;
qlock_t qlock;
struct rendez r;
};
typedef struct Netlogflag {
char *name;
int mask;
} Netlogflag;
static Netlogflag flags[] = {
{"ppp", Logppp,},
{"ip", Logip,},
{"fs", Logfs,},
{"tcp", Logtcp,},
{"il", Logil,},
{"icmp", Logicmp,},
{"udp", Logudp,},
{"compress", Logcompress,},
{"ilmsg", Logil | Logilmsg,},
{"gre", Loggre,},
{"tcpreset", Logtcp | Logtcpreset,},
{"tcprxmt", Logtcp | Logtcprxmt,},
{"tcpall", Logtcp | Logtcpreset | Logtcprxmt | Logtcpverbose,},
{"udpmsg", Logudp | Logudpmsg,},
{"ipmsg", Logip | Logipmsg,},
{"esp", Logesp,},
{NULL, 0,},
};
enum {
CMset,
CMclear,
CMonly,
};
static struct cmdtab routecmd[] = {
{CMset, "set", 0},
{CMclear, "clear", 0},
{CMonly, "only", 0},
};
void netloginit(struct Fs *f)
{
f->alog = kzmalloc(sizeof(struct Netlog), 0);
spinlock_init(&f->alog->lock);
qlock_init(&f->alog->qlock);
rendez_init(&f->alog->r);
}
void netlogopen(struct Fs *f)
{
ERRSTACK(1);
spin_lock(&f->alog->lock);
if (waserror()) {
spin_unlock(&f->alog->lock);
nexterror();
}
if (f->alog->opens == 0) {
if (f->alog->buf == NULL)
f->alog->buf = kzmalloc(Nlog, 0);
f->alog->rptr = f->alog->buf;
f->alog->end = f->alog->buf + Nlog;
}
f->alog->opens++;
spin_unlock(&f->alog->lock);
poperror();
}
void netlogclose(struct Fs *f)
{
ERRSTACK(1);
spin_lock(&f->alog->lock);
if (waserror()) {
spin_unlock(&f->alog->lock);
nexterror();
}
f->alog->opens--;
if (f->alog->opens == 0) {
kfree(f->alog->buf);
f->alog->buf = NULL;
}
spin_unlock(&f->alog->lock);
poperror();
}
static int netlogready(void *a)
{
struct Fs *f = a;
return f->alog->len;
}
long netlogread(struct Fs *f, void *a, uint32_t unused, long n)
{
ERRSTACK(1);
int i, d;
char *p, *rptr;
qlock(&f->alog->qlock);
if (waserror()) {
qunlock(&f->alog->qlock);
nexterror();
}
for (;;) {
spin_lock(&f->alog->lock);
if (f->alog->len) {
if (n > f->alog->len)
n = f->alog->len;
d = 0;
rptr = f->alog->rptr;
f->alog->rptr += n;
if (f->alog->rptr >= f->alog->end) {
d = f->alog->rptr - f->alog->end;
f->alog->rptr = f->alog->buf + d;
}
f->alog->len -= n;
spin_unlock(&f->alog->lock);
i = n - d;
p = a;
memmove(p, rptr, i);
memmove(p + i, f->alog->buf, d);
break;
} else
spin_unlock(&f->alog->lock);
rendez_sleep(&f->alog->r, netlogready, f);
}
qunlock(&f->alog->qlock);
poperror();
return n;
}
void netlogctl(struct Fs *f, char *s, int n)
{
ERRSTACK(1);
int i, set = 0;
Netlogflag *fp;
struct cmdbuf *cb;
struct cmdtab *ct;
cb = parsecmd(s, n);
if (waserror()) {
kfree(cb);
nexterror();
}
if (cb->nf < 2)
error(EINVAL, ERROR_FIXME);
ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
switch (ct->index) {
case CMset:
set = 1;
break;
case CMclear:
set = 0;
break;
case CMonly:
parseip(f->alog->iponly, cb->f[1]);
if (ipcmp(f->alog->iponly, IPnoaddr) == 0)
f->alog->iponlyset = 0;
else
f->alog->iponlyset = 1;
kfree(cb);
poperror();
return;
default:
cmderror(cb, "unknown ip control message");
}
for (i = 1; i < cb->nf; i++) {
for (fp = flags; fp->name; fp++)
if (strcmp(fp->name, cb->f[i]) == 0)
break;
if (fp->name == NULL)
continue;
if (set)
f->alog->logmask |= fp->mask;
else
f->alog->logmask &= ~fp->mask;
}
kfree(cb);
poperror();
}
void netlog(struct Fs *f, int mask, char *fmt, ...)
{
char buf[256], *t, *fp;
int i, n;
va_list arg;
struct timespec ts_now;
if (!(f->alog->logmask & mask))
return;
if (f->alog->opens == 0)
return;
/* Same style as trace_printk */
if (likely(__proc_global_info.tsc_freq))
ts_now = tsc2timespec(read_tsc());
n = snprintf(buf, sizeof(buf), "[%lu.%09lu]: ",
ts_now.tv_sec, ts_now.tv_nsec);
va_start(arg, fmt);
n += vsnprintf(buf + n, sizeof(buf) - n, fmt, arg);
va_end(arg);
spin_lock(&f->alog->lock);
i = f->alog->len + n - Nlog;
if (i > 0) {
f->alog->len -= i;
f->alog->rptr += i;
if (f->alog->rptr >= f->alog->end)
f->alog->rptr = f->alog->buf + (f->alog->rptr -
f->alog->end);
}
t = f->alog->rptr + f->alog->len;
fp = buf;
f->alog->len += n;
while (n-- > 0) {
if (t >= f->alog->end)
t = f->alog->buf + (t - f->alog->end);
*t++ = *fp++;
}
spin_unlock(&f->alog->lock);
rendez_wakeup(&f->alog->r);
}