summaryrefslogtreecommitdiffstats
path: root/src/vnet/ip/icmp4.h
blob: e2a95673fc74f6a644d245de6f3fcba94aa146b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
 * Copyright (c) 2015 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef included_vnet_icmp4_h
#define included_vnet_icmp4_h

#define foreach_icmp4_error                                             \
  _ (NONE, "valid packets")                                             \
  _ (UNKNOWN_TYPE, "unknown type")                                      \
  _ (INVALID_CODE_FOR_TYPE, "invalid code for type")                    \
  _ (INVALID_HOP_LIMIT_FOR_TYPE, "hop_limit != 255")                    \
  _ (LENGTH_TOO_SMALL_FOR_TYPE, "payload length too small for type")    \
  _ (OPTIONS_WITH_ODD_LENGTH,                                           \
     "total option length not multiple of 8 bytes")                     \
  _ (OPTION_WITH_ZERO_LENGTH, "option has zero length")                 \
  _ (ECHO_REPLIES_SENT, "echo replies sent")                            \
  _ (DST_LOOKUP_MISS, "icmp6 dst address lookup misses")                \
  _ (DEST_UNREACH_SENT, "destination unreachable response sent")        \
  _ (TTL_EXPIRE_SENT, "hop limit exceeded response sent")               \
  _ (PARAM_PROBLEM_SENT, "parameter problem response sent")             \
  _ (DROP, "error message dropped")

typedef enum
{
#define _(f,s) ICMP4_ERROR_##f,
  foreach_icmp4_error
#undef _
} icmp4_error_t;

typedef struct
{
  u8 packet_data[64];
} icmp_input_trace_t;

format_function_t format_icmp4_input_trace;
void ip4_icmp_register_type (vlib_main_t * vm, icmp4_type_t type,
			     u32 node_index);

static_always_inline void
icmp4_error_set_vnet_buffer (vlib_buffer_t * b, u8 type, u8 code, u32 data)
{
  vnet_buffer (b)->ip.icmp.type = type;
  vnet_buffer (b)->ip.icmp.code = code;
  vnet_buffer (b)->ip.icmp.data = data;
}

extern vlib_node_registration_t ip4_icmp_input_node;

#endif /* included_vnet_icmp4_h */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
} /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/* 
 *------------------------------------------------------------------
 * Copyright (c) 2005-2016 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include "g2.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

/*
 * globals
 */
boolean g_little_endian;
event_t *g_events;
ulong g_nevents;
pid_sort_t *g_pids;
pid_sort_t *g_original_pids;
int g_npids;
pid_data_t *g_pid_data_list;

/*
 * locals
 */
pid_data_t **s_pidhash;

/*
 * config parameters
 */

double ticks_per_ns=1000.0;
boolean ticks_per_ns_set;

/****************************************************************************
* event_init
****************************************************************************/

void event_init(void)
{
    ulong endian;
    char *ep;
    char *askstr;
    int tmp;

    ep = (char *)&endian;
    endian = 0x12345678;
    if (*ep != 0x12)
        g_little_endian = TRUE;
    else
        g_little_endian = FALSE;

    askstr = getprop("dont_ask_ticks_per_ns_initially");
    
    if (askstr && (*askstr == 't' || *askstr == 'T')) {
        tmp = atol(getprop_default("ticks_per_ns", 0));
        if (tmp > 0) {
            ticks_per_ns = tmp;
            ticks_per_ns_set = TRUE;
        }
    }
}

/****************************************************************************
* find_or_add_pid
****************************************************************************/

pid_data_t *find_or_add_pid (ulong pid)
{
    pid_data_t *pp;
    ulong bucket;

    bucket = pid % PIDHASH_NBUCKETS;

    pp = s_pidhash[bucket];

    if (pp == 0) {
        pp = g_malloc0(sizeof(pid_data_t));
        pp->pid_value = pid;
        s_pidhash[bucket] = pp;
        g_npids++;
        return(pp);
    }
    while (pp) {
        if (pp->pid_value == pid)
            return(pp);
        pp = pp->next;
    }

    pp = g_malloc0(sizeof(pid_data_t));
    pp->pid_value = pid;
    pp->next = s_pidhash[bucket];
    s_pidhash[bucket] = pp;
    g_npids++;
    return(pp);
}

/****************************************************************************
* pid_cmp
****************************************************************************/

int pid_cmp(const void *a1, const void *a2)
{
    pid_sort_t *p1 = (pid_sort_t *)a1;
    pid_sort_t *p2 = (pid_sort_t *)a2;

    if (p1->pid_value < p2->pid_value)
        return(-1);
    else if (p1->pid_value == p2->pid_value)
        return(0);
    else
        return(1);
}

/****************************************************************************
* make_sorted_pid_vector
****************************************************************************/

static void make_sorted_pid_vector(void)
{
    pid_data_t *pp;
    pid_data_t **p_previous;
    pid_sort_t *psp;
    int i;

    psp = g_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);

    for (i = 0; i < PIDHASH_NBUCKETS; i++) {
        pp = s_pidhash[i];
        while(pp) {
            psp->pid = pp;
            psp->pid_value = pp->pid_value;
            psp++;
            pp = pp->next;
        }
    }

    qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp);

    /* put the sort order into the pid objects */
    psp = g_pids;

    /*
     * This is rather gross.
     *
     * We happen to know that whenever this function is called, the hash table
     * structure itself is immediately torn down. So the "next" pointers in the
     * pid_data_t elements are about to become useless.
     *
     * So we re-use them, to link all the pid_data_t elements together into a
     * single unified linked list, with g_pid_data_list pointing to the head.
     * This means we can walk all the pid_data_t objects if we really want to.
     * Reading snapshots from disk is one example.
     *
     * Alternatively we could just leave the hash table in place; this is
     * far nicer, but as it happens, trading O(n) lookups for O(1) lookups
     * isn't actually a problem for the restricted post-tear-down usage. So for
     * now we take the memory savings and swap our hash table for a list.
     */
    p_previous = &g_pid_data_list;
    for (i = 0; i < g_npids; i++) {
        pp = psp->pid;
        pp->pid_index = i;
        *p_previous = pp;
        p_previous = &pp->next;
        psp++;
    }
    *p_previous = NULL;

    /*
     * Squirrel away original (sorted) vector, so we can
     * toggle between "chase" mode, snapshots, and the original
     * display method on short notice 
     */
    g_original_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);
    memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids); 
}

/****************************************************************************
* read_events
****************************************************************************/

void read_events(char *filename)
{
    ulong *ulp;
    ulong size;
    event_t *ep;
    raw_event_t *rep;
    ulonglong start_time=0ULL;
    ulonglong low_time;
    boolean once=TRUE;
    int i;
    char tmpbuf [128];

    ulp = (ulong *)mapfile(filename, &size);

    if (ulp == NULL) {
        sprintf(tmpbuf, "Couldn't open %s\n", filename);
        infobox("Read Event Log Failure", tmpbuf);
        return;
    }

    g_nevents = ntohl(*ulp);

    if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) {
        sprintf(tmpbuf, "%s was damaged, or isn't an event log.\n", filename);
        infobox("Bad Input File", tmpbuf);
        g_nevents = 0;
        unmapfile((char *)ulp, size);
        return;
    }

    rep = (raw_event_t *)(ulp+1);

    if (g_events)
        g_free(g_events);

    g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t));
    ep = g_events;

    while (g_npids > 0) {
        g_free((g_pids + g_npids-1)->pid);
        g_npids--;
    }
    if (g_pids) {
        g_free(g_pids);
        g_free(g_original_pids);
        g_pids = 0;
        g_original_pids = 0;
    }

    s_pidhash = (pid_data_t **)g_malloc0(
        PIDHASH_NBUCKETS*sizeof(pid_data_t *));

    /* $$$ add a SEGV handler... */
    for (i = 0; i < g_nevents; i++) {
        if (once) {
            once = FALSE;
            start_time = ((ulonglong)ntohl(rep->time[0]));
            start_time <<= 32;
            low_time = ntohl(rep->time[1]);
            low_time &= 0xFFFFFFFF;
            start_time |= low_time;
            ep->time = 0LL;
        } else {
            ep->time = ((ulonglong)ntohl(rep->time[0]));
            ep->time <<= 32;
            low_time = ntohl(rep->time[1]);
            low_time &= 0xFFFFFFFF;
            ep->time |= low_time;
            ep->time -= start_time;
            ep->time /= ticks_per_ns;
        }
        ep->code = ntohl(rep->code);
        ep->pid = find_or_add_pid(ntohl(rep->pid));
        ep->datum = ntohl(rep->datum);
        ep->flags = 0;
        ep++;
        rep++;
    }

    unmapfile((char *)ulp, size);
    
    make_sorted_pid_vector();
    g_free(s_pidhash);
    s_pidhash = 0;

    /* Give the view-1 world a chance to reset a few things... */
    view1_read_events_callback();
}

static event_t *add_ep;

/****************************************************************************
* cpel_event_init
****************************************************************************/
void cpel_event_init (ulong nevents)
{
    g_nevents = nevents;
    if (g_events)
        g_free(g_events);
    add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t));
    while (g_npids > 0) {
        g_free((g_pids + g_npids-1)->pid);
        g_npids--;
    }
    if (g_pids) {
        g_free(g_pids);
        g_free(g_original_pids);
        g_pids = 0;
        g_original_pids = 0;
    }
    s_pidhash = (pid_data_t **)g_malloc0(
        PIDHASH_NBUCKETS*sizeof(pid_data_t *));
}

/****************************************************************************
* add_cpel_event
****************************************************************************/

void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum)
{
    event_t *ep;

    ep = add_ep++;
    ep->time = delta;
    ep->pid = find_or_add_pid(track);
    ep->code = event;
    ep->datum = datum;
    ep->flags = 0;
}

/****************************************************************************
* add_clib_event
****************************************************************************/

void add_clib_event(double delta, unsigned short track, 
                    unsigned short event, unsigned int index)
{
    event_t *ep;

    ep = add_ep++;
    ep->time = (ulonglong) (delta * 1e9); /* time in integer nanoseconds */
    ep->pid = find_or_add_pid(track);
    ep->code = event;
    ep->datum = index;
    ep->flags = EVENT_FLAG_CLIB;
}

/****************************************************************************
* cpel_event_finalize
****************************************************************************/

void cpel_event_finalize(void)
{
    make_sorted_pid_vector();
    g_free(s_pidhash);
    s_pidhash = 0;
    
    /* Give the view-1 world a chance to reset a few things... */
    view1_read_events_callback();
}

/****************************************************************************
* mapfile
****************************************************************************/

char *mapfile (char *file, ulong *sizep)
{
    struct stat statb;
    char *rv;
    int maphfile;
    size_t mapfsize;
    
    maphfile = open (file, O_RDONLY);

    if (maphfile < 0)
        return (NULL);

    if (fstat (maphfile, &statb) < 0) {
        return (NULL);
    }

    /* Don't try to mmap directories, FIFOs, semaphores, etc. */
    if (! (statb.st_mode & S_IFREG)) {
        return (NULL);
    }

    mapfsize = statb.st_size;

    if (mapfsize < 3) {
        close (maphfile);
        return (NULL);
    }

    rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0);

    if (rv == 0) {
        g_error ("%s mapping problem, I quit...\n", file);
    }

    close (maphfile);

    if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) {
        return (rv);
    }

    if (sizep) {
        *sizep = mapfsize;
    }
    return (rv);
}

/****************************************************************************
* unmapfile
****************************************************************************/

boolean unmapfile (char *addr, ulong size)
{
    if (munmap (addr, size) < 0) {
        g_warning("Unmap error, addr 0x%lx size 0x%x\n", 
                  (unsigned long) addr, (unsigned int)size);
        return(FALSE);
    }
    return(TRUE);
}

/****************************************************************************
* find_event_index
* Binary search for first event whose time is >= t
****************************************************************************/

int find_event_index (ulonglong t)
{
    int index, bottom, top;
    event_t *ep;

    bottom = g_nevents-1;
    top = 0;

    while (1) {
	index = (bottom + top) / 2;

        ep = (g_events + index);

        if (ep->time == t)
            return(index);

        if (top >= bottom) {
            while (index > 0 && ep->time > t) {
                ep--;
                index--;
            }
            while (index < g_nevents && ep->time < t) {
                ep++;
                index++;
            }
            return(index);
        }

        if (ep->time < t)
            top = index + 1;
        else 
            bottom = index - 1;
    }
}

/****************************************************************************
* events_about
****************************************************************************/

void events_about (char *tmpbuf)
{
    sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n", 
            (int)g_nevents, ticks_per_ns);
}