akaros/kern/src/net/netlog.c
<<
>>
Prefs
   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
  41enum {
  42        Nlog = 4 * 1024,
  43};
  44
  45/*
  46 *  action log
  47 */
  48struct 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
  64typedef struct Netlogflag {
  65        char *name;
  66        int mask;
  67} Netlogflag;
  68
  69static 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
  89enum {
  90        CMset,
  91        CMclear,
  92        CMonly,
  93};
  94
  95static struct cmdtab routecmd[] = {
  96        {CMset, "set", 0},
  97        {CMclear, "clear", 0},
  98        {CMonly, "only", 0},
  99};
 100
 101void 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
 109void 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
 128void 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
 145static int netlogready(void *a)
 146{
 147        struct Fs *f = a;
 148
 149        return f->alog->len;
 150}
 151
 152long 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
 196void 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
 254void 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}
 298