summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/command.c74
-rw-r--r--lib/command.h6
-rw-r--r--lib/frr_zmq.c191
-rw-r--r--lib/frr_zmq.h88
-rw-r--r--lib/grammar_sandbox_main.c1
-rw-r--r--lib/libfrr.c50
-rw-r--r--lib/libfrr.h1
-rw-r--r--lib/nexthop.c3
-rw-r--r--lib/nexthop.h16
-rw-r--r--lib/ns.c2
-rw-r--r--lib/prefix.h19
-rw-r--r--lib/routemap.c129
-rw-r--r--lib/routemap.h4
-rw-r--r--lib/sockunion.h1
-rw-r--r--lib/subdir.am15
-rw-r--r--lib/vty.c33
-rw-r--r--lib/vty.h15
-rw-r--r--lib/zclient.c34
-rw-r--r--lib/zclient.h15
-rw-r--r--lib/zebra.h4
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);
diff --git a/lib/ns.c b/lib/ns.c
index 5e03a43e2a..ba920e31b9 100644
--- a/lib/ns.c
+++ b/lib/ns.c
@@ -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 += \
diff --git a/lib/vty.c b/lib/vty.c
index 59a8825357..12c3c12394 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -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());
}
}
diff --git a/lib/vty.h b/lib/vty.h
index 9acd62af3c..3b75afb02c 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -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