summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/if.c29
-rw-r--r--lib/if.h20
-rw-r--r--lib/if_rmap.c1
-rw-r--r--lib/libfrr.c5
-rw-r--r--lib/linklist.c6
-rw-r--r--lib/linklist.h10
-rw-r--r--lib/log.c2
-rw-r--r--lib/log.h4
-rw-r--r--lib/log_int.h1
-rw-r--r--lib/nexthop.h4
-rw-r--r--lib/nexthop_group.c24
-rw-r--r--lib/nexthop_group.h5
-rw-r--r--lib/northbound.c202
-rw-r--r--lib/northbound.h69
-rw-r--r--lib/northbound_sysrepo.c2
-rw-r--r--lib/prefix.c29
-rw-r--r--lib/prefix.h12
-rw-r--r--lib/privs.c88
-rw-r--r--lib/privs.h19
-rw-r--r--lib/vxlan.h1
-rw-r--r--lib/yang.c44
-rw-r--r--lib/yang.h45
-rw-r--r--lib/zclient.c11
-rw-r--r--lib/zclient.h6
24 files changed, 442 insertions, 197 deletions
diff --git a/lib/if.c b/lib/if.c
index a31b44c7d5..86b850c059 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -436,13 +436,13 @@ void if_set_index(struct interface *ifp, ifindex_t ifindex)
}
/* Does interface up ? */
-int if_is_up(struct interface *ifp)
+int if_is_up(const struct interface *ifp)
{
return ifp->flags & IFF_UP;
}
/* Is interface running? */
-int if_is_running(struct interface *ifp)
+int if_is_running(const struct interface *ifp)
{
return ifp->flags & IFF_RUNNING;
}
@@ -450,7 +450,7 @@ int if_is_running(struct interface *ifp)
/* Is the interface operative, eg. either UP & RUNNING
or UP & !ZEBRA_INTERFACE_LINK_DETECTION and
if ptm checking is enabled, then ptm check has passed */
-int if_is_operative(struct interface *ifp)
+int if_is_operative(const struct interface *ifp)
{
return ((ifp->flags & IFF_UP)
&& (((ifp->flags & IFF_RUNNING)
@@ -461,7 +461,7 @@ int if_is_operative(struct interface *ifp)
/* Is the interface operative, eg. either UP & RUNNING
or UP & !ZEBRA_INTERFACE_LINK_DETECTION, without PTM check */
-int if_is_no_ptm_operative(struct interface *ifp)
+int if_is_no_ptm_operative(const struct interface *ifp)
{
return ((ifp->flags & IFF_UP)
&& ((ifp->flags & IFF_RUNNING)
@@ -470,7 +470,7 @@ int if_is_no_ptm_operative(struct interface *ifp)
}
/* Is this loopback interface ? */
-int if_is_loopback(struct interface *ifp)
+int if_is_loopback(const struct interface *ifp)
{
/* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M
* but Y on platform N?
@@ -479,12 +479,12 @@ int if_is_loopback(struct interface *ifp)
}
/* Check interface is VRF */
-int if_is_vrf(struct interface *ifp)
+int if_is_vrf(const struct interface *ifp)
{
return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
}
-bool if_is_loopback_or_vrf(struct interface *ifp)
+bool if_is_loopback_or_vrf(const struct interface *ifp)
{
if (if_is_loopback(ifp) || if_is_vrf(ifp))
return true;
@@ -493,19 +493,19 @@ bool if_is_loopback_or_vrf(struct interface *ifp)
}
/* Does this interface support broadcast ? */
-int if_is_broadcast(struct interface *ifp)
+int if_is_broadcast(const struct interface *ifp)
{
return ifp->flags & IFF_BROADCAST;
}
/* Does this interface support broadcast ? */
-int if_is_pointopoint(struct interface *ifp)
+int if_is_pointopoint(const struct interface *ifp)
{
return ifp->flags & IFF_POINTOPOINT;
}
/* Does this interface support multicast ? */
-int if_is_multicast(struct interface *ifp)
+int if_is_multicast(const struct interface *ifp)
{
return ifp->flags & IFF_MULTICAST;
}
@@ -1303,7 +1303,7 @@ static int lib_interface_create(enum nb_event event,
#else
ifp = if_get_by_name(ifname, vrf->vrf_id);
#endif /* SUNOS_5 */
- yang_dnode_set_entry(dnode, ifp);
+ nb_running_set_entry(dnode, ifp);
break;
}
@@ -1315,10 +1315,10 @@ static int lib_interface_destroy(enum nb_event event,
{
struct interface *ifp;
- ifp = yang_dnode_get_entry(dnode, true);
switch (event) {
case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(dnode, NULL, true);
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
zlog_warn("%s: only inactive interfaces can be deleted",
__func__);
@@ -1329,6 +1329,7 @@ static int lib_interface_destroy(enum nb_event event,
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
+ ifp = nb_running_unset_entry(dnode);
if_delete(ifp);
break;
}
@@ -1349,7 +1350,7 @@ static int lib_interface_description_modify(enum nb_event event,
if (event != NB_EV_APPLY)
return NB_OK;
- ifp = yang_dnode_get_entry(dnode, true);
+ ifp = nb_running_get_entry(dnode, NULL, true);
XFREE(MTYPE_TMP, ifp->desc);
description = yang_dnode_get_string(dnode, NULL);
ifp->desc = XSTRDUP(MTYPE_TMP, description);
@@ -1365,7 +1366,7 @@ static int lib_interface_description_destroy(enum nb_event event,
if (event != NB_EV_APPLY)
return NB_OK;
- ifp = yang_dnode_get_entry(dnode, true);
+ ifp = nb_running_get_entry(dnode, NULL, true);
XFREE(MTYPE_TMP, ifp->desc);
return NB_OK;
diff --git a/lib/if.h b/lib/if.h
index 6689769beb..d26d4dd68b 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -499,16 +499,16 @@ extern void if_delete_retain(struct interface *);
deletes it from the interface list and frees the structure. */
extern void if_delete(struct interface *);
-extern int if_is_up(struct interface *);
-extern int if_is_running(struct interface *);
-extern int if_is_operative(struct interface *);
-extern int if_is_no_ptm_operative(struct interface *);
-extern int if_is_loopback(struct interface *);
-extern int if_is_vrf(struct interface *ifp);
-extern bool if_is_loopback_or_vrf(struct interface *ifp);
-extern int if_is_broadcast(struct interface *);
-extern int if_is_pointopoint(struct interface *);
-extern int if_is_multicast(struct interface *);
+extern int if_is_up(const struct interface *ifp);
+extern int if_is_running(const struct interface *ifp);
+extern int if_is_operative(const struct interface *ifp);
+extern int if_is_no_ptm_operative(const struct interface *ifp);
+extern int if_is_loopback(const struct interface *ifp);
+extern int if_is_vrf(const struct interface *ifp);
+extern bool if_is_loopback_or_vrf(const struct interface *ifp);
+extern int if_is_broadcast(const struct interface *ifp);
+extern int if_is_pointopoint(const struct interface *ifp);
+extern int if_is_multicast(const struct interface *ifp);
struct vrf;
extern void if_terminate(struct vrf *vrf);
extern void if_dump_all(void);
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
index d8236b6b25..b0802da961 100644
--- a/lib/if_rmap.c
+++ b/lib/if_rmap.c
@@ -291,6 +291,7 @@ int config_write_if_rmap(struct vty *vty,
void if_rmap_ctx_delete(struct if_rmap_ctx *ctx)
{
+ listnode_delete(if_rmap_ctx_list, ctx);
hash_clean(ctx->ifrmaphash, (void (*)(void *))if_rmap_free);
if (ctx->name)
XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 1afe30d618..0d4c8d6c0f 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -38,6 +38,7 @@
#include "lib_errors.h"
#include "db.h"
#include "northbound_cli.h"
+#include "northbound_db.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
@@ -654,6 +655,10 @@ struct thread_master *frr_init(void)
yang_init();
nb_init(master, di->yang_modules, di->n_yang_modules);
+ if (nb_db_init() != NB_OK)
+ flog_warn(EC_LIB_NB_DATABASE,
+ "%s: failed to initialize northbound database",
+ __func__);
return master;
}
diff --git a/lib/linklist.c b/lib/linklist.c
index f0d0c29245..40c4b27169 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -50,7 +50,7 @@ static void listnode_free(struct listnode *node)
XFREE(MTYPE_LINK_NODE, node);
}
-void listnode_add(struct list *list, void *val)
+struct listnode *listnode_add(struct list *list, void *val)
{
struct listnode *node;
@@ -68,6 +68,8 @@ void listnode_add(struct list *list, void *val)
list->tail = node;
list->count++;
+
+ return node;
}
void listnode_add_head(struct list *list, void *val)
@@ -326,7 +328,7 @@ void list_sort(struct list *list, int (*cmp)(const void **, const void **))
XFREE(MTYPE_TMP, items);
}
-void listnode_add_force(struct list **list, void *val)
+struct listnode *listnode_add_force(struct list **list, void *val)
{
if (*list == NULL)
*list = list_new();
diff --git a/lib/linklist.h b/lib/linklist.h
index e75d863431..c30d8d314a 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -84,7 +84,7 @@ extern struct list *list_new(void);
* data
* element to add
*/
-extern void listnode_add(struct list *list, void *data);
+extern struct listnode *listnode_add(struct list *list, void *data);
/*
* Add a new element to the beginning of a list.
@@ -343,7 +343,13 @@ extern void list_add_list(struct list *list, struct list *add);
extern struct listnode *listnode_lookup_nocheck(struct list *list, void *data);
-extern void listnode_add_force(struct list **list, void *val);
+/*
+ * Add a node to *list, if non-NULL. Otherwise, allocate a new list, mail
+ * it back in *list, and add a new node.
+ *
+ * Return: the new node.
+ */
+extern struct listnode *listnode_add_force(struct list **list, void *val);
#ifdef __cplusplus
}
diff --git a/lib/log.c b/lib/log.c
index 8724e0db93..e64c00186b 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1068,6 +1068,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_IPTABLE_DELETE),
DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER),
DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
+ DESC_ENTRY(ZEBRA_VXLAN_SG_ADD),
+ DESC_ENTRY(ZEBRA_VXLAN_SG_DEL),
};
#undef DESC_ENTRY
diff --git a/lib/log.h b/lib/log.h
index 189857a907..9368bf9e82 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -94,6 +94,7 @@ extern void zlog_warn(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_info(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_notice(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
/* For logs which have error codes associated with them */
#define flog_err(ferr_id, format, ...) \
@@ -102,7 +103,8 @@ extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
flog_err(ferr_id, format, ##__VA_ARGS__)
#define flog_warn(ferr_id, format, ...) \
zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
-
+#define flog(priority, ferr_id, format, ...) \
+ zlog(priority, "[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
extern void zlog_thread_info(int log_level);
diff --git a/lib/log_int.h b/lib/log_int.h
index 58ae031e1b..287e626eab 100644
--- a/lib/log_int.h
+++ b/lib/log_int.h
@@ -51,7 +51,6 @@ extern const char *zlog_priority[];
/* Generic function for zlog. */
extern void vzlog(int priority, const char *format, va_list args);
-extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
#ifdef __cplusplus
}
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 24b0953191..663acaeb69 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -81,8 +81,8 @@ struct nexthop {
#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */
#define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */
-#define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */
-#define NEXTHOP_FLAG_DUPLICATE (1 << 6) /* nexthop duplicates another active one */
+#define NEXTHOP_FLAG_DUPLICATE (1 << 5) /* nexthop duplicates another active one */
+#define NEXTHOP_FLAG_RNH_FILTERED (1 << 6) /* rmap filtered, used by rnh */
#define NEXTHOP_IS_ACTIVE(flags) \
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
&& !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index fa89b7708c..ed22f64494 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -59,6 +59,30 @@ nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
return strcmp(nhgc1->name, nhgc2->name);
}
+uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
+{
+ struct nexthop *nhop;
+ uint8_t num = 0;
+
+ for (ALL_NEXTHOPS_PTR(nhg, nhop))
+ num++;
+
+ return num;
+}
+
+uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
+{
+ struct nexthop *nhop;
+ uint8_t num = 0;
+
+ for (ALL_NEXTHOPS_PTR(nhg, nhop)) {
+ if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
+ num++;
+ }
+
+ return num;
+}
+
struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
{
struct nexthop *nexthop;
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index f68033c20c..5adf2db937 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -117,6 +117,11 @@ extern struct nexthop_group_cmd *nhgc_find(const char *name);
extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
+/* Return the number of nexthops in this nhg */
+extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
+extern uint8_t
+nexthop_group_active_nexthop_num(const struct nexthop_group *nhg);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/northbound.c b/lib/northbound.c
index 9deb9c6cce..5e031ac2ce 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -22,6 +22,7 @@
#include "libfrr.h"
#include "log.h"
#include "lib_errors.h"
+#include "hash.h"
#include "command.h"
#include "debug.h"
#include "db.h"
@@ -31,10 +32,14 @@
DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node")
DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration")
+DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry")
/* Running configuration - shouldn't be modified directly. */
struct nb_config *running_config;
+/* Hash table of user pointers associated with configuration entries. */
+static struct hash *running_config_entries;
+
/*
* Global lock used to prevent multiple configuration transactions from
* happening concurrently.
@@ -454,13 +459,6 @@ int nb_candidate_edit(struct nb_config *candidate,
struct lyd_node *dnode;
char xpath_edit[XPATH_MAXLEN];
- if (!nb_operation_is_valid(operation, nb_node->snode)) {
- flog_warn(EC_LIB_NB_CANDIDATE_EDIT_ERROR,
- "%s: %s operation not valid for %s", __func__,
- nb_operation_name(operation), xpath);
- return NB_ERR;
- }
-
/* Use special notation for leaf-lists (RFC 6020, section 9.13.5). */
if (nb_node->snode->nodetype == LYS_LEAFLIST)
snprintf(xpath_edit, sizeof(xpath_edit), "%s[.='%s']", xpath,
@@ -535,38 +533,6 @@ int nb_candidate_update(struct nb_config *candidate)
}
/*
- * The northbound configuration callbacks use the 'priv' pointer present in the
- * libyang lyd_node structure to store pointers to FRR internal variables
- * associated to YANG lists and presence containers. Before commiting a
- * candidate configuration, we must restore the 'priv' pointers stored in the
- * running configuration since they might be lost while editing the candidate.
- */
-static void nb_candidate_restore_priv_pointers(struct nb_config *candidate)
-{
- struct lyd_node *root, *next, *dnode_iter;
-
- LY_TREE_FOR (running_config->dnode, root) {
- LY_TREE_DFS_BEGIN (root, next, dnode_iter) {
- struct lyd_node *dnode_candidate;
- char xpath[XPATH_MAXLEN];
-
- if (!dnode_iter->priv)
- goto next;
-
- yang_dnode_get_path(dnode_iter, xpath, sizeof(xpath));
- dnode_candidate =
- yang_dnode_get(candidate->dnode, xpath);
- if (dnode_candidate)
- yang_dnode_set_entry(dnode_candidate,
- dnode_iter->priv);
-
- next:
- LY_TREE_DFS_END(root, next, dnode_iter);
- }
- }
-}
-
-/*
* Perform YANG syntactic and semantic validation.
*
* WARNING: lyd_validate() can change the configuration as part of the
@@ -588,7 +554,6 @@ static int nb_candidate_validate_changes(struct nb_config *candidate,
{
struct nb_config_cb *cb;
- nb_candidate_restore_priv_pointers(candidate);
RB_FOREACH (cb, nb_config_cbs, changes) {
struct nb_config_change *change = (struct nb_config_change *)cb;
int ret;
@@ -753,40 +718,44 @@ static int nb_callback_configuration(const enum nb_event event,
ret = (*nb_node->cbs.move)(event, dnode);
break;
default:
- break;
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unknown operation (%u) [xpath %s]", __func__,
+ operation, xpath);
+ exit(1);
}
if (ret != NB_OK) {
- enum lib_log_refs ref = 0;
+ int priority;
+ enum lib_log_refs ref;
switch (event) {
case NB_EV_VALIDATE:
+ priority = LOG_WARNING;
ref = EC_LIB_NB_CB_CONFIG_VALIDATE;
break;
case NB_EV_PREPARE:
+ priority = LOG_WARNING;
ref = EC_LIB_NB_CB_CONFIG_PREPARE;
break;
case NB_EV_ABORT:
+ priority = LOG_WARNING;
ref = EC_LIB_NB_CB_CONFIG_ABORT;
break;
case NB_EV_APPLY:
+ priority = LOG_ERR;
ref = EC_LIB_NB_CB_CONFIG_APPLY;
break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unknown event (%u) [xpath %s]",
+ __func__, event, xpath);
+ exit(1);
}
- if (event == NB_EV_VALIDATE || event == NB_EV_PREPARE)
- flog_warn(
- ref,
- "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
- __func__, nb_err_name(ret),
- nb_event_name(event),
- nb_operation_name(operation), xpath);
- else
- flog_err(
- ref,
- "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
- __func__, nb_err_name(ret),
- nb_event_name(event),
- nb_operation_name(operation), xpath);
+
+ flog(priority, ref,
+ "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
+ __func__, nb_err_name(ret), nb_event_name(event),
+ nb_operation_name(operation), xpath);
}
return ret;
@@ -1548,6 +1517,116 @@ int nb_notification_send(const char *xpath, struct list *arguments)
return ret;
}
+/* Running configuration user pointers management. */
+struct nb_config_entry {
+ char xpath[XPATH_MAXLEN];
+ void *entry;
+};
+
+static bool running_config_entry_cmp(const void *value1, const void *value2)
+{
+ const struct nb_config_entry *c1 = value1;
+ const struct nb_config_entry *c2 = value2;
+
+ return strmatch(c1->xpath, c2->xpath);
+}
+
+static unsigned int running_config_entry_key_make(void *value)
+{
+ return string_hash_make(value);
+}
+
+static void *running_config_entry_alloc(void *p)
+{
+ struct nb_config_entry *new, *key = p;
+
+ new = XCALLOC(MTYPE_NB_CONFIG_ENTRY, sizeof(*new));
+ strlcpy(new->xpath, key->xpath, sizeof(new->xpath));
+
+ return new;
+}
+
+static void running_config_entry_free(void *arg)
+{
+ XFREE(MTYPE_NB_CONFIG_ENTRY, arg);
+}
+
+void nb_running_set_entry(const struct lyd_node *dnode, void *entry)
+{
+ struct nb_config_entry *config, s;
+
+ yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+ config = hash_get(running_config_entries, &s,
+ running_config_entry_alloc);
+ config->entry = entry;
+}
+
+static void *nb_running_unset_entry_helper(const struct lyd_node *dnode)
+{
+ struct nb_config_entry *config, s;
+ struct lyd_node *child;
+ void *entry = NULL;
+
+ yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+ config = hash_release(running_config_entries, &s);
+ if (config) {
+ entry = config->entry;
+ running_config_entry_free(config);
+ }
+
+ /* Unset user pointers from the child nodes. */
+ if (CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER)) {
+ LY_TREE_FOR (dnode->child, child) {
+ (void)nb_running_unset_entry_helper(child);
+ }
+ }
+
+ return entry;
+}
+
+void *nb_running_unset_entry(const struct lyd_node *dnode)
+{
+ void *entry;
+
+ entry = nb_running_unset_entry_helper(dnode);
+ assert(entry);
+
+ return entry;
+}
+
+void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
+ bool abort_if_not_found)
+{
+ const struct lyd_node *orig_dnode = dnode;
+ char xpath_buf[XPATH_MAXLEN];
+
+ assert(dnode || xpath);
+
+ if (!dnode)
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+
+ while (dnode) {
+ struct nb_config_entry *config, s;
+
+ yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+ config = hash_lookup(running_config_entries, &s);
+ if (config)
+ return config->entry;
+
+ dnode = dnode->parent;
+ }
+
+ if (!abort_if_not_found)
+ return NULL;
+
+ yang_dnode_get_path(orig_dnode, xpath_buf, sizeof(xpath_buf));
+ flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
+ "%s: failed to find entry [xpath %s]", __func__, xpath_buf);
+ zlog_backtrace(LOG_ERR);
+ abort();
+}
+
+/* Logging functions. */
const char *nb_event_name(enum nb_event event)
{
switch (event) {
@@ -1677,14 +1756,11 @@ void nb_init(struct thread_master *tm,
exit(1);
}
- /* Initialize the northbound database (used for the rollback log). */
- if (nb_db_init() != NB_OK)
- flog_warn(EC_LIB_NB_DATABASE,
- "%s: failed to initialize northbound database",
- __func__);
-
/* Create an empty running configuration. */
running_config = nb_config_new(NULL);
+ running_config_entries = hash_create(running_config_entry_key_make,
+ running_config_entry_cmp,
+ "Running Configuration Entries");
/* Initialize the northbound CLI. */
nb_cli_init(tm);
@@ -1699,5 +1775,7 @@ void nb_terminate(void)
nb_nodes_delete();
/* Delete the running configuration. */
+ hash_clean(running_config_entries, running_config_entry_free);
+ hash_free(running_config_entries);
nb_config_free(running_config);
}
diff --git a/lib/northbound.h b/lib/northbound.h
index bfa28b3f65..14f27c1d41 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -808,6 +808,75 @@ extern bool nb_operation_is_valid(enum nb_operation operation,
extern int nb_notification_send(const char *xpath, struct list *arguments);
/*
+ * Associate a user pointer to a configuration node.
+ *
+ * This should be called by northbound 'create' callbacks in the NB_EV_APPLY
+ * phase only.
+ *
+ * dnode
+ * libyang data node - only its XPath is used.
+ *
+ * entry
+ * Arbitrary user-specified pointer.
+ */
+extern void nb_running_set_entry(const struct lyd_node *dnode, void *entry);
+
+/*
+ * Unset the user pointer associated to a configuration node.
+ *
+ * This should be called by northbound 'destroy' callbacks in the NB_EV_APPLY
+ * phase only.
+ *
+ * dnode
+ * libyang data node - only its XPath is used.
+ *
+ * Returns:
+ * The user pointer that was unset.
+ */
+extern void *nb_running_unset_entry(const struct lyd_node *dnode);
+
+/*
+ * Find the user pointer (if any) associated to a configuration node.
+ *
+ * The XPath associated to the configuration node can be provided directly or
+ * indirectly through a libyang data node.
+ *
+ * If an user point is not found, this function follows the parent nodes in the
+ * running configuration until an user pointer is found or until the root node
+ * is reached.
+ *
+ * dnode
+ * libyang data node - only its XPath is used (can be NULL if 'xpath' is
+ * provided).
+ *
+ * xpath
+ * XPath of the configuration node (can be NULL if 'dnode' is provided).
+ *
+ * abort_if_not_found
+ * When set to true, abort the program if no user pointer is found.
+ *
+ * As a rule of thumb, this parameter should be set to true in the following
+ * scenarios:
+ * - Calling this function from any northbound configuration callback during
+ * the NB_EV_APPLY phase.
+ * - Calling this function from a 'delete' northbound configuration callback
+ * during any phase.
+ *
+ * In both the above cases, the given configuration node should contain an
+ * user pointer except when there's a bug in the code, in which case it's
+ * better to abort the program right away and eliminate the need for
+ * unnecessary NULL checks.
+ *
+ * In all other cases, this parameter should be set to false and the caller
+ * should check if the function returned NULL or not.
+ *
+ * Returns:
+ * User pointer if found, NULL otherwise.
+ */
+extern void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
+ bool abort_if_not_found);
+
+/*
* Return a human-readable string representing a northbound event.
*
* event
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 4359c39caf..33b6c24782 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -374,7 +374,7 @@ static int frr_sr_state_data_iter_cb(const struct lys_node *snode,
/* Callback for state retrieval. */
static int frr_sr_state_cb(const char *xpath, sr_val_t **values,
size_t *values_cnt, uint64_t request_id,
- void *private_ctx)
+ const char *original_xpath, void *private_ctx)
{
struct list *elements;
struct yang_data *data;
diff --git a/lib/prefix.c b/lib/prefix.c
index 52bb266f11..6b91969218 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -1359,6 +1359,35 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
return str;
}
+void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
+ char *buf, int buf_size)
+{
+ int save_errno = errno;
+
+ if (addr.s_addr == INADDR_ANY)
+ strcpy(buf, "*");
+ else {
+ if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
+ if (onfail)
+ snprintf(buf, buf_size, "%s", onfail);
+ }
+ }
+
+ errno = save_errno;
+}
+
+const char *prefix_sg2str(const struct prefix_sg *sg, char *sg_str)
+{
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+
+ prefix_mcast_inet4_dump("<src?>", sg->src, src_str, sizeof(src_str));
+ prefix_mcast_inet4_dump("<grp?>", sg->grp, grp_str, sizeof(grp_str));
+ snprintf(sg_str, PREFIX_SG_STR_LEN, "(%s,%s)", src_str, grp_str);
+
+ return sg_str;
+}
+
struct prefix *prefix_new(void)
{
struct prefix *p;
diff --git a/lib/prefix.h b/lib/prefix.h
index a1c2086b8d..d3c387e102 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -321,6 +321,15 @@ union prefixconstptr {
/* Maximum string length of the result of prefix2str */
#define PREFIX_STRLEN 80
+/*
+ * Longest possible length of a (S,G) string is 36 bytes
+ * 123.123.123.123 = 15 * 2
+ * (,) = 3
+ * NULL Character at end = 1
+ * (123.123.123.123,123.123.123.123)
+ */
+#define PREFIX_SG_STR_LEN 34
+
/* Max bit/byte length of IPv4 address. */
#define IPV4_MAX_BYTELEN 4
#define IPV4_MAX_BITLEN 32
@@ -394,6 +403,9 @@ extern int str2prefix(const char *, struct prefix *);
#define PREFIX2STR_BUFFER PREFIX_STRLEN
+extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
+ char *buf, int buf_size);
+extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str);
extern const char *prefix2str(union prefixconstptr, char *, int);
extern int prefix_match(const struct prefix *, const struct prefix *);
extern int prefix_match_network_statement(const struct prefix *,
diff --git a/lib/privs.c b/lib/privs.c
index 59f24afe4a..a19707b1c9 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -25,10 +25,25 @@
#include "privs.h"
#include "memory.h"
#include "lib_errors.h"
+#include "lib/queue.h"
+DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information")
+
+/*
+ * Different capabilities/privileges apis have different characteristics: some
+ * are process-wide, and some are per-thread.
+ */
#ifdef HAVE_CAPABILITIES
+#ifdef HAVE_LCAPS
+static const bool privs_per_process; /* = false */
+#elif defined(HAVE_SOLARIS_CAPABILITIES)
+static const bool privs_per_process = true;
+#endif
+#else
+static const bool privs_per_process = true;
+#endif /* HAVE_CAPABILITIES */
-DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information")
+#ifdef HAVE_CAPABILITIES
/* sort out some generic internal types for:
*
@@ -698,25 +713,66 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups,
}
#endif /* HAVE_GETGROUPLIST */
+/*
+ * Helper function that locates a refcounting object to use: a process-wide
+ * object or a per-pthread object.
+ */
+static struct zebra_privs_refs_t *get_privs_refs(struct zebra_privs_t *privs)
+{
+ struct zebra_privs_refs_t *temp, *refs = NULL;
+ pthread_t tid;
+
+ if (privs_per_process)
+ refs = &(privs->process_refs);
+ else {
+ /* Locate - or create - the object for the current pthread. */
+ tid = pthread_self();
+
+ STAILQ_FOREACH(temp, &(privs->thread_refs), entry) {
+ if (pthread_equal(temp->tid, tid)) {
+ refs = temp;
+ break;
+ }
+ }
+
+ /* Need to create a new refcounting object. */
+ if (refs == NULL) {
+ refs = XCALLOC(MTYPE_PRIVS,
+ sizeof(struct zebra_privs_refs_t));
+ refs->tid = tid;
+ STAILQ_INSERT_TAIL(&(privs->thread_refs), refs, entry);
+ }
+ }
+
+ return refs;
+}
+
struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
const char *funcname)
{
int save_errno = errno;
+ struct zebra_privs_refs_t *refs;
if (!privs)
return NULL;
- /* If we're already elevated, just return */
+ /*
+ * Serialize 'raise' operations; particularly important for
+ * OSes where privs are process-wide.
+ */
pthread_mutex_lock(&(privs->mutex));
{
- if (++(privs->refcount) == 1) {
+ /* Locate ref-counting object to use */
+ refs = get_privs_refs(privs);
+
+ if (++(refs->refcount) == 1) {
errno = 0;
if (privs->change(ZPRIVS_RAISE)) {
zlog_err("%s: Failed to raise privileges (%s)",
funcname, safe_strerror(errno));
}
errno = save_errno;
- privs->raised_in_funcname = funcname;
+ refs->raised_in_funcname = funcname;
}
}
pthread_mutex_unlock(&(privs->mutex));
@@ -727,22 +783,27 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
void _zprivs_lower(struct zebra_privs_t **privs)
{
int save_errno = errno;
+ struct zebra_privs_refs_t *refs;
if (!*privs)
return;
- /* Don't lower privs if there's another caller */
+ /* Serialize 'lower privs' operation - particularly important
+ * when OS privs are process-wide.
+ */
pthread_mutex_lock(&(*privs)->mutex);
{
- if (--((*privs)->refcount) == 0) {
+ refs = get_privs_refs(*privs);
+
+ if (--(refs->refcount) == 0) {
errno = 0;
if ((*privs)->change(ZPRIVS_LOWER)) {
zlog_err("%s: Failed to lower privileges (%s)",
- (*privs)->raised_in_funcname,
+ refs->raised_in_funcname,
safe_strerror(errno));
}
errno = save_errno;
- (*privs)->raised_in_funcname = NULL;
+ refs->raised_in_funcname = NULL;
}
}
pthread_mutex_unlock(&(*privs)->mutex);
@@ -761,7 +822,9 @@ void zprivs_preinit(struct zebra_privs_t *zprivs)
}
pthread_mutex_init(&(zprivs->mutex), NULL);
- zprivs->refcount = 0;
+ zprivs->process_refs.refcount = 0;
+ zprivs->process_refs.raised_in_funcname = NULL;
+ STAILQ_INIT(&zprivs->thread_refs);
if (zprivs->vty_group) {
/* in a "NULL" setup, this is allowed to fail too, but still
@@ -919,6 +982,8 @@ void zprivs_init(struct zebra_privs_t *zprivs)
void zprivs_terminate(struct zebra_privs_t *zprivs)
{
+ struct zebra_privs_refs_t *refs;
+
if (!zprivs) {
fprintf(stderr, "%s: no privs struct given, terminating",
__func__);
@@ -941,6 +1006,11 @@ void zprivs_terminate(struct zebra_privs_t *zprivs)
}
#endif /* HAVE_LCAPS */
+ while ((refs = STAILQ_FIRST(&(zprivs->thread_refs))) != NULL) {
+ STAILQ_REMOVE_HEAD(&(zprivs->thread_refs), entry);
+ XFREE(MTYPE_PRIVS, refs);
+ }
+
zprivs->change = zprivs_change_null;
zprivs->current_state = zprivs_state_null;
zprivs_null_state = ZPRIVS_LOWERED;
diff --git a/lib/privs.h b/lib/privs.h
index 01ddba4622..2b0b44b3f2 100644
--- a/lib/privs.h
+++ b/lib/privs.h
@@ -24,6 +24,7 @@
#define _ZEBRA_PRIVS_H
#include <pthread.h>
+#include "lib/queue.h"
#ifdef __cplusplus
extern "C" {
@@ -56,6 +57,13 @@ typedef enum {
ZPRIVS_LOWER,
} zebra_privs_ops_t;
+struct zebra_privs_refs_t {
+ STAILQ_ENTRY(zebra_privs_refs_t) entry;
+ pthread_t tid;
+ uint32_t refcount;
+ const char *raised_in_funcname;
+};
+
struct zebra_privs_t {
zebra_capabilities_t *caps_p; /* caps required for operation */
zebra_capabilities_t *caps_i; /* caps to allow inheritance of */
@@ -63,11 +71,15 @@ struct zebra_privs_t {
int cap_num_i;
/* Mutex and counter used to avoid race conditions in multi-threaded
- * processes. The privs elevation is process-wide, so we need to
- * avoid changing the privilege status across threads.
+ * processes. If privs status is process-wide, we need to
+ * control changes to the privilege status among threads.
+ * If privs changes are per-thread, we need to be able to
+ * manage that too.
*/
pthread_mutex_t mutex;
- uint32_t refcount;
+ struct zebra_privs_refs_t process_refs;
+
+ STAILQ_HEAD(thread_refs_q, zebra_privs_refs_t) thread_refs;
const char *user; /* user and group to run as */
const char *group;
@@ -76,7 +88,6 @@ struct zebra_privs_t {
int (*change)(zebra_privs_ops_t); /* change privileges, 0 on success */
zebra_privs_current_t (*current_state)(
void); /* current privilege state */
- const char *raised_in_funcname;
};
struct zprivs_ids_t {
diff --git a/lib/vxlan.h b/lib/vxlan.h
index 2a8077f8cf..69d3939596 100644
--- a/lib/vxlan.h
+++ b/lib/vxlan.h
@@ -38,6 +38,7 @@ typedef uint32_t vni_t;
enum vxlan_flood_control {
VXLAN_FLOOD_HEAD_END_REPL = 0,
VXLAN_FLOOD_DISABLED,
+ VXLAN_FLOOD_PIM_SM,
};
#ifdef __cplusplus
diff --git a/lib/yang.c b/lib/yang.c
index 7982d14fdd..2a2c155dee 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -20,7 +20,6 @@
#include <zebra.h>
#include "log.h"
-#include "log_int.h"
#include "lib_errors.h"
#include "yang.h"
#include "yang_translator.h"
@@ -513,42 +512,6 @@ void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
lyd_change_leaf((struct lyd_node_leaf_list *)dnode, value);
}
-void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry)
-{
- assert(CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER));
- lyd_set_private(dnode, entry);
-}
-
-void *yang_dnode_get_entry(const struct lyd_node *dnode,
- bool abort_if_not_found)
-{
- const struct lyd_node *orig_dnode = dnode;
- char xpath[XPATH_MAXLEN];
-
- while (dnode) {
- switch (dnode->schema->nodetype) {
- case LYS_CONTAINER:
- case LYS_LIST:
- if (dnode->priv)
- return dnode->priv;
- break;
- default:
- break;
- }
-
- dnode = dnode->parent;
- }
-
- if (!abort_if_not_found)
- return NULL;
-
- yang_dnode_get_path(orig_dnode, xpath, sizeof(xpath));
- flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
- "%s: failed to find entry [xpath %s]", __func__, xpath);
- zlog_backtrace(LOG_ERR);
- abort();
-}
-
struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
{
struct lyd_node *dnode;
@@ -629,12 +592,6 @@ struct yang_data *yang_data_list_find(const struct list *list,
return NULL;
}
-static void *ly_dup_cb(const void *priv)
-{
- /* Make a shallow copy of the priv pointer. */
- return (void *)priv;
-}
-
/* Make libyang log its errors using FRR logging infrastructure. */
static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
{
@@ -724,7 +681,6 @@ CPP_NOTICE("lib/yang: deprecated libyang <0.16.74 extension loading in use!")
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
exit(1);
}
- ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
#ifndef LIBYANG_EXT_BUILTIN
/* Detect if the required libyang plugin(s) were loaded successfully. */
diff --git a/lib/yang.h b/lib/yang.h
index 15f0ec7ae6..6f8c84ab64 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -403,51 +403,6 @@ extern bool yang_dnode_is_default_recursive(const struct lyd_node *dnode);
extern void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value);
/*
- * Set the libyang private pointer to a user pointer. Can only be used on YANG
- * lists and containers.
- *
- * dnode
- * libyang data node to operate on.
- *
- * entry
- * Arbitrary user-specified pointer.
- */
-extern void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry);
-
-/*
- * Find the user pointer associated to the given libyang data node.
- *
- * The data node is traversed by following the parent pointers until an user
- * pointer is found or until the root node is reached.
- *
- * dnode
- * libyang data node to operate on.
- *
- * abort_if_not_found
- * When set to true, abort the program if no user pointer is found.
- *
- * As a rule of thumb, this parameter should be set to true in the following
- * scenarios:
- * - Calling this function from any northbound configuration callback during
- * the NB_EV_APPLY phase.
- * - Calling this function from a 'delete' northbound configuration callback
- * during any phase.
- *
- * In both the above cases, the libyang data node should contain an user
- * pointer except when there's a bug in the code, in which case it's better
- * to abort the program right away and eliminate the need for unnecessary
- * NULL checks.
- *
- * In all other cases, this parameter should be set to false and the caller
- * should check if the function returned NULL or not.
- *
- * Returns:
- * User pointer if found, NULL otherwise.
- */
-extern void *yang_dnode_get_entry(const struct lyd_node *dnode,
- bool abort_if_not_found);
-
-/*
* Create a new libyang data node.
*
* ly_ctx
diff --git a/lib/zclient.c b/lib/zclient.c
index e5cab9e0f2..4901c92743 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -2701,6 +2701,17 @@ static int zclient_read(struct thread *thread)
(*zclient->iptable_notify_owner)(command,
zclient, length,
vrf_id);
+ break;
+ case ZEBRA_VXLAN_SG_ADD:
+ if (zclient->vxlan_sg_add)
+ (*zclient->vxlan_sg_add)(command, zclient, length,
+ vrf_id);
+ break;
+ case ZEBRA_VXLAN_SG_DEL:
+ if (zclient->vxlan_sg_del)
+ (*zclient->vxlan_sg_del)(command, zclient, length,
+ vrf_id);
+ break;
default:
break;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 3a054e5e72..0926281f2e 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -164,6 +164,8 @@ typedef enum {
ZEBRA_IPTABLE_DELETE,
ZEBRA_IPTABLE_NOTIFY_OWNER,
ZEBRA_VXLAN_FLOOD_CONTROL,
+ ZEBRA_VXLAN_SG_ADD,
+ ZEBRA_VXLAN_SG_DEL,
} zebra_message_types_t;
struct redist_proto {
@@ -275,6 +277,10 @@ struct zclient {
struct zclient *zclient,
uint16_t length,
vrf_id_t vrf_id);
+ int (*vxlan_sg_add)(int command, struct zclient *client,
+ uint16_t length, vrf_id_t vrf_id);
+ int (*vxlan_sg_del)(int command, struct zclient *client,
+ uint16_t length, vrf_id_t vrf_id_t);
};
/* Zebra API message flag. */