summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/imsg.c3
-rw-r--r--lib/json.c15
-rw-r--r--lib/json.h4
-rw-r--r--lib/prefix.h17
-rw-r--r--lib/thread.c64
-rw-r--r--lib/thread.h1
-rw-r--r--lib/wheel.c164
-rw-r--r--lib/wheel.h70
-rw-r--r--lib/zebra.h3
10 files changed, 306 insertions, 39 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1bb2d395c8..f2c076c475 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -24,7 +24,7 @@ libzebra_la_SOURCES = \
sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \
ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \
imsg-buffer.c imsg.c skiplist.c \
- qobj.c \
+ qobj.c wheel.c \
event_counter.c \
strlcpy.c \
strlcat.c
@@ -45,7 +45,7 @@ pkginclude_HEADERS = \
workqueue.h route_types.h libospf.h nexthop.h json.h \
ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h \
- skiplist.h qobj.h \
+ skiplist.h qobj.h wheel.h \
event_counter.h
noinst_HEADERS = \
diff --git a/lib/imsg.c b/lib/imsg.c
index 246430cdd5..fc62c13734 100644
--- a/lib/imsg.c
+++ b/lib/imsg.c
@@ -182,7 +182,8 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
else
imsg->fd = -1;
- memcpy(imsg->data, ibuf->r.rptr, datalen);
+ if (imsg->data)
+ memcpy(imsg->data, ibuf->r.rptr, datalen);
if (imsg->hdr.len < av) {
left = av - imsg->hdr.len;
diff --git a/lib/json.c b/lib/json.c
index 3edd146a8f..ccbecb726a 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -87,3 +87,18 @@ json_object_free(struct json_object *obj)
{
json_object_put(obj);
}
+
+#if !defined(HAVE_JSON_C_JSON_H)
+int
+json_object_object_get_ex(struct json_object *obj,
+ const char *key,
+ struct json_object **value)
+{
+ *value = json_object_object_get(obj, key);
+
+ if (*value)
+ return 1;
+
+ return 0;
+}
+#endif
diff --git a/lib/json.h b/lib/json.h
index bacc799519..7e98614280 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -32,6 +32,10 @@
* so let's just turn it back to the original usage.
*/
#define json_object_to_json_string_ext(A, B) json_object_to_json_string (A)
+
+extern int json_object_object_get_ex(struct json_object *obj,
+ const char *key,
+ struct json_object **value);
#endif
#include "command.h"
diff --git a/lib/prefix.h b/lib/prefix.h
index 5e4b1f9c83..45e6368463 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -134,6 +134,14 @@ struct prefix_ptr
uintptr_t prefix __attribute__ ((aligned (8)));
};
+struct prefix_sg
+{
+ u_char family;
+ u_char prefixlen;
+ struct in_addr src __attribute ((aligned (8)));
+ struct in_addr grp;
+};
+
/* helper to get type safety/avoid casts on calls
* (w/o this, functions accepting all prefix types need casts on the caller
* side, which strips type safety since the cast will accept any pointer
@@ -222,13 +230,8 @@ extern const char *prefix_family_str (const struct prefix *);
extern int prefix_blen (const struct prefix *);
extern int str2prefix (const char *, struct prefix *);
-/*
- * 8 groups of 4 bytes of hexadecimal + 7 seperators is 39
- * /128 = 4 bytes
- * Null = 1 byte
- * 39 + 4 + 1 = 44 bytes
- */
-#define PREFIX2STR_BUFFER 44
+#define PREFIX2STR_BUFFER PREFIX_STRLEN
+
extern const char *prefix2str (union prefix46constptr, char *, int);
extern int prefix_match (const struct prefix *, const struct prefix *);
extern int prefix_same (const struct prefix *, const struct prefix *);
diff --git a/lib/thread.c b/lib/thread.c
index eac7f3250b..64eaae45b9 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -221,8 +221,8 @@ static void
vty_out_cpu_thread_history(struct vty* vty,
struct cpu_thread_history *a)
{
- vty_out(vty, "%10ld.%03ld %9d %8ld %9ld %8ld %9ld",
- a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
+ vty_out(vty, "%5d %10ld.%03ld %9d %8ld %9ld %8ld %9ld",
+ a->total_active, a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
a->cpu.total/a->total_calls, a->cpu.max,
a->real.total/a->total_calls, a->real.max);
vty_out(vty, " %c%c%c%c%c%c %s%s",
@@ -247,6 +247,7 @@ cpu_record_hash_print(struct hash_backet *bucket,
if ( !(a->types & *filter) )
return;
vty_out_cpu_thread_history(vty,a);
+ totals->total_active += a->total_active;
totals->total_calls += a->total_calls;
totals->real.total += a->real.total;
if (totals->real.max < a->real.max)
@@ -268,7 +269,7 @@ cpu_record_print(struct vty *vty, thread_type filter)
vty_out(vty, "%21s %18s %18s%s",
"", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
- vty_out(vty, " Runtime(ms) Invoked Avg uSec Max uSecs");
+ vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
vty_out(vty, " Avg uSec Max uSecs");
vty_out(vty, " Type Thread%s", VTY_NEWLINE);
hash_iterate(cpu_record,
@@ -570,7 +571,9 @@ thread_add_unuse (struct thread_master *m, struct thread *thread)
assert (m != NULL && thread != NULL);
assert (thread->next == NULL);
assert (thread->prev == NULL);
- assert (thread->type == THREAD_UNUSED);
+
+ thread->type = THREAD_UNUSED;
+ thread->hist->total_active--;
thread_list_add (&m->unuse, thread);
}
@@ -693,6 +696,7 @@ thread_get (struct thread_master *m, u_char type,
int (*func) (struct thread *), void *arg, debugargdef)
{
struct thread *thread = thread_trim_head (&m->unuse);
+ struct cpu_thread_history tmp;
if (! thread)
{
@@ -702,11 +706,30 @@ thread_get (struct thread_master *m, u_char type,
thread->type = type;
thread->add_type = type;
thread->master = m;
- thread->func = func;
thread->arg = arg;
thread->index = -1;
thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
+ /*
+ * So if the passed in funcname is not what we have
+ * stored that means the thread->hist needs to be
+ * updated. We keep the last one around in unused
+ * under the assumption that we are probably
+ * going to immediately allocate the same
+ * type of thread.
+ * This hopefully saves us some serious
+ * hash_get lookups.
+ */
+ if (thread->funcname != funcname ||
+ thread->func != func)
+ {
+ tmp.func = func;
+ tmp.funcname = funcname;
+ thread->hist = hash_get (cpu_record, &tmp,
+ (void * (*) (void *))cpu_record_hash_alloc);
+ }
+ thread->hist->total_active++;
+ thread->func = func;
thread->funcname = funcname;
thread->schedfrom = schedfrom;
thread->schedfrom_line = fromln;
@@ -1063,7 +1086,6 @@ thread_cancel (struct thread *thread)
assert(!"Thread should be either in queue or list or array!");
}
- thread->type = THREAD_UNUSED;
thread_add_unuse (thread->master, thread);
}
@@ -1086,7 +1108,6 @@ thread_cancel_event (struct thread_master *m, void *arg)
{
ret++;
thread_list_delete (&m->event, t);
- t->type = THREAD_UNUSED;
thread_add_unuse (m, t);
}
}
@@ -1104,7 +1125,6 @@ thread_cancel_event (struct thread_master *m, void *arg)
{
ret++;
thread_list_delete (&m->ready, t);
- t->type = THREAD_UNUSED;
thread_add_unuse (m, t);
}
}
@@ -1128,7 +1148,6 @@ thread_run (struct thread_master *m, struct thread *thread,
struct thread *fetch)
{
*fetch = *thread;
- thread->type = THREAD_UNUSED;
thread_add_unuse (m, thread);
return fetch;
}
@@ -1427,23 +1446,6 @@ thread_call (struct thread *thread)
unsigned long realtime, cputime;
RUSAGE_T before, after;
- /* Cache a pointer to the relevant cpu history thread, if the thread
- * does not have it yet.
- *
- * Callers submitting 'dummy threads' hence must take care that
- * thread->cpu is NULL
- */
- if (!thread->hist)
- {
- struct cpu_thread_history tmp;
-
- tmp.func = thread->func;
- tmp.funcname = thread->funcname;
-
- thread->hist = hash_get (cpu_record, &tmp,
- (void * (*) (void *))cpu_record_hash_alloc);
- }
-
GETRUSAGE (&before);
thread->real = before.real;
@@ -1488,18 +1490,22 @@ funcname_thread_execute (struct thread_master *m,
int val,
debugargdef)
{
- struct thread dummy;
+ struct cpu_thread_history tmp;
+ struct thread dummy;
memset (&dummy, 0, sizeof (struct thread));
dummy.type = THREAD_EVENT;
dummy.add_type = THREAD_EXECUTE;
dummy.master = NULL;
- dummy.func = func;
dummy.arg = arg;
dummy.u.val = val;
- dummy.funcname = funcname;
+ tmp.func = dummy.func = func;
+ tmp.funcname = dummy.funcname = funcname;
+ dummy.hist = hash_get (cpu_record, &tmp,
+ (void * (*) (void *))cpu_record_hash_alloc);
+
dummy.schedfrom = schedfrom;
dummy.schedfrom_line = fromln;
diff --git a/lib/thread.h b/lib/thread.h
index 5c6b96a32d..c22bb4828d 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -115,6 +115,7 @@ struct cpu_thread_history
{
int (*func)(struct thread *);
unsigned int total_calls;
+ unsigned int total_active;
struct time_stats
{
unsigned long total, max;
diff --git a/lib/wheel.c b/lib/wheel.c
new file mode 100644
index 0000000000..fe53dea299
--- /dev/null
+++ b/lib/wheel.c
@@ -0,0 +1,164 @@
+/*
+ * Timer Wheel
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#include "zebra.h"
+#include "linklist.h"
+#include "thread.h"
+#include "memory.h"
+#include "wheel.h"
+#include "log.h"
+
+DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel")
+DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List")
+
+static int debug_timer_wheel = 0;
+
+static int
+wheel_timer_thread (struct thread *t)
+{
+ struct listnode *node, *nextnode;
+ unsigned long long curr_slot;
+ unsigned int slots_to_skip = 1;
+ struct timer_wheel *wheel;
+ void *data;
+
+ wheel = THREAD_ARG(t);
+ THREAD_OFF(wheel->timer);
+
+ wheel->curr_slot += wheel->slots_to_skip;
+
+ curr_slot = wheel->curr_slot % wheel->slots;
+
+ if (debug_timer_wheel)
+ zlog_debug ("%s: Wheel Slot: %lld(%lld) count: %d",
+ __PRETTY_FUNCTION__,
+ wheel->curr_slot,
+ curr_slot, listcount(wheel->wheel_slot_lists[curr_slot]));
+
+ for (ALL_LIST_ELEMENTS (wheel->wheel_slot_lists[curr_slot], node, nextnode, data))
+ (*wheel->slot_run)(data);
+
+ while (list_isempty(wheel->wheel_slot_lists[(curr_slot + slots_to_skip) % wheel->slots]) &&
+ (curr_slot + slots_to_skip ) % wheel->slots != curr_slot)
+ slots_to_skip++;
+
+ wheel->slots_to_skip = slots_to_skip;
+ THREAD_TIMER_MSEC_ON (wheel->master, wheel->timer,
+ wheel_timer_thread, wheel,
+ wheel->nexttime * slots_to_skip);
+
+ return 0;
+}
+
+struct timer_wheel *
+wheel_init (struct thread_master *master, int period, size_t slots,
+ unsigned int (*slot_key) (void *),
+ void (*slot_run) (void *))
+{
+ struct timer_wheel *wheel;
+ size_t i;
+
+ wheel = XCALLOC(MTYPE_TIMER_WHEEL, sizeof (struct timer_wheel));
+
+ wheel->slot_key = slot_key;
+ wheel->slot_run = slot_run;
+
+ wheel->period = period;
+ wheel->slots = slots;
+ wheel->curr_slot = 0;
+ wheel->master = master;
+ wheel->nexttime = period / slots;
+
+ wheel->wheel_slot_lists = XCALLOC(MTYPE_TIMER_WHEEL_LIST,
+ slots * sizeof (struct listnode *));
+ for (i = 0; i < slots; i++)
+ wheel->wheel_slot_lists[i] = list_new ();
+
+ THREAD_TIMER_MSEC_ON (wheel->master, wheel->timer,
+ wheel_timer_thread, wheel,
+ wheel->nexttime);
+
+ return wheel;
+}
+
+void
+wheel_delete (struct timer_wheel *wheel)
+{
+ int i;
+
+ for (i = 0; i < wheel->slots; i++)
+ {
+ list_delete(wheel->wheel_slot_lists[i]);
+ }
+
+ THREAD_OFF(wheel->timer);
+ XFREE(MTYPE_TIMER_WHEEL_LIST, wheel->wheel_slot_lists);
+ XFREE(MTYPE_TIMER_WHEEL, wheel);
+}
+
+int
+wheel_stop (struct timer_wheel *wheel)
+{
+ THREAD_OFF(wheel->timer);
+ return 0;
+}
+
+int
+wheel_start (struct timer_wheel *wheel)
+{
+ if (!wheel->timer)
+ THREAD_TIMER_MSEC_ON (wheel->master, wheel->timer,
+ wheel_timer_thread, wheel,
+ wheel->nexttime);
+
+ return 0;
+}
+
+int
+wheel_add_item (struct timer_wheel *wheel, void *item)
+{
+ long long slot;
+
+ slot = (*wheel->slot_key)(item);
+
+ if (debug_timer_wheel)
+ zlog_debug ("%s: Inserting %p: %lld %lld",
+ __PRETTY_FUNCTION__, item,
+ slot, slot % wheel->slots);
+ listnode_add (wheel->wheel_slot_lists[slot % wheel->slots], item);
+
+ return 0;
+}
+
+int
+wheel_remove_item (struct timer_wheel *wheel, void *item)
+{
+ long long slot;
+
+ slot = (*wheel->slot_key)(item);
+
+ if (debug_timer_wheel)
+ zlog_debug ("%s: Removing %p: %lld %lld",
+ __PRETTY_FUNCTION__, item,
+ slot, slot % wheel->slots);
+ listnode_delete (wheel->wheel_slot_lists[slot % wheel->slots], item);
+
+ return 0;
+}
diff --git a/lib/wheel.h b/lib/wheel.h
new file mode 100644
index 0000000000..ddb79988b4
--- /dev/null
+++ b/lib/wheel.h
@@ -0,0 +1,70 @@
+/*
+ * Timer Wheel
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#ifndef __WHEEL_H__
+#define __WHEEL_H__
+
+struct timer_wheel
+{
+ struct thread_master *master;
+ int slots;
+ long long curr_slot;
+ unsigned int period;
+ unsigned int nexttime;
+ unsigned int slots_to_skip;
+
+ struct list **wheel_slot_lists;
+ struct thread *timer;
+ /*
+ * Key to determine what slot the item belongs in
+ */
+ unsigned int (*slot_key) (void *);
+
+ void (*slot_run) (void *);
+};
+
+struct timer_wheel *wheel_init (struct thread_master *master, int period, size_t slots,
+ unsigned int (*slot_key) (void *),
+ void (*slot_run) (void *));
+void wheel_delete (struct timer_wheel *);
+
+/*
+ * Pause the Wheel from running
+ */
+int wheel_stop (struct timer_wheel *wheel);
+
+/*
+ * Start the wheel from running again
+ */
+int wheel_start (struct timer_wheel *wheel);
+
+/*
+ * Add item to a slot setup by the slot_key,
+ * possibly change next time pop.
+ */
+int wheel_add_item (struct timer_wheel *wheel, void *item);
+
+/*
+ * Remove a item to a slot setup by the slot_key,
+ * possibly change next time pop.
+ */
+int wheel_remove_item (struct timer_wheel *wheel, void *item);
+
+#endif
diff --git a/lib/zebra.h b/lib/zebra.h
index 5a58cf8e6e..c9be1892e4 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -489,6 +489,9 @@ typedef enum {
#define IANA_AFI_RESERVED 0
#define IANA_AFI_IPV4 1
#define IANA_AFI_IPV6 2
+#define IANA_AFI_L2VPN 25
+#define IANA_AFI_IPMR 128
+#define IANA_AFI_IP6MR 129
#define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1