diff options
| -rw-r--r-- | lib/Makefile.am | 4 | ||||
| -rw-r--r-- | lib/imsg.c | 3 | ||||
| -rw-r--r-- | lib/json.c | 15 | ||||
| -rw-r--r-- | lib/json.h | 4 | ||||
| -rw-r--r-- | lib/prefix.h | 17 | ||||
| -rw-r--r-- | lib/thread.c | 64 | ||||
| -rw-r--r-- | lib/thread.h | 1 | ||||
| -rw-r--r-- | lib/wheel.c | 164 | ||||
| -rw-r--r-- | lib/wheel.h | 70 | ||||
| -rw-r--r-- | lib/zebra.h | 3 | ||||
| -rw-r--r-- | zebra/if_netlink.c | 2 | ||||
| -rw-r--r-- | zebra/kernel_netlink.c | 62 | ||||
| -rw-r--r-- | zebra/kernel_netlink.h | 8 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 173 | ||||
| -rw-r--r-- | zebra/zebra_fpm.c | 6 | ||||
| -rw-r--r-- | zebra/zebra_fpm_netlink.c | 16 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_static.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_static.h | 15 | ||||
| -rw-r--r-- | zebra/zebra_vty.c | 13 | ||||
| -rw-r--r-- | zebra/zserv.c | 17 | ||||
| -rw-r--r-- | zebra/zserv.h | 2 |
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 */ |
