summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--zebra/if_netlink.c2
-rw-r--r--zebra/kernel_netlink.c62
-rw-r--r--zebra/kernel_netlink.h8
-rw-r--r--zebra/rt_netlink.c173
-rw-r--r--zebra/zebra_fpm.c6
-rw-r--r--zebra/zebra_fpm_netlink.c16
-rw-r--r--zebra/zebra_rib.c2
-rw-r--r--zebra/zebra_static.c2
-rw-r--r--zebra/zebra_static.h15
-rw-r--r--zebra/zebra_vty.c13
-rw-r--r--zebra/zserv.c17
-rw-r--r--zebra/zserv.h2
22 files changed, 563 insertions, 100 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
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 3665ad061d..d553850546 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -433,7 +433,7 @@ netlink_address (int cmd, int family, struct interface *ifp,
addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
strlen (ifc->label) + 1);
- return netlink_talk (&req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
}
int
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 9f9a62f384..fb1015e5d5 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -63,6 +63,14 @@
((struct rtattr *) (((u_char *) (rta)) + RTA_ALIGN((rta)->rta_len)))
#endif
+#ifndef RTNL_FAMILY_IP6MR
+#define RTNL_FAMILY_IP6MR 129
+#endif
+
+#ifndef RTPROT_MROUTED
+#define RTPROT_MROUTED 17
+#endif
+
static const struct message nlmsg_str[] = {
{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_DELROUTE, "RTM_DELROUTE"},
@@ -91,15 +99,31 @@ static const struct message rtproto_str[] = {
#ifdef RTPROT_BIRD
{RTPROT_BIRD, "BIRD"},
#endif /* RTPROT_BIRD */
+ {RTPROT_MROUTED, "mroute"},
{0, NULL}
};
+static const struct message family_str[] = {
+ {AF_INET, "ipv4"},
+ {AF_INET6, "ipv6"},
+ {AF_BRIDGE, "bridge"},
+ {RTNL_FAMILY_IPMR, "ipv4MR"},
+ {RTNL_FAMILY_IP6MR, "ipv6MR"},
+ {0, NULL},
+};
+
+static const struct message rttype_str[] = {
+ {RTN_UNICAST, "unicast"},
+ {RTN_MULTICAST, "multicast"},
+ {0, NULL},
+};
+
extern struct thread_master *master;
extern u_int32_t nl_rcvbufsize;
extern struct zebra_privs_t zserv_privs;
-static int
+int
netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id)
{
@@ -321,7 +345,12 @@ addattr_l (struct nlmsghdr *n, unsigned int maxlen, int type,
rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
rta->rta_type = type;
rta->rta_len = len;
- memcpy (RTA_DATA (rta), data, alen);
+
+ if (data)
+ memcpy (RTA_DATA (rta), data, alen);
+ else
+ assert (len == 0);
+
n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
return 0;
@@ -342,7 +371,12 @@ rta_addattr_l (struct rtattr *rta, unsigned int maxlen, int type,
subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
subrta->rta_type = type;
subrta->rta_len = len;
- memcpy (RTA_DATA (subrta), data, alen);
+
+ if (data)
+ memcpy (RTA_DATA (subrta), data, alen);
+ else
+ assert (len == 0);
+
rta->rta_len = NLMSG_ALIGN (rta->rta_len) + RTA_ALIGN (len);
return 0;
@@ -397,6 +431,19 @@ nl_rtproto_to_str (u_char rtproto)
{
return lookup (rtproto_str, rtproto);
}
+
+const char *
+nl_family_to_str (u_char family)
+{
+ return lookup (family_str, family);
+}
+
+const char *
+nl_rttype_to_str (u_char rttype)
+{
+ return lookup (rttype_str, rttype);
+}
+
/* Receive message from netlink interface and pass those information
to the given function. */
int
@@ -592,7 +639,9 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
/* sendmsg() to netlink socket then recvmsg(). */
int
-netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns)
+netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
+ ns_id_t),
+ struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns)
{
int status;
struct sockaddr_nl snl;
@@ -648,7 +697,7 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns)
* Get reply from netlink socket.
* The reply should either be an acknowlegement or an error.
*/
- return netlink_parse_info (netlink_talk_filter, nl, zns, 0);
+ return netlink_parse_info (filter, nl, zns, 0);
}
/* Get type specified information from netlink. */
@@ -718,7 +767,8 @@ kernel_init (struct zebra_ns *zns)
/* Initialize netlink sockets */
groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR |
- RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
+ RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR |
+ RTMGRP_IPV4_MROUTE;
snprintf (zns->netlink.name, sizeof (zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index 890236c047..f17f1380c2 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -40,11 +40,17 @@ extern struct rtattr * rta_nest(struct rtattr *rta, int maxlen, int type);
extern int rta_nest_end(struct rtattr *rta, struct rtattr *nest);
extern const char * nl_msg_type_to_str (uint16_t msg_type);
extern const char * nl_rtproto_to_str (u_char rtproto);
+extern const char * nl_family_to_str (u_char family);
+extern const char * nl_rttype_to_str (u_char rttype);
extern int netlink_parse_info (int (*filter) (struct sockaddr_nl *,
struct nlmsghdr *, ns_id_t), struct nlsock *nl,
struct zebra_ns *zns, int count);
-extern int netlink_talk (struct nlmsghdr *n, struct nlsock *nl,
+extern int netlink_talk_filter (struct sockaddr_nl *, struct nlmsghdr *,
+ ns_id_t);
+extern int netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
+ ns_id_t),
+ struct nlmsghdr *n, struct nlsock *nl,
struct zebra_ns *zns);
extern int netlink_request (int family, int type, struct nlsock *nl);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 2e7f336d20..913d1d5770 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -77,6 +77,10 @@
#define RTA_ENCAP 22
#endif
+#ifndef RTA_EXPIRES
+#define RTA_EXPIRES 23
+#endif
+
#ifndef LWTUNNEL_ENCAP_MPLS
#define LWTUNNEL_ENCAP_MPLS 1
#endif
@@ -304,8 +308,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
}
/* Routing information change from the kernel. */
-int
-netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
+static int
+netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id)
{
int len;
@@ -327,35 +331,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
rtm = NLMSG_DATA (h);
- if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
- {
- /* If this is not route add/delete message print warning. */
- zlog_warn ("Kernel message: %d", h->nlmsg_type);
- return 0;
- }
-
- /* Connected route. */
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("%s %s %s proto %s",
- h->nlmsg_type ==
- RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
- rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
- rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
- nl_rtproto_to_str (rtm->rtm_protocol));
-
- if (rtm->rtm_type != RTN_UNICAST)
- {
- return 0;
- }
-
- /* We don't care about change notifications for the MPLS table. */
- /* TODO: Revisit this. */
- if (rtm->rtm_family == AF_MPLS)
- return 0;
-
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
- if (len < 0)
- return -1;
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
@@ -441,7 +417,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
{
char buf[PREFIX_STRLEN];
zlog_debug ("%s %s vrf %u",
- h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
+ nl_msg_type_to_str (h->nlmsg_type),
prefix2str (&p, buf, sizeof(buf)), vrf_id);
}
@@ -528,7 +504,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
{
char buf[PREFIX_STRLEN];
zlog_debug ("%s %s vrf %u",
- h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
+ nl_msg_type_to_str (h->nlmsg_type),
prefix2str (&p, buf, sizeof(buf)), vrf_id);
}
@@ -544,6 +520,133 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
return 0;
}
+static int
+netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ ns_id_t ns_id)
+{
+ int len;
+ unsigned long long lastused = 0;
+ struct rtmsg *rtm;
+ struct rtattr *tb[RTA_MAX + 1];
+ struct prefix_sg sg;
+ int iif = 0;
+ int count;
+ int oif[256];
+ int oif_count = 0;
+ char sbuf[40];
+ char gbuf[40];
+ char oif_list[256] = "\0";
+ memset (&sg, 0, sizeof (sg));
+ sg.family = IANA_AFI_IPMR;
+ vrf_id_t vrf = ns_id;
+
+ rtm = NLMSG_DATA (h);
+
+ len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
+
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+ if (tb[RTA_IIF])
+ iif = *(int *)RTA_DATA (tb[RTA_IIF]);
+
+ if (tb[RTA_SRC])
+ sg.src = *(struct in_addr *)RTA_DATA (tb[RTA_SRC]);
+
+ if (tb[RTA_DST])
+ sg.grp = *(struct in_addr *)RTA_DATA (tb[RTA_DST]);
+
+ if ((RTA_EXPIRES <= RTA_MAX) && tb[RTA_EXPIRES])
+ lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]);
+
+ if (tb[RTA_MULTIPATH])
+ {
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *)RTA_DATA (tb[RTA_MULTIPATH]);
+
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+ for (;;)
+ {
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ oif[oif_count] = rtnh->rtnh_ifindex;
+ oif_count++;
+
+ len -= NLMSG_ALIGN (rtnh->rtnh_len);
+ rtnh = RTNH_NEXT (rtnh);
+ }
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ strcpy (sbuf, inet_ntoa (sg.src));
+ strcpy (gbuf, inet_ntoa (sg.grp));
+ for (count = 0; count < oif_count; count++)
+ {
+ struct interface *ifp = if_lookup_by_index_vrf (oif[count], vrf);
+ char temp[256];
+
+ sprintf (temp, "%s ", ifp->name);
+ strcat (oif_list, temp);
+ }
+ zlog_debug ("MCAST %s (%s,%s) IIF: %d OIF: %s jiffies: %lld",
+ nl_msg_type_to_str (h->nlmsg_type), sbuf, gbuf, iif, oif_list, lastused);
+ }
+ return 0;
+}
+
+int
+netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ ns_id_t ns_id)
+{
+ int len;
+ vrf_id_t vrf_id = ns_id;
+ struct rtmsg *rtm;
+
+ rtm = NLMSG_DATA (h);
+
+ if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
+ {
+ /* If this is not route add/delete message print warning. */
+ zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id);
+ return 0;
+ }
+
+ /* Connected route. */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s %s %s proto %s vrf %u",
+ nl_msg_type_to_str (h->nlmsg_type),
+ nl_family_to_str (rtm->rtm_family),
+ nl_rttype_to_str (rtm->rtm_type),
+ nl_rtproto_to_str (rtm->rtm_protocol),
+ vrf_id);
+
+ /* We don't care about change notifications for the MPLS table. */
+ /* TODO: Revisit this. */
+ if (rtm->rtm_family == AF_MPLS)
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
+ if (len < 0)
+ return -1;
+
+ switch (rtm->rtm_type)
+ {
+ case RTN_UNICAST:
+ netlink_route_change_read_unicast (snl, h, ns_id);
+ break;
+ case RTN_MULTICAST:
+ netlink_route_change_read_multicast (snl, h, ns_id);
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return 0;
+}
+
/* Routing table read function using netlink interface. Only called
bootstrap time. */
int
@@ -1108,7 +1211,7 @@ netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen
addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
- return netlink_talk (&req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
}
/* Routing table change via netlink interface. */
@@ -1403,7 +1506,7 @@ skip:
snl.nl_family = AF_NETLINK;
/* Talk to netlink socket. */
- return netlink_talk (&req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
}
int
@@ -1593,7 +1696,7 @@ netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp)
}
/* Talk to netlink socket. */
- return netlink_talk (&req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
}
/*
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 80512c71f6..8b337152b4 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -1622,14 +1622,16 @@ zfpm_init_message_format (const char *format)
{
int have_netlink, have_protobuf;
- have_netlink = have_protobuf = 0;
-
#ifdef HAVE_NETLINK
have_netlink = 1;
+#else
+ have_netlink = 0;
#endif
#ifdef HAVE_PROTOBUF
have_protobuf = 1;
+#else
+ have_protobuf = 0;
#endif
zfpm_g->message_format = ZFPM_MSG_FORMAT_NONE;
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index 0d9f809328..2c781899f4 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -251,10 +251,15 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
* particularly in our communication with the FPM.
*/
if (cmd == RTM_DELROUTE && !rib)
- goto skip;
+ return 1;
- if (rib)
- ri->rtm_protocol = netlink_proto_from_route_type (rib->type);
+ if (!rib)
+ {
+ zfpm_debug ("%s: Expected non-NULL rib pointer", __PRETTY_FUNCTION__);
+ return 0;
+ }
+
+ ri->rtm_protocol = netlink_proto_from_route_type (rib->type);
if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
discard = 1;
@@ -279,9 +284,7 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
ri->metric = &rib->metric;
if (discard)
- {
- goto skip;
- }
+ return 1;
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
{
@@ -307,7 +310,6 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
return 0;
}
- skip:
return 1;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index e48da0479b..59893b1a0f 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1633,7 +1633,7 @@ rib_process (struct route_node *rn)
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%u:%s/%d: Processing rn %p", vrf_id, buf, rn->p.prefixlen, rn);
- RNODE_FOREACH_RIB (rn, rib)
+ RNODE_FOREACH_RIB_SAFE (rn, rib, next)
{
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%u:%s/%d: Examine rib %p (type %d) status %x flags %x "
diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c
index b323950064..7d104f30d9 100644
--- a/zebra/zebra_static.c
+++ b/zebra/zebra_static.c
@@ -50,6 +50,8 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
if (! table)
return;
+ memset (&nh_p, 0, sizeof (nh_p));
+
/* Lookup existing route */
rn = route_node_get (table, p);
RNODE_FOREACH_RIB (rn, rib)
diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h
index 5e3177e3b8..233436f02d 100644
--- a/zebra/zebra_static.h
+++ b/zebra/zebra_static.h
@@ -31,6 +31,14 @@ struct static_nh_label
mpls_label_t label[2];
};
+typedef enum {
+ STATIC_IFINDEX,
+ STATIC_IPV4_GATEWAY,
+ STATIC_BLACKHOLE,
+ STATIC_IPV6_GATEWAY,
+ STATIC_IPV6_GATEWAY_IFINDEX,
+} zebra_static_types;
+
/* Static route information. */
struct static_route
{
@@ -48,12 +56,7 @@ struct static_route
route_tag_t tag;
/* Flag for this static route's type. */
- u_char type;
-#define STATIC_IFINDEX 1
-#define STATIC_IPV4_GATEWAY 2
-#define STATIC_BLACKHOLE 3
-#define STATIC_IPV6_GATEWAY 4
-#define STATIC_IPV6_GATEWAY_IFINDEX 5
+ zebra_static_types type;
/*
* Nexthop value.
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 3138e7c867..113b063913 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -31,7 +31,6 @@
#include "nexthop.h"
#include "vrf.h"
#include "mpls.h"
-#include "lib/json.h"
#include "routemap.h"
#include "zebra/zserv.h"
@@ -41,6 +40,7 @@
#include "zebra/redistribute.h"
#include "zebra/zebra_routemap.h"
#include "zebra/zebra_static.h"
+#include "lib/json.h"
extern int allow_delete;
@@ -2282,6 +2282,14 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd)
case STATIC_BLACKHOLE:
vty_out (vty, " Null0");
break;
+ case STATIC_IPV6_GATEWAY:
+ vty_out (vty, " %s", inet_ntop (AF_INET6, &si->addr.ipv6, buf, BUFSIZ));
+ break;
+ case STATIC_IPV6_GATEWAY_IFINDEX:
+ vty_out (vty, " %s %s",
+ inet_ntop (AF_INET6, &si->addr.ipv6, buf, BUFSIZ),
+ ifindex2ifname_vrf (si->ifindex, si->vrf_id));
+ break;
}
/* flags are incompatible with STATIC_BLACKHOLE */
@@ -3591,6 +3599,9 @@ static_config_ipv6 (struct vty *vty)
switch (si->type)
{
+ case STATIC_IPV4_GATEWAY:
+ vty_out (vty, " %s", inet_ntoa (si->addr.ipv4));
+ break;
case STATIC_IPV6_GATEWAY:
vty_out (vty, " %s", inet_ntop (AF_INET6, &si->addr.ipv6, buf, BUFSIZ));
break;
diff --git a/zebra/zserv.c b/zebra/zserv.c
index d3c204d119..6a15b9a251 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -1519,7 +1519,7 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
struct stream *s;
struct zapi_ipv6 api;
struct in6_addr nexthop;
- union g_addr *pnexthop;
+ union g_addr *pnexthop = NULL;
unsigned long ifindex;
struct prefix p;
@@ -2371,6 +2371,21 @@ zebra_show_client_brief (struct vty *vty, struct zserv *client)
}
+struct zserv *
+zebra_find_client (u_char proto)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ {
+ if (client->proto == proto)
+ return client;
+ }
+
+ return NULL;
+}
+
/* Display default rtm_table for all clients. */
DEFUN (show_table,
diff --git a/zebra/zserv.h b/zebra/zserv.h
index a0434d299b..d17a28eb6a 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -176,4 +176,6 @@ extern void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id)
extern void zserv_nexthop_num_warn(const char *, const struct prefix *, const unsigned int);
extern int zebra_server_send_message(struct zserv *client);
+extern struct zserv *zebra_find_client (u_char proto);
+
#endif /* _ZEBRA_ZEBRA_H */