summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorpaulzlabn <paulz@labn.net>2018-03-14 13:31:58 -0700
committerGitHub <noreply@github.com>2018-03-14 13:31:58 -0700
commit3f1224cd1a9408bdad6aca8c0c205211cb548d5c (patch)
tree87e6a52a3e7ad7b09caa3207f081fd92bc8fd018 /lib
parentfd9b55a2b77c187730600d429b3f290ab58fa035 (diff)
parent6ca96cc6ada990d052fcfc48cffeef454ae64a10 (diff)
Merge branch 'master' into working/master/bgp-vpn-vrf-leaking
Diffstat (limited to 'lib')
-rw-r--r--lib/.gitignore1
-rw-r--r--lib/debug.h92
-rw-r--r--lib/frr_pthread.c44
-rw-r--r--lib/frr_pthread.h36
-rw-r--r--lib/ipaddr.h17
-rw-r--r--lib/log.c43
-rw-r--r--lib/nexthop.c51
-rw-r--r--lib/nexthop.h2
-rw-r--r--lib/nexthop_group.c313
-rw-r--r--lib/nexthop_group.h42
-rw-r--r--lib/strlcat.c14
-rw-r--r--lib/strlcpy.c29
-rw-r--r--lib/thread.c12
-rw-r--r--lib/thread.h1
-rw-r--r--lib/vrf.c20
-rw-r--r--lib/vrf.h3
-rw-r--r--lib/zclient.c12
-rw-r--r--lib/zclient.h65
-rw-r--r--lib/zebra.h6
19 files changed, 691 insertions, 112 deletions
diff --git a/lib/.gitignore b/lib/.gitignore
index 94f401ebe6..072146dbd5 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -24,4 +24,3 @@ refix
grammar_sandbox
clippy
defun_lex.c
-plist_clippy.c
diff --git a/lib/debug.h b/lib/debug.h
index 3e6772aacf..d0fa27d3fe 100644
--- a/lib/debug.h
+++ b/lib/debug.h
@@ -104,76 +104,77 @@ struct debug_callbacks {
*
* MT-Safe
*/
-#define DEBUG_MODE_CHECK(name, type) \
- CHECK_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_MODE_ALL)
+#define DEBUG_MODE_CHECK(name, mode) \
+ CHECK_FLAG_ATOMIC(&(name)->flags, (mode)&DEBUG_MODE_ALL)
/*
* Check if an option bit is set for a debug.
*
* MT-Safe
*/
-#define DEBUG_OPT_CHECK(name, type) \
- CHECK_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_OPT_ALL)
+#define DEBUG_OPT_CHECK(name, opt) \
+ CHECK_FLAG_ATOMIC(&(name)->flags, (opt)&DEBUG_OPT_ALL)
/*
* Check if bits are set for a debug.
*
* MT-Safe
*/
-#define DEBUG_FLAGS_CHECK(name, type) CHECK_FLAG_ATOMIC(&(name)->flags, (type))
-
-/*
- * Check if any mode is on for a debug.
- *
- * MT-Safe
- */
-#define DEBUG(name) DEBUG_MODE_CHECK((name), DEBUG_MODE_ALL)
+#define DEBUG_FLAGS_CHECK(name, fl) CHECK_FLAG_ATOMIC(&(name)->flags, (fl))
/*
* Set modes on a debug.
*
* MT-Safe
*/
-#define DEBUG_MODE_SET(name, type) \
- SET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_MODE_ALL)
+#define DEBUG_MODE_SET(name, mode, onoff) \
+ do { \
+ if (onoff) \
+ SET_FLAG_ATOMIC(&(name)->flags, \
+ (mode)&DEBUG_MODE_ALL); \
+ else \
+ UNSET_FLAG_ATOMIC(&(name)->flags, \
+ (mode)&DEBUG_MODE_ALL); \
+ } while (0)
-/*
- * Unset modes on a debug.
- *
- * MT-Safe
- */
-#define DEBUG_MODE_UNSET(name, type) \
- UNSET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_MODE_ALL)
+/* Convenience macros for specific set operations. */
+#define DEBUG_MODE_ON(name, mode) DEBUG_MODE_SET(name, mode, true)
+#define DEBUG_MODE_OFF(name, mode) DEBUG_MODE_SET(name, mode, false)
/*
* Set options on a debug.
*
* MT-Safe
*/
-#define DEBUG_OPT_SET(name, type) \
- SET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_OPT_ALL)
+#define DEBUG_OPT_SET(name, opt, onoff) \
+ do { \
+ if (onoff) \
+ SET_FLAG_ATOMIC(&(name)->flags, (opt)&DEBUG_OPT_ALL); \
+ else \
+ UNSET_FLAG_ATOMIC(&(name)->flags, \
+ (opt)&DEBUG_OPT_ALL); \
+ } while (0)
-/*
- * Unset options on a debug.
- *
- * MT-Safe
- */
-#define DEBUG_OPT_UNSET(name, type) \
- UNSET_FLAG_ATOMIC(&(name)->flags, (type)&DEBUG_OPT_ALL)
+/* Convenience macros for specific set operations. */
+#define DEBUG_OPT_ON(name, opt) DEBUG_OPT_SET(name, opt, true)
+#define DEBUG_OPT_OFF(name, opt) DEBUG_OPT_SET(name, opt, true)
/*
* Set bits on a debug.
*
* MT-Safe
*/
-#define DEBUG_FLAGS_SET(name, type) SET_FLAG_ATOMIC(&(name)->flags, (type))
+#define DEBUG_FLAGS_SET(name, fl, onoff) \
+ do { \
+ if (onoff) \
+ SET_FLAG_ATOMIC(&(name)->flags, (fl)); \
+ else \
+ UNSET_FLAG_ATOMIC(&(name)->flags, (fl)); \
+ } while (0)
-/*
- * Unset bits on a debug.
- *
- * MT-Safe
- */
-#define DEBUG_FLAGS_UNSET(name, type) UNSET_FLAG_ATOMIC(&(name)->flags, (type))
+/* Convenience macros for specific set operations. */
+#define DEBUG_FLAGS_ON(name, fl) DEBUG_FLAGS_SET(&(name)->flags, (type), true)
+#define DEBUG_FLAGS_OFF(name, fl) DEBUG_FLAGS_SET(&(name)->flags, (type), false)
/*
* Unset all modes and options on a debug.
@@ -201,6 +202,23 @@ struct debug_callbacks {
#define DEBUG_NODE2MODE(vtynode) \
(((vtynode) == CONFIG_NODE) ? DEBUG_MODE_ALL : DEBUG_MODE_TERM)
+/*
+ * Debug at the given level to the default logging destination.
+ *
+ * MT-Safe
+ */
+#define DEBUG(level, name, fmt, ...) \
+ do { \
+ if (DEBUG_MODE_CHECK(name, DEBUG_MODE_ALL)) \
+ zlog_##level(fmt, ##__VA_ARGS__); \
+ } while (0)
+
+/* Convenience macros for the various levels. */
+#define DEBUGE(name, fmt, ...) DEBUG(err, name, fmt, ##__VA_ARGS__)
+#define DEBUGW(name, fmt, ...) DEBUG(warn, name, fmt, ##__VA_ARGS__)
+#define DEBUGI(name, fmt, ...) DEBUG(info, name, fmt, ##__VA_ARGS__)
+#define DEBUGN(name, fmt, ...) DEBUG(notice, name, fmt, ##__VA_ARGS__)
+#define DEBUGD(name, fmt, ...) DEBUG(debug, name, fmt, ##__VA_ARGS__)
/*
* Optional initializer for debugging. Highly recommended.
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index 72b47ae5c3..36a89168c2 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -1,6 +1,6 @@
/*
* Utilities and interfaces for managing POSIX threads within FRR.
- * Copyright (C) 2017 Cumulus Networks
+ * Copyright (C) 2017 Cumulus Networks, Inc.
*
* 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
@@ -29,7 +29,7 @@ DEFINE_MTYPE(LIB, FRR_PTHREAD, "FRR POSIX Thread");
DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives");
/* id for next created pthread */
-static unsigned int next_id = 0;
+static _Atomic uint32_t next_id = 0;
/* default frr_pthread start/stop routine prototypes */
static void *fpt_run(void *arg);
@@ -40,7 +40,6 @@ struct frr_pthread_attr frr_pthread_attr_default = {
.id = 0,
.start = fpt_run,
.stop = fpt_halt,
- .name = "Anonymous",
};
/* hash table to keep track of all frr_pthreads */
@@ -85,9 +84,10 @@ void frr_pthread_finish()
pthread_mutex_unlock(&frr_pthread_hash_mtx);
}
-struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr)
+struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
+ const char *name)
{
- static struct frr_pthread holder = {0};
+ static struct frr_pthread holder = {};
struct frr_pthread *fpt = NULL;
attr = attr ? attr : &frr_pthread_attr_default;
@@ -99,10 +99,14 @@ struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr)
if (!hash_lookup(frr_pthread_hash, &holder)) {
fpt = XCALLOC(MTYPE_FRR_PTHREAD,
sizeof(struct frr_pthread));
+ /* initialize mutex */
+ pthread_mutex_init(&fpt->mtx, NULL);
/* create new thread master */
- fpt->master = thread_master_create(attr->name);
+ fpt->master = thread_master_create(name);
/* set attributes */
fpt->attr = *attr;
+ name = (name ? name : "Anonymous thread");
+ fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
if (attr == &frr_pthread_attr_default)
fpt->attr.id = frr_pthread_get_id();
/* initialize startup synchronization primitives */
@@ -126,16 +130,31 @@ void frr_pthread_destroy(struct frr_pthread *fpt)
{
thread_master_free(fpt->master);
+ pthread_mutex_destroy(&fpt->mtx);
pthread_mutex_destroy(fpt->running_cond_mtx);
pthread_cond_destroy(fpt->running_cond);
+ if (fpt->name)
+ XFREE(MTYPE_FRR_PTHREAD, fpt->name);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
XFREE(MTYPE_FRR_PTHREAD, fpt);
}
-struct frr_pthread *frr_pthread_get(unsigned int id)
+void frr_pthread_set_name(struct frr_pthread *fpt, const char *name)
{
- static struct frr_pthread holder = {0};
+ pthread_mutex_lock(&fpt->mtx);
+ {
+ if (fpt->name)
+ XFREE(MTYPE_FRR_PTHREAD, fpt->name);
+ fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
+ }
+ pthread_mutex_unlock(&fpt->mtx);
+ thread_master_set_name(fpt->master, name);
+}
+
+struct frr_pthread *frr_pthread_get(uint32_t id)
+{
+ static struct frr_pthread holder = {};
struct frr_pthread *fpt;
pthread_mutex_lock(&frr_pthread_hash_mtx);
@@ -210,11 +229,13 @@ void frr_pthread_stop_all()
pthread_mutex_unlock(&frr_pthread_hash_mtx);
}
-unsigned int frr_pthread_get_id()
+uint32_t frr_pthread_get_id(void)
{
+ _Atomic uint32_t nxid;
+ nxid = atomic_fetch_add_explicit(&next_id, 1, memory_order_seq_cst);
/* just a sanity check, this should never happen */
- assert(next_id <= INT_MAX - 1);
- return next_id++;
+ assert(nxid <= (UINT32_MAX - 1));
+ return nxid;
}
void frr_pthread_yield(void)
@@ -238,6 +259,7 @@ static int fpt_dummy(struct thread *thread)
static int fpt_finish(struct thread *thread)
{
struct frr_pthread *fpt = THREAD_ARG(thread);
+
atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
return 0;
}
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
index 2cc50196a8..91002dd8ef 100644
--- a/lib/frr_pthread.h
+++ b/lib/frr_pthread.h
@@ -1,6 +1,6 @@
/*
* Utilities and interfaces for managing POSIX threads within FRR.
- * Copyright (C) 2017 Cumulus Networks
+ * Copyright (C) 2017 Cumulus Networks, Inc.
*
* 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
@@ -32,14 +32,19 @@ struct frr_pthread;
struct frr_pthread_attr;
struct frr_pthread_attr {
- int id;
+ _Atomic uint32_t id;
void *(*start)(void *);
int (*stop)(struct frr_pthread *, void **);
- const char *name;
};
struct frr_pthread {
+ /*
+ * Mutex protecting this structure. Must be taken for reading some
+ * fields, denoted by a 'Requires: mtx'.
+ */
+ pthread_mutex_t mtx;
+
/* pthread id */
pthread_t thread;
@@ -73,8 +78,17 @@ struct frr_pthread {
* Fake thread-specific storage. No constraints on usage. Helpful when
* creating reentrant pthread implementations. Can be used to pass
* argument to pthread entry function.
+ *
+ * Requires: mtx
*/
void *data;
+
+ /*
+ * Human-readable thread name.
+ *
+ * Requires: mtx
+ */
+ char *name;
};
extern struct frr_pthread_attr frr_pthread_attr_default;
@@ -107,9 +121,19 @@ void frr_pthread_finish(void);
* frr_pthread will cause them to run on that pthread.
*
* @param attr - the thread attributes
+ * @param name - Human-readable name
* @return the created frr_pthread upon success, or NULL upon failure
*/
-struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr);
+struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
+ const char *name);
+
+/*
+ * Changes the name of the frr_pthread.
+ *
+ * @param fpt - the frr_pthread to operate on
+ * @param name - Human-readable name
+ */
+void frr_pthread_set_name(struct frr_pthread *fpt, const char *name);
/*
* Destroys an frr_pthread.
@@ -125,7 +149,7 @@ void frr_pthread_destroy(struct frr_pthread *fpt);
*
* @return frr_thread associated with the provided id, or NULL on error
*/
-struct frr_pthread *frr_pthread_get(unsigned int id);
+struct frr_pthread *frr_pthread_get(uint32_t id);
/*
* Creates a new pthread and binds it to a frr_pthread.
@@ -198,6 +222,6 @@ void frr_pthread_yield(void);
*
* @return unique identifier
*/
-unsigned int frr_pthread_get_id(void);
+uint32_t frr_pthread_get_id(void);
#endif /* _FRR_PTHREAD_H */
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index 98c28008dc..44bde45add 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -85,4 +85,21 @@ static inline char *ipaddr2str(struct ipaddr *ip, char *buf, int size)
}
return buf;
}
+
+/*
+ * Convert IPv4 address to IPv4-mapped IPv6 address which is of the
+ * form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then
+ * be used to represent the IPv4 address, wherever only an IPv6 address
+ * is required.
+ */
+static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
+ struct in_addr in)
+{
+ u_int32_t addr_type = htonl(0xFFFF);
+
+ memset(in6, 0, sizeof(struct in6_addr));
+ memcpy((char *)in6 + 8, &addr_type, sizeof(addr_type));
+ memcpy((char *)in6 + 12, &in, sizeof(struct in_addr));
+}
+
#endif /* __IPADDR_H__ */
diff --git a/lib/log.c b/lib/log.c
index 49335e119b..a8e7462baa 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1096,41 +1096,52 @@ void zlog_hexdump(const void *mem, unsigned int len)
unsigned long i = 0;
unsigned int j = 0;
unsigned int columns = 8;
- char buf[(len * 4) + ((len / 4) * 20) + 30];
+ /*
+ * 19 bytes for 0xADDRESS:
+ * 24 bytes for data; 2 chars plus a space per data byte
+ * 1 byte for space
+ * 8 bytes for ASCII representation
+ * 1 byte for a newline
+ * =====================
+ * 53 bytes per 8 bytes of data
+ * 1 byte for null term
+ */
+ size_t bs = ((len / 8) + 1) * 53 + 1;
+ char buf[bs];
char *s = buf;
+ memset(buf, 0, sizeof(buf));
+
for (i = 0; i < len + ((len % columns) ? (columns - len % columns) : 0);
i++) {
/* print offset */
if (i % columns == 0)
- s += sprintf(s, "0x%016lx: ", (unsigned long)mem + i);
+ s += snprintf(s, bs - (s - buf),
+ "0x%016lx: ", (unsigned long)mem + i);
/* print hex data */
if (i < len)
- s += sprintf(s, "%02x ", 0xFF & ((const char *)mem)[i]);
+ s += snprintf(s, bs - (s - buf), "%02x ",
+ 0xFF & ((const char *)mem)[i]);
/* end of block, just aligning for ASCII dump */
else
- s += sprintf(s, " ");
+ s += snprintf(s, bs - (s - buf), " ");
/* print ASCII dump */
if (i % columns == (columns - 1)) {
for (j = i - (columns - 1); j <= i; j++) {
- if (j >= len) /* end of block, not really
- printing */
- s += sprintf(s, " ");
-
- else if (isprint((int)((const char *)mem)
- [j])) /* printable char
- */
- s += sprintf(
- s, "%c",
+ /* end of block not really printing */
+ if (j >= len)
+ s += snprintf(s, bs - (s - buf), " ");
+ else if (isprint((int)((const char *)mem)[j]))
+ s += snprintf(
+ s, bs - (s - buf), "%c",
0xFF & ((const char *)mem)[j]);
-
else /* other char */
- s += sprintf(s, ".");
+ s += snprintf(s, bs - (s - buf), ".");
}
- s += sprintf(s, "\n");
+ s += snprintf(s, bs - (s - buf), "\n");
}
}
zlog_debug("\n%s", buf);
diff --git a/lib/nexthop.c b/lib/nexthop.c
index cee34e85c7..fb7ccc169e 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -163,6 +163,57 @@ void nexthops_free(struct nexthop *nexthop)
}
}
+bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2)
+{
+ if (nh1 && !nh2)
+ return false;
+
+ if (!nh1 && nh2)
+ return false;
+
+ if (nh1 == nh2)
+ return true;
+
+ if (nh1->vrf_id != nh2->vrf_id)
+ return false;
+
+ if (nh1->type != nh2->type)
+ return false;
+
+ switch (nh1->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ if (nh1->ifindex != nh2->ifindex)
+ return false;
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ if (nh1->gate.ipv4.s_addr != nh2->gate.ipv4.s_addr)
+ return false;
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (nh1->gate.ipv4.s_addr != nh2->gate.ipv4.s_addr)
+ return false;
+ if (nh1->ifindex != nh2->ifindex)
+ return false;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ if (memcmp(&nh1->gate.ipv6, &nh2->gate.ipv6, 16))
+ return false;
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (memcmp(&nh1->gate.ipv6, &nh2->gate.ipv6, 16))
+ return false;
+ if (nh1->ifindex != nh2->ifindex)
+ return false;
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ if (nh1->bh_type != nh2->bh_type)
+ return false;
+ break;
+ }
+
+ return true;
+}
+
/* Update nexthop with label information. */
void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
u_int8_t num_labels, mpls_label_t *label)
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 0ca8a0063a..568243d3a9 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -118,6 +118,8 @@ void nexthop_add_labels(struct nexthop *, enum lsp_types_t, u_int8_t,
mpls_label_t *);
void nexthop_del_labels(struct nexthop *);
+extern bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2);
+
extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type);
extern int nexthop_same_no_recurse(const struct nexthop *next1,
const struct nexthop *next2);
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index e7f10487d1..e486247244 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -19,6 +19,7 @@
*/
#include <zebra.h>
+#include <vrf.h>
#include <nexthop.h>
#include <nexthop_group.h>
#include <vty.h>
@@ -28,6 +29,56 @@
#include "lib/nexthop_group_clippy.c"
#endif
+DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group")
+
+struct nexthop_group_hooks {
+ void (*new)(const char *name);
+ void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
+ const struct nexthop *nhop);
+ void (*del_nexthop)(const struct nexthop_group_cmd *nhg,
+ const struct nexthop *nhop);
+ void (*delete)(const char *name);
+};
+
+static struct nexthop_group_hooks nhg_hooks;
+
+static inline int
+nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
+ const struct nexthop_group_cmd *nhgc2);
+RB_GENERATE(nhgc_entry_head, nexthop_group_cmd, nhgc_entry,
+ nexthop_group_cmd_compare)
+
+struct nhgc_entry_head nhgc_entries;
+
+static inline int
+nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
+ const struct nexthop_group_cmd *nhgc2)
+{
+ return strcmp(nhgc1->name, nhgc2->name);
+}
+
+struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
+{
+ struct nexthop *nexthop;
+
+ for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
+ if (nexthop_same(nh, nexthop))
+ return nexthop;
+ }
+
+ return NULL;
+}
+
+struct nexthop_group *nexthop_group_new(void)
+{
+ return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group));
+}
+
+void nexthop_group_delete(struct nexthop_group **nhg)
+{
+ XFREE(MTYPE_NEXTHOP_GROUP, *nhg);
+}
+
/* Add nexthop to the end of a nexthop list. */
void nexthop_add(struct nexthop **target, struct nexthop *nexthop)
{
@@ -42,6 +93,27 @@ void nexthop_add(struct nexthop **target, struct nexthop *nexthop)
nexthop->prev = last;
}
+/* Delete nexthop from a nexthop list. */
+void nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
+{
+ struct nexthop *nexthop;
+
+ for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
+ if (nexthop_same(nh, nexthop))
+ break;
+ }
+
+ assert(nexthop);
+
+ if (nexthop->prev)
+ nexthop->prev->next = nexthop->next;
+ else
+ nhg->nexthop = nexthop->next;
+
+ if (nexthop->next)
+ nexthop->next->prev = nexthop->prev;
+}
+
void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
struct nexthop *rparent)
{
@@ -71,12 +143,169 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
}
}
-DEFPY (nexthop_group,
- nexthop_group_cmd,
- "nexthop-group NAME",
- "Enter into the nexthop-group submode\n"
- "Specify the NAME of the nexthop-group\n")
+static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nhgc->nhg.nexthop;
+ while (nexthop) {
+ struct nexthop *next = nexthop_next(nexthop);
+
+ if (nhg_hooks.del_nexthop)
+ nhg_hooks.del_nexthop(nhgc, nexthop);
+
+ nexthop_free(nexthop);
+
+ nexthop = next;
+ }
+}
+
+struct nexthop_group_cmd *nhgc_find(const char *name)
+{
+ struct nexthop_group_cmd find;
+
+ strlcpy(find.name, name, sizeof(find.name));
+
+ return RB_FIND(nhgc_entry_head, &nhgc_entries, &find);
+}
+
+static struct nexthop_group_cmd *nhgc_get(const char *name)
{
+ struct nexthop_group_cmd *nhgc;
+
+ nhgc = nhgc_find(name);
+ if (!nhgc) {
+ nhgc = XCALLOC(MTYPE_TMP, sizeof(*nhgc));
+ strlcpy(nhgc->name, name, sizeof(nhgc->name));
+
+ QOBJ_REG(nhgc, nexthop_group_cmd);
+ RB_INSERT(nhgc_entry_head, &nhgc_entries, nhgc);
+
+ if (nhg_hooks.new)
+ nhg_hooks.new(name);
+ }
+
+ return nhgc;
+}
+
+static void nhgc_delete(struct nexthop_group_cmd *nhgc)
+{
+ nhgc_delete_nexthops(nhgc);
+
+ if (nhg_hooks.delete)
+ nhg_hooks.delete(nhgc->name);
+
+ RB_REMOVE(nhgc_entry_head, &nhgc_entries, nhgc);
+}
+
+DEFINE_QOBJ_TYPE(nexthop_group_cmd)
+
+DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NAME",
+ "Enter into the nexthop-group submode\n"
+ "Specify the NAME of the nexthop-group\n")
+{
+ const char *nhg_name = argv[1]->arg;
+ struct nexthop_group_cmd *nhgc = NULL;
+
+ nhgc = nhgc_get(nhg_name);
+ VTY_PUSH_CONTEXT(NH_GROUP_NODE, nhgc);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NAME",
+ NO_STR
+ "Delete the nexthop-group\n"
+ "Specify the NAME of the nexthop-group\n")
+{
+ const char *nhg_name = argv[2]->arg;
+ struct nexthop_group_cmd *nhgc = NULL;
+
+ nhgc = nhgc_find(nhg_name);
+ if (nhgc)
+ nhgc_delete(nhgc);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
+ "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+ NO_STR
+ "Specify one of the nexthops in this ECMP group\n"
+ "v4 Address\n"
+ "v6 Address\n"
+ "Interface to use\n"
+ "If the nexthop is in a different vrf tell us\n"
+ "The nexthop-vrf Name\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+ struct vrf *vrf;
+ struct nexthop nhop;
+ struct nexthop *nh;
+
+ if (name)
+ vrf = vrf_lookup_by_name(name);
+ else
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+ if (!vrf) {
+ vty_out(vty, "Specified: %s is non-existent\n", name);
+ return CMD_WARNING;
+ }
+
+ memset(&nhop, 0, sizeof(nhop));
+ nhop.vrf_id = vrf->vrf_id;
+
+ if (addr->sa.sa_family == AF_INET) {
+ nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+ if (intf) {
+ nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
+ if (nhop.ifindex == IFINDEX_INTERNAL) {
+ vty_out(vty,
+ "Specified Intf %s does not exist in vrf: %s\n",
+ intf, vrf->name);
+ return CMD_WARNING;
+ }
+ } else
+ nhop.type = NEXTHOP_TYPE_IPV4;
+ } else {
+ memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
+ if (intf) {
+ nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
+ if (nhop.ifindex == IFINDEX_INTERNAL) {
+ vty_out(vty,
+ "Specified Intf %s does not exist in vrf: %s\n",
+ intf, vrf->name);
+ return CMD_WARNING;
+ }
+ } else
+ nhop.type = NEXTHOP_TYPE_IPV6;
+ }
+
+ nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+ if (no) {
+ if (nh) {
+ nexthop_del(&nhgc->nhg, nh);
+
+ if (nhg_hooks.del_nexthop)
+ nhg_hooks.del_nexthop(nhgc, nh);
+
+ nexthop_free(nh);
+ }
+ } else if (!nh) {
+ /* must be adding new nexthop since !no and !nexthop_exists */
+ nh = nexthop_new();
+
+ memcpy(nh, &nhop, sizeof(nhop));
+ nexthop_add(&nhgc->nhg.nexthop, nh);
+
+ if (nhg_hooks.add_nexthop)
+ nhg_hooks.add_nexthop(nhgc, nh);
+ }
+
return CMD_SUCCESS;
}
@@ -86,15 +315,85 @@ struct cmd_node nexthop_group_node = {
1
};
+void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
+{
+ char buf[100];
+ struct vrf *vrf;
+
+ vty_out(vty, " nexthop ");
+
+ switch (nh->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out(vty, "%s", ifindex2ifname(nh->ifindex, nh->vrf_id));
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ vty_out(vty, "%s", inet_ntoa(nh->gate.ipv4));
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4),
+ ifindex2ifname(nh->ifindex, nh->vrf_id));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ vty_out(vty, "%s",
+ inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ vty_out(vty, "%s %s",
+ inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)),
+ ifindex2ifname(nh->ifindex, nh->vrf_id));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ break;
+ }
+
+ if (nh->vrf_id != VRF_DEFAULT) {
+ vrf = vrf_lookup_by_id(nh->vrf_id);
+ vty_out(vty, " nexthop-vrf %s", vrf->name);
+ }
+ vty_out(vty, "\n");
+}
+
static int nexthop_group_write(struct vty *vty)
{
- vty_out(vty, "!\n");
+ struct nexthop_group_cmd *nhgc;
+ struct nexthop *nh;
+
+ RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+ vty_out(vty, "nexthop-group %s\n", nhgc->name);
+
+ for (nh = nhgc->nhg.nexthop; nh; nh = nh->next)
+ nexthop_group_write_nexthop(vty, nh);
+
+ vty_out(vty, "!\n");
+ }
return 1;
}
-void nexthop_group_init(void)
+void nexthop_group_init(void (*new)(const char *name),
+ void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
+ const struct nexthop *nhop),
+ void (*del_nexthop)(const struct nexthop_group_cmd *nhg,
+ const struct nexthop *nhop),
+ void (*delete)(const char *name))
{
+ RB_INIT(nhgc_entry_head, &nhgc_entries);
+
install_node(&nexthop_group_node, nexthop_group_write);
install_element(CONFIG_NODE, &nexthop_group_cmd);
+ install_element(CONFIG_NODE, &no_nexthop_group_cmd);
+
+ install_default(NH_GROUP_NODE);
+ install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
+
+ memset(&nhg_hooks, 0, sizeof(nhg_hooks));
+
+ if (new)
+ nhg_hooks.new = new;
+ if (add_nexthop)
+ nhg_hooks.add_nexthop = add_nexthop;
+ if (del_nexthop)
+ nhg_hooks.del_nexthop = del_nexthop;
+ if (delete)
+ nhg_hooks.delete = delete;
}
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 561fe96425..c2e4c4d757 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -21,6 +21,8 @@
#ifndef __NEXTHOP_GROUP__
#define __NEXTHOP_GROUP__
+#include <vty.h>
+
/*
* What is a nexthop group?
*
@@ -33,9 +35,11 @@ struct nexthop_group {
struct nexthop *nexthop;
};
-void nexthop_group_init(void);
+struct nexthop_group *nexthop_group_new(void);
+void nexthop_group_delete(struct nexthop_group **nhg);
void nexthop_add(struct nexthop **target, struct nexthop *nexthop);
+void nexthop_del(struct nexthop_group *nhg, struct nexthop *nexthop);
void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
struct nexthop *rparent);
@@ -51,4 +55,40 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
(nhop) = (head.nexthop); \
(nhop); \
(nhop) = nexthop_next(nhop)
+
+struct nexthop_group_cmd {
+
+ RB_ENTRY(nexthop_group_cmd) nhgc_entry;
+
+ char name[80];
+
+ struct nexthop_group nhg;
+
+ QOBJ_FIELDS
+};
+RB_HEAD(nhgc_entry_head, nexthp_group_cmd);
+RB_PROTOTYPE(nhgc_entry_head, nexthop_group_cmd, nhgc_entry,
+ nexthop_group_cmd_compare)
+DECLARE_QOBJ_TYPE(nexthop_group_cmd)
+
+/*
+ * Initialize nexthop_groups. If you are interested in when
+ * a nexthop_group is added/deleted/modified, then set the
+ * appropriate callback functions to handle it in your
+ * code
+ */
+void nexthop_group_init(
+ void (*new)(const char *name),
+ void (*add_nexthop)(const struct nexthop_group_cmd *nhgc,
+ const struct nexthop *nhop),
+ void (*del_nexthop)(const struct nexthop_group_cmd *nhgc,
+ const struct nexthop *nhop),
+ void (*delete)(const char *name));
+
+extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
+ struct nexthop *nh);
+
+extern struct nexthop_group_cmd *nhgc_find(const char *name);
+
+extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
#endif
diff --git a/lib/strlcat.c b/lib/strlcat.c
index 8186304437..be211f82a8 100644
--- a/lib/strlcat.c
+++ b/lib/strlcat.c
@@ -28,23 +28,25 @@
#ifndef HAVE_STRLCAT
#undef strlcat
-size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcat(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
-size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size)
+size_t strlcat(char *__restrict dest,
+ const char *__restrict src, size_t destsize)
{
size_t src_length = strlen(src);
/* Our implementation strlcat supports dest == NULL if size == 0
(for consistency with snprintf and strlcpy), but strnlen does
not, so we have to cover this case explicitly. */
- if (size == 0)
+ if (destsize == 0)
return src_length;
- size_t dest_length = strnlen(dest, size);
- if (dest_length != size) {
+ size_t dest_length = strnlen(dest, destsize);
+ if (dest_length != destsize) {
/* Copy at most the remaining number of characters in the
destination buffer. Leave for the NUL terminator. */
- size_t to_copy = size - dest_length - 1;
+ size_t to_copy = destsize - dest_length - 1;
/* But not more than what is available in the source string. */
if (to_copy > src_length)
to_copy = src_length;
diff --git a/lib/strlcpy.c b/lib/strlcpy.c
index b7681754aa..b0c33ca7f4 100644
--- a/lib/strlcpy.c
+++ b/lib/strlcpy.c
@@ -27,23 +27,26 @@
#ifndef HAVE_STRLCPY
#undef strlcpy
-size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcpy(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
-size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size)
+size_t strlcpy(char *__restrict dest,
+ const char *__restrict src, size_t destsize)
{
size_t src_length = strlen(src);
- if (__builtin_expect(src_length >= size, 0)) {
- if (size > 0) {
- /* Copy the leading portion of the string. The last
- character is subsequently overwritten with the NUL
- terminator, but the destination size is usually a
- multiple of a small power of two, so writing it twice
- should be more efficient than copying an odd number
- of
- bytes. */
- memcpy(dest, src, size);
- dest[size - 1] = '\0';
+ if (__builtin_expect(src_length >= destsize, 0)) {
+ if (destsize > 0) {
+ /*
+ * Copy the leading portion of the string. The last
+ * character is subsequently overwritten with the NUL
+ * terminator, but the destination destsize is usually
+ * a multiple of a small power of two, so writing it
+ * twice should be more efficient than copying an odd
+ * number of bytes.
+ */
+ memcpy(dest, src, destsize);
+ dest[destsize - 1] = '\0';
}
} else
/* Copy the string and its terminating NUL character. */
diff --git a/lib/thread.c b/lib/thread.c
index a221c77628..d26be1541f 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -343,7 +343,6 @@ static void initializer()
pthread_key_create(&thread_current, NULL);
}
-/* Allocate new thread master. */
struct thread_master *thread_master_create(const char *name)
{
struct thread_master *rv;
@@ -426,6 +425,17 @@ struct thread_master *thread_master_create(const char *name)
return rv;
}
+void thread_master_set_name(struct thread_master *master, const char *name)
+{
+ pthread_mutex_lock(&master->mtx);
+ {
+ if (master->name)
+ XFREE(MTYPE_THREAD_MASTER, master->name);
+ master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
+ }
+ pthread_mutex_unlock(&master->mtx);
+}
+
/* Add a new thread to the list. */
static void thread_list_add(struct thread_list *list, struct thread *thread)
{
diff --git a/lib/thread.h b/lib/thread.h
index c830446e10..f7c110914d 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -174,6 +174,7 @@ struct cpu_thread_history {
/* Prototypes. */
extern struct thread_master *thread_master_create(const char *);
+void thread_master_set_name(struct thread_master *master, const char *name);
extern void thread_master_free(struct thread_master *);
extern void thread_master_free_unused(struct thread_master *);
diff --git a/lib/vrf.c b/lib/vrf.c
index f8e5a97904..6002aee514 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -33,6 +33,7 @@
#include "memory.h"
#include "command.h"
#include "ns.h"
+#include "privs.h"
/* default VRF ID value used when VRF backend is not NETNS */
#define VRF_DEFAULT_INTERNAL 0
@@ -52,6 +53,7 @@ struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id);
struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
static int vrf_backend;
+static struct zebra_privs_t *vrf_daemon_privs;
/*
* Turn on/off debug code
@@ -690,14 +692,24 @@ DEFUN_NOSH (vrf_netns,
"Attach VRF to a Namespace\n"
"The file name in " NS_RUN_DIR ", or a full pathname\n")
{
- int idx_name = 1;
+ int idx_name = 1, ret;
char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
VTY_DECLVAR_CONTEXT(vrf, vrf);
if (!pathname)
return CMD_WARNING_CONFIG_FAILED;
- return vrf_netns_handler_create(vty, vrf, pathname, NS_UNKNOWN);
+
+ if (vrf_daemon_privs &&
+ vrf_daemon_privs->change(ZPRIVS_RAISE))
+ zlog_err("%s: Can't raise privileges", __func__);
+
+ ret = vrf_netns_handler_create(vty, vrf, pathname, NS_UNKNOWN);
+
+ if (vrf_daemon_privs &&
+ vrf_daemon_privs->change(ZPRIVS_LOWER))
+ zlog_err("%s: Can't lower privileges", __func__);
+ return ret;
}
DEFUN (no_vrf_netns,
@@ -779,7 +791,8 @@ void vrf_install_commands(void)
install_element(ENABLE_NODE, &no_vrf_debug_cmd);
}
-void vrf_cmd_init(int (*writefunc)(struct vty *vty))
+void vrf_cmd_init(int (*writefunc)(struct vty *vty),
+ struct zebra_privs_t *daemon_privs)
{
install_element(CONFIG_NODE, &vrf_cmd);
install_element(CONFIG_NODE, &no_vrf_cmd);
@@ -787,6 +800,7 @@ void vrf_cmd_init(int (*writefunc)(struct vty *vty))
install_default(VRF_NODE);
if (vrf_is_backend_netns() && ns_have_netns()) {
/* Install NS commands. */
+ vrf_daemon_privs = daemon_privs;
install_element(VRF_NODE, &vrf_netns_cmd);
install_element(VRF_NODE, &no_vrf_netns_cmd);
}
diff --git a/lib/vrf.h b/lib/vrf.h
index 6482740aa1..617405a77e 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -242,7 +242,8 @@ extern int vrf_switchback_to_initial(void);
/* VRF vty command initialisation
*/
-extern void vrf_cmd_init(int (*writefunc)(struct vty *vty));
+extern void vrf_cmd_init(int (*writefunc)(struct vty *vty),
+ struct zebra_privs_t *daemon_priv);
/* VRF vty debugging
*/
diff --git a/lib/zclient.c b/lib/zclient.c
index 3ad4d9c6e7..777f6fcf9b 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -322,6 +322,18 @@ stream_failure:
return 0;
}
+bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr)
+{
+ STREAM_GETW(zmsg, hdr->length);
+ STREAM_GETC(zmsg, hdr->marker);
+ STREAM_GETC(zmsg, hdr->version);
+ STREAM_GETL(zmsg, hdr->vrf_id);
+ STREAM_GETW(zmsg, hdr->command);
+ return true;
+stream_failure:
+ return false;
+}
+
/* Send simple Zebra message. */
static int zebra_message_send(struct zclient *zclient, int command,
vrf_id_t vrf_id)
diff --git a/lib/zclient.h b/lib/zclient.h
index 1aa94b641c..8033488444 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -237,14 +237,13 @@ struct zclient {
*/
#define ZAPI_MESSAGE_TABLEID 0x80
+#define ZSERV_VERSION 5
/* Zserv protocol message header */
-struct zserv_header {
+struct zmsghdr {
uint16_t length;
- uint8_t marker; /* corresponds to command field in old zserv
- * always set to 255 in new zserv.
- */
+ /* Always set to 255 in new zserv */
+ uint8_t marker;
uint8_t version;
-#define ZSERV_VERSION 5
vrf_id_t vrf_id;
uint16_t command;
};
@@ -380,9 +379,11 @@ struct zclient_options {
/* Prototypes of zebra client service functions. */
extern struct zclient *zclient_new(struct thread_master *);
+/* clang-format off */
#if CONFDATE > 20181101
CPP_NOTICE("zclient_new_notify can take over or zclient_new now");
#endif
+/* clang-format on */
extern struct zclient_options zclient_options_default;
@@ -449,9 +450,58 @@ extern int zclient_send_message(struct zclient *);
/* create header for command, length to be filled in by user later */
extern void zclient_create_header(struct stream *, uint16_t, vrf_id_t);
+/*
+ * Read sizeof(struct zmsghdr) bytes from the provided socket and parse the
+ * received data into the specified fields. If this is successful, read the
+ * rest of the packet into the provided stream.
+ *
+ * s
+ * The stream to read into
+ *
+ * sock
+ * The socket to read from
+ *
+ * size
+ * Parsed message size will be placed in the pointed-at integer
+ *
+ * marker
+ * Parsed marker will be placed in the pointed-at byte
+ *
+ * version
+ * Parsed version will be placed in the pointed-at byte
+ *
+ * vrf_id
+ * Parsed VRF ID will be placed in the pointed-at vrf_id_t
+ *
+ * cmd
+ * Parsed command number will be placed in the pointed-at integer
+ *
+ * Returns:
+ * -1 if:
+ * - insufficient data for header was read
+ * - a version mismatch was detected
+ * - a marker mismatch was detected
+ * - header size field specified more data than could be read
+ */
extern int zclient_read_header(struct stream *s, int sock, u_int16_t *size,
u_char *marker, u_char *version,
vrf_id_t *vrf_id, u_int16_t *cmd);
+/*
+ * Parse header from ZAPI message stream into struct zmsghdr.
+ * This function assumes the stream getp points at the first byte of the header.
+ * If the function is successful then the stream getp will point to the byte
+ * immediately after the last byte of the header.
+ *
+ * zmsg
+ * The stream containing the header
+ *
+ * hdr
+ * The header struct to parse into.
+ *
+ * Returns:
+ * true if parsing succeeded, false otherwise
+ */
+extern bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr);
extern void zclient_interface_set_master(struct zclient *client,
struct interface *master,
@@ -468,10 +518,11 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s,
extern void zebra_interface_if_set_value(struct stream *, struct interface *);
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
+/* clang-format off */
#if CONFDATE > 20180823
-CPP_NOTICE(
- "zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now");
+CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now");
#endif
+/* clang-format on */
extern int zapi_ipv4_route(u_char, struct zclient *, struct prefix_ipv4 *,
struct zapi_ipv4 *) __attribute__((deprecated));
diff --git a/lib/zebra.h b/lib/zebra.h
index 262ad2e43d..923f6f77c6 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -232,10 +232,12 @@ typedef unsigned char u_int8_t;
#include "zassert.h"
#ifndef HAVE_STRLCAT
-size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcat(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
#endif
#ifndef HAVE_STRLCPY
-size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcpy(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
#endif
#ifdef HAVE_BROKEN_CMSG_FIRSTHDR