diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/if.c | 29 | ||||
| -rw-r--r-- | lib/if.h | 20 | ||||
| -rw-r--r-- | lib/if_rmap.c | 1 | ||||
| -rw-r--r-- | lib/libfrr.c | 5 | ||||
| -rw-r--r-- | lib/linklist.c | 6 | ||||
| -rw-r--r-- | lib/linklist.h | 10 | ||||
| -rw-r--r-- | lib/log.c | 2 | ||||
| -rw-r--r-- | lib/log.h | 4 | ||||
| -rw-r--r-- | lib/log_int.h | 1 | ||||
| -rw-r--r-- | lib/nexthop.h | 4 | ||||
| -rw-r--r-- | lib/nexthop_group.c | 24 | ||||
| -rw-r--r-- | lib/nexthop_group.h | 5 | ||||
| -rw-r--r-- | lib/northbound.c | 202 | ||||
| -rw-r--r-- | lib/northbound.h | 69 | ||||
| -rw-r--r-- | lib/northbound_sysrepo.c | 2 | ||||
| -rw-r--r-- | lib/prefix.c | 29 | ||||
| -rw-r--r-- | lib/prefix.h | 12 | ||||
| -rw-r--r-- | lib/privs.c | 88 | ||||
| -rw-r--r-- | lib/privs.h | 19 | ||||
| -rw-r--r-- | lib/vxlan.h | 1 | ||||
| -rw-r--r-- | lib/yang.c | 44 | ||||
| -rw-r--r-- | lib/yang.h | 45 | ||||
| -rw-r--r-- | lib/zclient.c | 11 | ||||
| -rw-r--r-- | lib/zclient.h | 6 |
24 files changed, 442 insertions, 197 deletions
@@ -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; @@ -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 } @@ -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 @@ -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. */ |
