diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/command.c | 74 | ||||
| -rw-r--r-- | lib/command.h | 6 | ||||
| -rw-r--r-- | lib/frr_zmq.c | 191 | ||||
| -rw-r--r-- | lib/frr_zmq.h | 88 | ||||
| -rw-r--r-- | lib/grammar_sandbox_main.c | 1 | ||||
| -rw-r--r-- | lib/libfrr.c | 50 | ||||
| -rw-r--r-- | lib/libfrr.h | 1 | ||||
| -rw-r--r-- | lib/nexthop.c | 3 | ||||
| -rw-r--r-- | lib/nexthop.h | 16 | ||||
| -rw-r--r-- | lib/ns.c | 2 | ||||
| -rw-r--r-- | lib/prefix.h | 19 | ||||
| -rw-r--r-- | lib/routemap.c | 129 | ||||
| -rw-r--r-- | lib/routemap.h | 4 | ||||
| -rw-r--r-- | lib/sockunion.h | 1 | ||||
| -rw-r--r-- | lib/subdir.am | 15 | ||||
| -rw-r--r-- | lib/vty.c | 33 | ||||
| -rw-r--r-- | lib/vty.h | 15 | ||||
| -rw-r--r-- | lib/zclient.c | 34 | ||||
| -rw-r--r-- | lib/zclient.h | 15 | ||||
| -rw-r--r-- | lib/zebra.h | 4 |
20 files changed, 574 insertions, 127 deletions
diff --git a/lib/command.c b/lib/command.c index c86025a3bd..a303781370 100644 --- a/lib/command.c +++ b/lib/command.c @@ -125,6 +125,23 @@ vector cmdvec = NULL; /* Host information structure. */ struct host host; +/* + * Returns host.name if any, otherwise + * it returns the system hostname. + */ +const char *cmd_hostname_get(void) +{ + return host.name; +} + +/* + * Returns unix domainname + */ +const char *cmd_domainname_get(void) +{ + return host.domainname; +} + /* Standard command node structures. */ static struct cmd_node auth_node = { AUTH_NODE, "Password: ", @@ -475,8 +492,8 @@ static char *zencrypt(const char *passwd) /* This function write configuration of this host. */ static int config_write_host(struct vty *vty) { - if (host.name) - vty_out(vty, "hostname %s\n", host.name); + if (cmd_hostname_get()) + vty_out(vty, "hostname %s\n", cmd_hostname_get()); if (host.encrypt) { if (host.password_encrypt) @@ -1411,7 +1428,7 @@ DEFUN (show_version, "Displays zebra version\n") { vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION, - host.name ? host.name : ""); + cmd_hostname_get() ? cmd_hostname_get() : ""); vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO); vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS); @@ -1745,6 +1762,40 @@ DEFUN (show_startup_config, return CMD_SUCCESS; } +int cmd_domainname_set(const char *domainname) +{ + XFREE(MTYPE_HOST, host.domainname); + host.domainname = domainname ? XSTRDUP(MTYPE_HOST, domainname) : NULL; + return CMD_SUCCESS; +} + +/* Hostname configuration */ +DEFUN(config_domainname, + domainname_cmd, + "domainname WORD", + "Set system's domain name\n" + "This system's domain name\n") +{ + struct cmd_token *word = argv[1]; + + if (!isalpha((int)word->arg[0])) { + vty_out(vty, "Please specify string starting with alphabet\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return cmd_domainname_set(word->arg); +} + +DEFUN(config_no_domainname, + no_domainname_cmd, + "no domainname [DOMAINNAME]", + NO_STR + "Reset system's domain name\n" + "domain name of this router\n") +{ + return cmd_domainname_set(NULL); +} + int cmd_hostname_set(const char *hostname) { XFREE(MTYPE_HOST, host.name); @@ -2515,9 +2566,12 @@ void install_default(enum node_type node) * terminal = -1 -- watchfrr / no logging, but minimal config control */ void cmd_init(int terminal) { + struct utsname names; + if (array_size(node_names) != NODE_TYPE_MAX) assert(!"Update the CLI node description array!"); + uname(&names); qobj_init(); varhandlers = list_new(); @@ -2526,7 +2580,15 @@ void cmd_init(int terminal) cmdvec = vector_init(VECTOR_MIN_SIZE); /* Default host value settings. */ - host.name = NULL; + host.name = XSTRDUP(MTYPE_HOST, names.nodename); +#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME + if ((strcmp(names.domainname, "(none)") == 0)) + host.domainname = NULL; + else + host.domainname = XSTRDUP(MTYPE_HOST, names.domainname); +#else + host.domainname = NULL; +#endif host.password = NULL; host.enable = NULL; host.logfile = NULL; @@ -2579,6 +2641,8 @@ void cmd_init(int terminal) install_element(CONFIG_NODE, &hostname_cmd); install_element(CONFIG_NODE, &no_hostname_cmd); + install_element(CONFIG_NODE, &domainname_cmd); + install_element(CONFIG_NODE, &no_domainname_cmd); install_element(CONFIG_NODE, &frr_version_defaults_cmd); install_element(CONFIG_NODE, &debug_memstats_cmd); @@ -2644,6 +2708,8 @@ void cmd_terminate() if (host.name) XFREE(MTYPE_HOST, host.name); + if (host.domainname) + XFREE(MTYPE_HOST, host.domainname); if (host.password) XFREE(MTYPE_HOST, host.password); if (host.password_encrypt) diff --git a/lib/command.h b/lib/command.h index 8f12e2aabd..1c6938523c 100644 --- a/lib/command.h +++ b/lib/command.h @@ -41,6 +41,9 @@ struct host { /* Host name of this router. */ char *name; + /* Domainname of this router */ + char *domainname; + /* Password for vty interface. */ char *password; char *password_encrypt; @@ -398,7 +401,10 @@ extern void cmd_terminate(void); extern void cmd_exit(struct vty *vty); extern int cmd_list_cmds(struct vty *vty, int do_permute); +extern int cmd_domainname_set(const char *domainname); extern int cmd_hostname_set(const char *hostname); +extern const char *cmd_hostname_get(void); +extern const char *cmd_domainname_get(void); /* NOT safe for general use; call this only if DEV_BUILD! */ extern void grammar_sandbox_init(void); diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c new file mode 100644 index 0000000000..861f7a5f0c --- /dev/null +++ b/lib/frr_zmq.c @@ -0,0 +1,191 @@ +/* + * libzebra ZeroMQ bindings + * Copyright (C) 2015 David Lamparter + * + * 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 <zmq.h> + +#include "thread.h" +#include "memory.h" +#include "frr_zmq.h" +#include "log.h" + +DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback") + +/* libzmq's context */ +void *frrzmq_context = NULL; +static unsigned frrzmq_initcount = 0; + +void frrzmq_init(void) +{ + if (frrzmq_initcount++ == 0) { + frrzmq_context = zmq_ctx_new(); + zmq_ctx_set(frrzmq_context, ZMQ_IPV6, 1); + } +} + +void frrzmq_finish(void) +{ + if (--frrzmq_initcount == 0) { + zmq_ctx_term(frrzmq_context); + frrzmq_context = NULL; + } +} + +/* read callback integration */ +struct frrzmq_cb { + struct thread *thread; + void *zmqsock; + void *arg; + int fd; + + bool cancelled; + + void (*cb_msg)(void *arg, void *zmqsock); + void (*cb_part)(void *arg, void *zmqsock, + zmq_msg_t *msg, unsigned partnum); +}; + + +static int frrzmq_read_msg(struct thread *t) +{ + struct frrzmq_cb *cb = THREAD_ARG(t); + zmq_msg_t msg; + unsigned partno; + int ret, more; + size_t moresz; + + while (1) { + zmq_pollitem_t polli = { + .socket = cb->zmqsock, + .events = ZMQ_POLLIN + }; + ret = zmq_poll(&polli, 1, 0); + + if (ret < 0) + goto out_err; + if (!(polli.revents & ZMQ_POLLIN)) + break; + + if (cb->cb_msg) { + cb->cb_msg(cb->arg, cb->zmqsock); + + if (cb->cancelled) { + XFREE(MTYPE_ZEROMQ_CB, cb); + return 0; + } + continue; + } + + partno = 0; + if (zmq_msg_init(&msg)) + goto out_err; + do { + ret = zmq_msg_recv(&msg, cb->zmqsock, ZMQ_NOBLOCK); + if (ret < 0) { + if (errno == EAGAIN) + break; + + zmq_msg_close(&msg); + goto out_err; + } + + cb->cb_part(cb->arg, cb->zmqsock, &msg, partno); + if (cb->cancelled) { + zmq_msg_close(&msg); + XFREE(MTYPE_ZEROMQ_CB, cb); + return 0; + } + + /* cb_part may have read additional parts of the + * message; don't use zmq_msg_more here */ + moresz = sizeof(more); + more = 0; + ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE, + &more, &moresz); + if (ret < 0) { + zmq_msg_close(&msg); + goto out_err; + } + + partno++; + } while (more); + zmq_msg_close(&msg); + } + + funcname_thread_add_read_write(THREAD_READ, t->master, frrzmq_read_msg, + cb, cb->fd, &cb->thread, t->funcname, t->schedfrom, + t->schedfrom_line); + return 0; + +out_err: + zlog_err("ZeroMQ error: %s(%d)", strerror (errno), errno); + return 0; +} + +struct frrzmq_cb *funcname_frrzmq_thread_add_read( + struct thread_master *master, + void (*msgfunc)(void *arg, void *zmqsock), + void (*partfunc)(void *arg, void *zmqsock, + zmq_msg_t *msg, unsigned partnum), + void *arg, void *zmqsock, debugargdef) +{ + int fd, events; + size_t len; + struct frrzmq_cb *cb; + + if (!(msgfunc || partfunc) || (msgfunc && partfunc)) + return NULL; + len = sizeof(fd); + if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len)) + return NULL; + len = sizeof(events); + if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len)) + return NULL; + + cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb)); + if (!cb) + return NULL; + + cb->arg = arg; + cb->zmqsock = zmqsock; + cb->cb_msg = msgfunc; + cb->cb_part = partfunc; + cb->fd = fd; + + if (events & ZMQ_POLLIN) + funcname_thread_add_event(master, + frrzmq_read_msg, cb, fd, &cb->thread, + funcname, schedfrom, fromln); + else + funcname_thread_add_read_write(THREAD_READ, master, + frrzmq_read_msg, cb, fd, &cb->thread, + funcname, schedfrom, fromln); + return cb; +} + +void frrzmq_thread_cancel(struct frrzmq_cb *cb) +{ + if (!cb->thread) { + /* canceling from within callback */ + cb->cancelled = 1; + return; + } + thread_cancel(cb->thread); + XFREE(MTYPE_ZEROMQ_CB, cb); +} diff --git a/lib/frr_zmq.h b/lib/frr_zmq.h new file mode 100644 index 0000000000..69c6f8580d --- /dev/null +++ b/lib/frr_zmq.h @@ -0,0 +1,88 @@ +/* + * libzebra ZeroMQ bindings + * Copyright (C) 2015 David Lamparter + * + * 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 _FRRZMQ_H +#define _FRRZMQ_H + +#include "thread.h" +#include <zmq.h> + +/* linking/packaging note: this is a separate library that needs to be + * linked into any daemon/library/module that wishes to use its + * functionality. The purpose of this is to encapsulate the libzmq + * dependency and not make libfrr/FRR itself depend on libzmq. + * + * libfrrzmq should be put in LDFLAGS/LIBADD *before* either libfrr or + * libzmq, and both of these should always be listed, e.g. + * foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS) + */ + +/* libzmq's context + * + * this is mostly here as a convenience, it has IPv6 enabled but nothing + * else is tied to it; you can use a separate context without problems + */ +extern void *frrzmq_context; + +extern void frrzmq_init (void); +extern void frrzmq_finish (void); + +#define debugargdef const char *funcname, const char *schedfrom, int fromln + +/* core event registration, one of these 2 macros should be used */ +#define frrzmq_thread_add_read_msg(m,f,a,z) funcname_frrzmq_thread_add_read( \ + m,f,NULL,a,z,#f,__FILE__,__LINE__) +#define frrzmq_thread_add_read_part(m,f,a,z) funcname_frrzmq_thread_add_read( \ + m,NULL,f,a,z,#f,__FILE__,__LINE__) + +struct frrzmq_cb; + +/* Set up a POLLIN notification to be called from the libfrr main loop. + * This has the following properties: + * + * - since ZeroMQ works with edge triggered notifications, it will loop and + * dispatch as many events as ZeroMQ has pending at the time libfrr calls + * into this code + * - due to this looping (which means it non-single-issue), the callback is + * also persistent. Do _NOT_ re-register the event inside of your + * callback function. + * - either msgfunc or partfunc will be called (only one can be specified) + * - msgfunc is called once for each incoming message + * - if partfunc is specified, the message is read and partfunc is called + * for each ZeroMQ multi-part subpart. Note that you can't send replies + * before all parts have been read because that violates the ZeroMQ FSM. + * - you can safely cancel the callback from within itself + * - installing a callback will check for pending events (ZMQ_EVENTS) and + * may schedule the event to run as soon as libfrr is back in its main + * loop. + * + * TODO #1: add ZMQ_POLLERR / error callback + * TODO #2: add frrzmq_check_events() function to check for edge triggered + * things that may have happened after a zmq_send() call or so + */ +extern struct frrzmq_cb *funcname_frrzmq_thread_add_read( + struct thread_master *master, + void (*msgfunc)(void *arg, void *zmqsock), + void (*partfunc)(void *arg, void *zmqsock, + zmq_msg_t *msg, unsigned partnum), + void *arg, void *zmqsock, debugargdef); + +extern void frrzmq_thread_cancel(struct frrzmq_cb *cb); + +#endif /* _FRRZMQ_H */ diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index 89b0993d1d..264c7c48f0 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -50,6 +50,7 @@ int main(int argc, char **argv) /* Library inits. */ cmd_init(1); host.name = strdup("test"); + host.domainname = strdup("testdomainname"); vty_init(master); memory_init(); diff --git a/lib/libfrr.c b/lib/libfrr.c index 9944fdd1e1..3e2e008223 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -101,13 +101,15 @@ static const struct optspec os_always = { static const struct option lo_cfg_pid_dry[] = { {"pid_file", required_argument, NULL, 'i'}, {"config_file", required_argument, NULL, 'f'}, + {"pathspace", required_argument, NULL, 'N'}, {"dryrun", no_argument, NULL, 'C'}, {"terminal", no_argument, NULL, 't'}, {NULL}}; static const struct optspec os_cfg_pid_dry = { - "f:i:Ct", + "f:i:CtN:", " -f, --config_file Set configuration file name\n" " -i, --pid_file Set process identifier file name\n" + " -N, --pathspace Insert prefix into config & socket paths\n" " -C, --dryrun Check configuration for validity and exit\n" " -t, --terminal Open terminal session on stdio\n" " -d -t Daemonize after terminal session ends\n", @@ -351,6 +353,23 @@ static int frr_opt(int opt) return 1; di->config_file = optarg; break; + case 'N': + if (di->flags & FRR_NO_CFG_PID_DRY) + return 1; + if (di->pathspace) { + fprintf(stderr, + "-N/--pathspace option specified more than once!\n"); + errors++; + break; + } + if (strchr(optarg, '/') || strchr(optarg, '.')) { + fprintf(stderr, + "slashes or dots are not permitted in the --pathspace option.\n"); + errors++; + break; + } + di->pathspace = optarg; + break; case 'C': if (di->flags & FRR_NO_CFG_PID_DRY) return 1; @@ -500,14 +519,25 @@ struct thread_master *frr_init(void) struct option_chain *oc; struct frrmod_runtime *module; char moderr[256]; + char p_instance[16] = "", p_pathspace[256] = ""; const char *dir; dir = di->module_path ? di->module_path : frr_moduledir; srandom(time(NULL)); - if (di->instance) + if (di->instance) { snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]", di->logname, di->instance); + snprintf(p_instance, sizeof(p_instance), "-%d", di->instance); + } + if (di->pathspace) + snprintf(p_pathspace, sizeof(p_pathspace), "/%s", + di->pathspace); + + snprintf(config_default, sizeof(config_default), "%s%s/%s%s.conf", + frr_sysconfdir, p_pathspace, di->name, p_instance); + snprintf(pidfile_default, sizeof(pidfile_default), "%s%s/%s%s.pid", + frr_vtydir, p_pathspace, di->name, p_instance); zprivs_preinit(di->privs); @@ -695,14 +725,6 @@ void frr_config_fork(void) { hook_call(frr_late_init, master); - if (di->instance) { - snprintf(config_default, sizeof(config_default), - "%s/%s-%d.conf", frr_sysconfdir, di->name, - di->instance); - snprintf(pidfile_default, sizeof(pidfile_default), - "%s/%s-%d.pid", frr_vtydir, di->name, di->instance); - } - vty_read_config(di->config_file, config_default); /* Don't start execution if we are in dry-run mode */ @@ -723,7 +745,13 @@ void frr_vty_serv(void) * (not currently set anywhere) */ if (!di->vty_path) { const char *dir; - dir = di->vty_sock_path ? di->vty_sock_path : frr_vtydir; + char defvtydir[256]; + + snprintf(defvtydir, sizeof(defvtydir), "%s%s%s", frr_vtydir, + di->pathspace ? "/" : "", + di->pathspace ? di->pathspace : ""); + + dir = di->vty_sock_path ? di->vty_sock_path : defvtydir; if (di->instance) snprintf(vtypath_default, sizeof(vtypath_default), diff --git a/lib/libfrr.h b/lib/libfrr.h index f7d69eecb3..fe6c46670a 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -54,6 +54,7 @@ struct frr_daemon_info { const char *pid_file; const char *vty_path; const char *module_path; + const char *pathspace; const char *proghelp; void (*printhelp)(FILE *target); diff --git a/lib/nexthop.c b/lib/nexthop.c index 7180be33dd..2dba412f45 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -36,7 +36,8 @@ DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop") DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label") /* check if nexthops are same, non-recursive */ -int nexthop_same_no_recurse(struct nexthop *next1, struct nexthop *next2) +int nexthop_same_no_recurse(const struct nexthop *next1, + const struct nexthop *next2) { if (next1->type != next2->type) return 0; diff --git a/lib/nexthop.h b/lib/nexthop.h index e7804379f1..781eb93413 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -43,6 +43,13 @@ enum nexthop_types_t { NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */ }; +enum blackhole_type { + BLACKHOLE_UNSPEC = 0, + BLACKHOLE_NULL, + BLACKHOLE_REJECT, + BLACKHOLE_ADMINPROHIB, +}; + /* Nexthop label structure. */ struct nexthop_label { u_int8_t num_labels; @@ -69,7 +76,10 @@ struct nexthop { #define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */ /* Nexthop address */ - union g_addr gate; + union { + union g_addr gate; + enum blackhole_type bh_type; + }; union g_addr src; union g_addr rmap_src; /* Src is set via routemap */ @@ -128,8 +138,8 @@ void nexthop_add_labels(struct nexthop *, enum lsp_types_t, u_int8_t, void nexthop_del_labels(struct nexthop *); extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type); -extern int nexthop_same_no_recurse(struct nexthop *next1, - struct nexthop *next2); +extern int nexthop_same_no_recurse(const struct nexthop *next1, + const struct nexthop *next2); extern int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2); extern const char *nexthop2str(struct nexthop *nexthop, char *str, int size); @@ -312,7 +312,7 @@ DEFUN_NOSH (ns_netns, if (ns->name && strcmp(ns->name, pathname) != 0) { vty_out(vty, "NS %u is already configured with NETNS %s\n", ns->ns_id, ns->name); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } if (!ns->name) diff --git a/lib/prefix.h b/lib/prefix.h index a27f46ba0a..0732cf1290 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -315,7 +315,9 @@ extern void prefix_ipv4_free(struct prefix_ipv4 *); extern int str2prefix_ipv4(const char *, struct prefix_ipv4 *); extern void apply_mask_ipv4(struct prefix_ipv4 *); -#define PREFIX_COPY_IPV4(DST, SRC) \ +#define PREFIX_COPY(DST, SRC) \ + *((struct prefix *)(DST)) = *((const struct prefix *)(SRC)) +#define PREFIX_COPY_IPV4(DST, SRC) \ *((struct prefix_ipv4 *)(DST)) = *((const struct prefix_ipv4 *)(SRC)); extern int prefix_ipv4_any(const struct prefix_ipv4 *); @@ -377,15 +379,20 @@ static inline int ipv4_martian(struct in_addr *addr) return 0; } -static inline int is_default_prefix(struct prefix *p) +static inline int is_default_prefix(const struct prefix *p) { if (!p) return 0; - if (((p->family == AF_INET) && (p->u.prefix4.s_addr == INADDR_ANY)) - || ((p->family == AF_INET6) - && !memcmp(&p->u.prefix6, &in6addr_any, - sizeof(struct in6_addr)))) + if ((p->family == AF_INET) && + (p->u.prefix4.s_addr == INADDR_ANY) && + (p->prefixlen == 0)) + return 1; + + if ((p->family == AF_INET6) && + (p->prefixlen == 0) && + (!memcmp(&p->u.prefix6, &in6addr_any, + sizeof(struct in6_addr)))) return 1; return 0; diff --git a/lib/routemap.c b/lib/routemap.c index a70248633c..409c9c3780 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -416,23 +416,25 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, int ret; ret = route_map_add_match(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; + switch (ret) { + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_ADDED) { + route_map_upd8_dependency(type, arg, index->map->name); } + break; + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; } - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } return CMD_SUCCESS; } @@ -441,6 +443,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, route_map_event_t type) { int ret; + int retval = CMD_SUCCESS; char *dep_name = NULL; const char *tmpstr; char *rmap_name = NULL; @@ -459,34 +462,30 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, } ret = route_map_delete_match(index, command, dep_name); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - break; - } - if (dep_name) - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - if (rmap_name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - return CMD_WARNING_CONFIG_FAILED; + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + if (type != RMAP_EVENT_MATCH_DELETED && dep_name) + route_map_upd8_dependency(type, dep_name, rmap_name); + break; } - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - if (dep_name) XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); if (rmap_name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - return CMD_SUCCESS; + return retval; } int generic_set_add(struct vty *vty, struct route_map_index *index, @@ -495,19 +494,22 @@ int generic_set_add(struct vty *vty, struct route_map_index *index, int ret; ret = route_map_add_set(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -517,19 +519,22 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, int ret; ret = route_map_delete_set(index, command, arg); - if (ret) { - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - return CMD_WARNING_CONFIG_FAILED; - } + switch (ret) { + case RMAP_RULE_MISSING: + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + return CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + break; } + return CMD_SUCCESS; } @@ -1217,7 +1222,7 @@ int route_map_add_match(struct route_map_index *index, const char *match_name, RMAP_EVENT_CALL_ADDED); } - return 0; + return RMAP_COMPILE_SUCCESS; } /* Delete specified route match rule. */ @@ -1304,7 +1309,7 @@ int route_map_add_set(struct route_map_index *index, const char *set_name, route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED); } - return 0; + return RMAP_COMPILE_SUCCESS; } /* Delete route map set rule. */ @@ -2201,7 +2206,7 @@ DEFUN (no_set_ip_nexthop, "Next hop address\n" "IP address of next hop\n") { - int idx; + int idx = 0; VTY_DECLVAR_CONTEXT(route_map_index, index); const char *arg = NULL; diff --git a/lib/routemap.h b/lib/routemap.h index 43af8dbcfe..b166de1e09 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -99,8 +99,10 @@ struct route_map_rule_cmd { /* Route map apply error. */ enum { + RMAP_COMPILE_SUCCESS, + /* Route map rule is missing. */ - RMAP_RULE_MISSING = 1, + RMAP_RULE_MISSING, /* Route map rule can't compile */ RMAP_COMPILE_ERROR diff --git a/lib/sockunion.h b/lib/sockunion.h index 7b1c7ba9c5..67a7a46272 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -34,6 +34,7 @@ union sockunion { struct sockaddr_in6 sin6; #ifdef __OpenBSD__ struct sockaddr_mpls smpls; + struct sockaddr_rtlabel rtlabel; #endif }; diff --git a/lib/subdir.am b/lib/subdir.am index eaa6cd6ec8..c8eddc8e25 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -186,6 +186,21 @@ lib_libfrrsnmp_la_SOURCES = \ # end # +# ZeroMQ support +# +if ZEROMQ +lib_LTLIBRARIES += lib/libfrrzmq.la +pkginclude_HEADERS += lib/frr_zmq.h +endif + +lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS) +lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0 +lib_libfrrzmq_la_LIBADD = lib/libfrr.la $(ZEROMQ_LIBS) +lib_libfrrzmq_la_SOURCES = \ + lib/frr_zmq.c \ + #end + +# # CLI utilities # noinst_PROGRAMS += \ @@ -91,6 +91,24 @@ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; static int do_log_commands = 0; +void vty_frame(struct vty *vty, const char *format, ...) +{ + va_list args; + + va_start(args, format); + vsnprintf(vty->frame + vty->frame_pos, + sizeof(vty->frame) - vty->frame_pos, format, args); + vty->frame_pos = strlen(vty->frame); + va_end(args); +} + +void vty_endframe(struct vty *vty, const char *endtext) +{ + if (vty->frame_pos == 0 && endtext) + vty_out(vty, "%s", endtext); + vty->frame_pos = 0; +} + /* VTY standard output function. */ int vty_out(struct vty *vty, const char *format, ...) { @@ -100,6 +118,11 @@ int vty_out(struct vty *vty, const char *format, ...) char buf[1024]; char *p = NULL; + if (vty->frame_pos) { + vty->frame_pos = 0; + vty_out(vty, "%s", vty->frame); + } + if (vty_shell(vty)) { va_start(args, format); vprintf(format, args); @@ -250,16 +273,8 @@ void vty_hello(struct vty *vty) /* Put out prompt and wait input from user. */ static void vty_prompt(struct vty *vty) { - struct utsname names; - const char *hostname; - if (vty->type == VTY_TERM) { - hostname = host.name; - if (!hostname) { - uname(&names); - hostname = names.nodename; - } - vty_out(vty, cmd_prompt(vty->node), hostname); + vty_out(vty, cmd_prompt(vty->node), cmd_hostname_get()); } } @@ -125,6 +125,12 @@ struct vty { /* What address is this vty comming from. */ char address[SU_ADDRSTRLEN]; + + /* "frame" output. This is buffered and will be printed if some + * actual output follows, or will be discarded if the frame ends + * without any output. */ + size_t frame_pos; + char frame[1024]; }; static inline void vty_push_context(struct vty *vty, int node, uint64_t id) @@ -247,7 +253,16 @@ extern void vty_terminate(void); extern void vty_reset(void); extern struct vty *vty_new(void); extern struct vty *vty_stdio(void (*atclose)(int isexit)); + +/* - vty_frame() output goes to a buffer (for context-begin markers) + * - vty_out() will first print this buffer, and clear it + * - vty_endframe() clears the buffer without printing it, and prints an + * extra string if the buffer was empty before (for context-end markers) + */ extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +extern void vty_endframe(struct vty *, const char *); + extern void vty_read_config(const char *, char *); extern void vty_time_print(struct vty *, int); extern void vty_serv_sock(const char *, unsigned short, const char *); diff --git a/lib/zclient.c b/lib/zclient.c index 72fa2679b3..910e05cb47 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -621,10 +621,9 @@ static int zclient_connect(struct thread *t) * | IPv4 Nexthop address or Interface Index number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or - * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_ - * nexthop information is provided, and the message describes a prefix - * to blackhole or reject route. + * Alternatively, if the route is a blackhole route, then Nexthop count + * is set to 1 and a nexthop of type NEXTHOP_TYPE_BLACKHOLE is the sole + * nexthop. * * The original struct zapi_ipv4, zapi_ipv4_route() and zread_ipv4_*() * infrastructure was built around the traditional (32-bit "gate OR @@ -692,14 +691,7 @@ int zapi_ipv4_route(u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { - /* traditional 32-bit data units */ - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) { - stream_putc(s, 1); - stream_putc(s, NEXTHOP_TYPE_BLACKHOLE); - /* XXX assert(api->nexthop_num == 0); */ - /* XXX assert(api->ifindex_num == 0); */ - } else - stream_putc(s, api->nexthop_num + api->ifindex_num); + stream_putc(s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc(s, NEXTHOP_TYPE_IPV4); @@ -769,13 +761,7 @@ int zapi_ipv4_route_ipv6_nexthop(u_char cmd, struct zclient *zclient, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) { - stream_putc(s, 1); - stream_putc(s, NEXTHOP_TYPE_BLACKHOLE); - /* XXX assert(api->nexthop_num == 0); */ - /* XXX assert(api->ifindex_num == 0); */ - } else - stream_putc(s, api->nexthop_num + api->ifindex_num); + stream_putc(s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc(s, NEXTHOP_TYPE_IPV6); @@ -855,13 +841,7 @@ int zapi_ipv6_route(u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) { - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_BLACKHOLE)) { - stream_putc(s, 1); - stream_putc(s, NEXTHOP_TYPE_BLACKHOLE); - /* XXX assert(api->nexthop_num == 0); */ - /* XXX assert(api->ifindex_num == 0); */ - } else - stream_putc(s, api->nexthop_num + api->ifindex_num); + stream_putc(s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc(s, NEXTHOP_TYPE_IPV6); @@ -948,6 +928,7 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api) stream_putc(s, api_nh->type); switch (api_nh->type) { case NEXTHOP_TYPE_BLACKHOLE: + stream_putc(s, api_nh->bh_type); break; case NEXTHOP_TYPE_IPV4: stream_put_in_addr(s, &api_nh->gate.ipv4); @@ -1060,6 +1041,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) api_nh->type = stream_getc(s); switch (api_nh->type) { case NEXTHOP_TYPE_BLACKHOLE: + api_nh->bh_type = stream_getc(s); break; case NEXTHOP_TYPE_IPV4: api_nh->gate.ipv4.s_addr = stream_get_ipv4(s); diff --git a/lib/zclient.h b/lib/zclient.h index 7c4780201e..288951eb1a 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -222,7 +222,10 @@ struct zserv_header { struct zapi_nexthop { enum nexthop_types_t type; ifindex_t ifindex; - union g_addr gate; + union { + union g_addr gate; + enum blackhole_type bh_type; + }; /* MPLS labels for BGP-LU or Segment Routing */ uint8_t label_num; @@ -429,4 +432,14 @@ extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *); extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *); extern int zapi_route_decode(struct stream *, struct zapi_route *); +static inline void zapi_route_set_blackhole(struct zapi_route *api, + enum blackhole_type bh_type) +{ + api->nexthop_num = 1; + api->nexthops[0].type = NEXTHOP_TYPE_BLACKHOLE; + api->nexthops[0].bh_type = bh_type; + SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP); +}; + + #endif /* _ZEBRA_ZCLIENT_H */ diff --git a/lib/zebra.h b/lib/zebra.h index 6d64bbd670..fa5fa89f77 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -404,13 +404,13 @@ extern const char *zserv_command_string(unsigned int command); /* Zebra message flags */ #define ZEBRA_FLAG_INTERNAL 0x01 #define ZEBRA_FLAG_SELFROUTE 0x02 -#define ZEBRA_FLAG_BLACKHOLE 0x04 #define ZEBRA_FLAG_IBGP 0x08 #define ZEBRA_FLAG_SELECTED 0x10 #define ZEBRA_FLAG_STATIC 0x40 -#define ZEBRA_FLAG_REJECT 0x80 #define ZEBRA_FLAG_SCOPE_LINK 0x100 #define ZEBRA_FLAG_FIB_OVERRIDE 0x200 +/* ZEBRA_FLAG_BLACKHOLE was 0x04 */ +/* ZEBRA_FLAG_REJECT was 0x80 */ /* Zebra FEC flags. */ #define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1 |
