summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/command.h5
-rw-r--r--lib/filter.h10
-rw-r--r--lib/filter_cli.c97
-rw-r--r--lib/filter_nb.c96
-rw-r--r--lib/grammar_sandbox_main.c2
-rw-r--r--lib/hash.c15
-rw-r--r--lib/if.c2
-rw-r--r--lib/if.h2
-rw-r--r--lib/keychain.c2
-rw-r--r--lib/ldp_sync.c93
-rw-r--r--lib/ldp_sync.h91
-rw-r--r--lib/libfrr.c5
-rw-r--r--lib/libfrr.h1
-rw-r--r--lib/mpls.h3
-rw-r--r--lib/nexthop_group.c36
-rw-r--r--lib/nexthop_group.h3
-rw-r--r--lib/northbound.c50
-rw-r--r--lib/northbound.h23
-rw-r--r--lib/northbound_cli.c27
-rw-r--r--lib/northbound_confd.c7
-rw-r--r--lib/northbound_grpc.cpp24
-rw-r--r--lib/northbound_sysrepo.c379
-rw-r--r--lib/pbr.h5
-rw-r--r--lib/prefix.c13
-rw-r--r--lib/prefix.h1
-rw-r--r--lib/privs.c6
-rw-r--r--lib/stream.c48
-rw-r--r--lib/stream.h23
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/thread.c8
-rw-r--r--lib/vrf.c20
-rw-r--r--lib/yang.c3
-rw-r--r--lib/yang.h1
-rw-r--r--lib/zclient.c44
-rw-r--r--lib/zclient.h16
-rw-r--r--lib/zlog_targets.c5
36 files changed, 754 insertions, 414 deletions
diff --git a/lib/command.h b/lib/command.h
index e20bfe3318..d828989118 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -421,6 +421,11 @@ struct cmd_node {
#define CMD_VNI_RANGE "(1-16777215)"
#define CONF_BACKUP_EXT ".sav"
+#define MPLS_LDP_SYNC_STR "Enable MPLS LDP-SYNC\n"
+#define NO_MPLS_LDP_SYNC_STR "Disable MPLS LDP-SYNC\n"
+#define MPLS_LDP_SYNC_HOLDDOWN_STR \
+ "Time to wait for LDP-SYNC to occur before restoring if cost\n"
+#define NO_MPLS_LDP_SYNC_HOLDDOWN_STR "holddown timer disable\n"
/* Command warnings. */
#define NO_PASSWD_CMD_WARNING \
diff --git a/lib/filter.h b/lib/filter.h
index d41f3b65cd..623fb94527 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -32,6 +32,16 @@ extern "C" {
/* Maximum ACL name length */
#define ACL_NAMSIZ 128
+/** Cisco host wildcard mask. */
+#define CISCO_HOST_WILDCARD_MASK "0.0.0.0"
+/** Cisco host wildcard binary mask. */
+#define CISCO_BIN_HOST_WILDCARD_MASK INADDR_ANY
+
+/** Cisco any wildcard mask. */
+#define CISCO_ANY_WILDCARD_MASK "255.255.255.255"
+/** Cisco binary any wildcard mask. */
+#define CISCO_BIN_ANY_WILDCARD_MASK INADDR_NONE
+
/* Filter direction. */
#define FILTER_IN 0
#define FILTER_OUT 1
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
index 8c7a515dc5..09fc3289ce 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -37,14 +37,8 @@
#define ACCESS_LIST_STR "Access list entry\n"
#define ACCESS_LIST_LEG_STR "IP standard access list\n"
-#define ACCESS_LIST_LEG_EXT_STR "IP standard access list (expanded range)\n"
#define ACCESS_LIST_ELEG_STR "IP extended access list\n"
#define ACCESS_LIST_ELEG_EXT_STR "IP extended access list (expanded range)\n"
-#define ACCESS_LIST_XLEG_STR \
- ACCESS_LIST_LEG_STR \
- ACCESS_LIST_LEG_EXT_STR \
- ACCESS_LIST_ELEG_STR \
- ACCESS_LIST_ELEG_EXT_STR
#define ACCESS_LIST_ZEBRA_STR "Access list entry\n"
#define ACCESS_LIST_SEQ_STR \
"Sequence number of an entry\n" \
@@ -68,7 +62,6 @@ static int64_t acl_cisco_get_seq(struct access_list *acl, const char *action,
struct filter f, *fn;
memset(&f, 0, sizeof(f));
- memset(&fc, 0, sizeof(fc));
f.cisco = 1;
if (strcmp(action, "permit") == 0)
f.type = FILTER_PERMIT;
@@ -110,7 +103,8 @@ static int64_t acl_zebra_get_seq(struct access_list *acl, const char *action,
f.type = FILTER_DENY;
fz = &f.u.zfilter;
- fz->prefix = *p;
+ if (p->family)
+ prefix_copy(&fz->prefix, p);
fz->exact = exact;
fn = filter_lookup_zebra(acl, &f);
@@ -130,6 +124,7 @@ static void concat_addr_mask_v4(const char *addr, const char *mask, char *dst,
int plen;
assert(inet_pton(AF_INET, mask, &ia) == 1);
+ ia.s_addr = ~ia.s_addr;
plen = ip_masklen(ia);
snprintf(dst, dstlen, "%s/%d", addr, plen);
}
@@ -171,17 +166,15 @@ static long acl_get_seq(struct vty *vty, const char *xpath)
*/
DEFPY_YANG(
access_list_std, access_list_std_cmd,
- "access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
+ "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
ACCESS_LIST_STR
ACCESS_LIST_LEG_STR
- ACCESS_LIST_LEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"A single host address\n"
"Address to match\n"
"Address to match\n"
- "Wildcard bits\n"
- "Any source host\n")
+ "Wildcard bits\n")
{
int64_t sseq;
char ipmask[64];
@@ -193,8 +186,7 @@ DEFPY_YANG(
* none given (backward compatibility).
*/
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
if (seq_str == NULL) {
/* Use XPath to find the next sequence number. */
@@ -222,18 +214,16 @@ DEFPY_YANG(
DEFPY_YANG(
no_access_list_std, no_access_list_std_cmd,
- "no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
+ "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
NO_STR
ACCESS_LIST_STR
ACCESS_LIST_LEG_STR
- ACCESS_LIST_LEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"A single host address\n"
"Address to match\n"
"Address to match\n"
- "Wildcard bits\n"
- "Any source host\n")
+ "Wildcard bits\n")
{
struct access_list *acl;
struct lyd_node *dnode;
@@ -246,15 +236,14 @@ DEFPY_YANG(
snprintf(
xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
- number_str, seq_str);
+ name, seq_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
/* Otherwise, to keep compatibility, we need to figure it out. */
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
/* Access-list must exist before entries. */
if (yang_dnode_exists(running_config->dnode, xpath) == false)
@@ -263,13 +252,9 @@ DEFPY_YANG(
/* Use access-list data structure to fetch sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
- if (host_str != NULL)
- sseq = acl_cisco_get_seq(acl, action, host_str,
- mask_str ? mask_str : "0.0.0.0", NULL,
- NULL);
- else
- sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
- "255.255.255.255", NULL, NULL);
+ sseq = acl_cisco_get_seq(acl, action, host_str,
+ mask_str ? mask_str : CISCO_HOST_WILDCARD_MASK,
+ NULL, NULL);
if (sseq == -1)
return CMD_WARNING;
@@ -282,10 +267,9 @@ DEFPY_YANG(
DEFPY_YANG(
access_list_ext, access_list_ext_cmd,
- "access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
+ "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
ACCESS_LIST_STR
ACCESS_LIST_ELEG_STR
- ACCESS_LIST_ELEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"IPv4 address\n"
@@ -301,7 +285,7 @@ DEFPY_YANG(
"Any destination host\n")
{
int64_t sseq;
- char ipmask[64];
+ char ipmask[64], ipmask_dst[64];
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 128];
@@ -310,8 +294,7 @@ DEFPY_YANG(
* none given (backward compatibility).
*/
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
if (seq_str == NULL) {
/* Use XPath to find the next sequence number. */
@@ -337,12 +320,12 @@ DEFPY_YANG(
if (dst_str != NULL && dst_mask_str == NULL) {
nb_cli_enqueue_change(vty, "./destination-host", NB_OP_MODIFY,
- src_str);
+ dst_str);
} else if (dst_str != NULL && dst_mask_str != NULL) {
- concat_addr_mask_v4(dst_str, dst_mask_str, ipmask,
- sizeof(ipmask));
+ concat_addr_mask_v4(dst_str, dst_mask_str, ipmask_dst,
+ sizeof(ipmask_dst));
nb_cli_enqueue_change(vty, "./destination-network",
- NB_OP_MODIFY, ipmask);
+ NB_OP_MODIFY, ipmask_dst);
} else {
nb_cli_enqueue_change(vty, "./destination-any", NB_OP_CREATE,
NULL);
@@ -353,11 +336,10 @@ DEFPY_YANG(
DEFPY_YANG(
no_access_list_ext, no_access_list_ext_cmd,
- "no access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
+ "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
NO_STR
ACCESS_LIST_STR
ACCESS_LIST_ELEG_STR
- ACCESS_LIST_ELEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"Any Internet Protocol\n"
@@ -383,15 +365,14 @@ DEFPY_YANG(
snprintfrr(
xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
- number_str, seq_str);
+ name, seq_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
/* Otherwise, to keep compatibility, we need to figure it out. */
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
/* Access-list must exist before entries. */
if (yang_dnode_exists(running_config->dnode, xpath) == false)
@@ -404,24 +385,28 @@ DEFPY_YANG(
if (dst_str != NULL)
sseq = acl_cisco_get_seq(
acl, action, src_str,
- src_mask_str ? src_mask_str : "0.0.0.0",
+ src_mask_str ? src_mask_str
+ : CISCO_HOST_WILDCARD_MASK,
dst_str,
- dst_mask_str ? dst_mask_str : "0.0.0.0");
+ dst_mask_str ? dst_mask_str
+ : CISCO_HOST_WILDCARD_MASK);
else
- sseq = acl_cisco_get_seq(acl, action, src_str,
- src_mask_str ? src_mask_str
- : "0.0.0.0",
- "0.0.0.0", "255.255.255.255");
+ sseq = acl_cisco_get_seq(
+ acl, action, src_str,
+ src_mask_str ? src_mask_str
+ : CISCO_HOST_WILDCARD_MASK,
+ "0.0.0.0", CISCO_ANY_WILDCARD_MASK);
} else {
if (dst_str != NULL)
- sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
- "255.255.255.255", dst_str,
- dst_mask_str ? dst_mask_str
- : "0.0.0.0");
+ sseq = acl_cisco_get_seq(
+ acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK,
+ dst_str,
+ dst_mask_str ? dst_mask_str
+ : CISCO_HOST_WILDCARD_MASK);
else
- sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
- "255.255.255.255", "0.0.0.0",
- "255.255.255.255");
+ sseq = acl_cisco_get_seq(
+ acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK,
+ "0.0.0.0", CISCO_ANY_WILDCARD_MASK);
}
if (sseq == -1)
return CMD_WARNING;
@@ -522,7 +507,7 @@ DEFPY_YANG(
/* Use access-list data structure to fetch sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
- if (prefix == NULL) {
+ if (prefix_str == NULL) {
memset(&pany, 0, sizeof(pany));
pany.family = AF_INET;
sseq = acl_zebra_get_seq(acl, action, &pany, exact);
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index 91691d2f1d..8838a48abd 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -29,6 +29,7 @@
#include "lib/filter.h"
#include "lib/plist.h"
#include "lib/plist_int.h"
+#include "lib/routemap.h"
/* Helper function. */
static in_addr_t
@@ -40,6 +41,22 @@ ipv4_network_addr(in_addr_t hostaddr, int masklen)
return hostaddr & mask.s_addr;
}
+static void acl_notify_route_map(struct access_list *acl, int route_map_event)
+{
+ switch (route_map_event) {
+ case RMAP_EVENT_FILTER_ADDED:
+ if (acl->master->add_hook)
+ (*acl->master->add_hook)(acl);
+ break;
+ case RMAP_EVENT_FILTER_DELETED:
+ if (acl->master->delete_hook)
+ (*acl->master->delete_hook)(acl);
+ break;
+ }
+
+ route_map_notify_dependencies(acl->name, route_map_event);
+}
+
static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args)
{
int type = yang_dnode_get_enum(args->dnode, "../../type");
@@ -112,6 +129,19 @@ static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)
ple->le = 0;
}
+/**
+ * Unsets the cisco style rule for addresses so it becomes disabled (the
+ * equivalent of setting: `0.0.0.0/32`).
+ *
+ * \param addr address part.
+ * \param mask mask part.
+ */
+static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask)
+{
+ addr->s_addr = INADDR_ANY;
+ mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
+}
+
/*
* XPath: /frr-filter:lib/access-list
*/
@@ -255,6 +285,8 @@ lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
else
f->type = FILTER_DENY;
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -275,6 +307,8 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
fz = &f->u.zfilter;
yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -291,6 +325,8 @@ lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
memset(&fz->prefix, 0, sizeof(fz->prefix));
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
return NB_OK;
}
@@ -310,6 +346,8 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
fz = &f->u.zfilter;
fz->exact = yang_dnode_get_bool(args->dnode, NULL);
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -326,6 +364,8 @@ lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
fz->exact = 0;
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
return NB_OK;
}
@@ -345,7 +385,9 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
f->cisco = 1;
fc = &f->u.cfilter;
yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
- fc->addr_mask.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -361,8 +403,9 @@ lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -386,6 +429,9 @@ lib_access_list_entry_network_modify(struct nb_cb_modify_args *args)
yang_dnode_get_prefix(&p, args->dnode, NULL);
fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
masklen2ip(p.prefixlen, &fc->addr_mask);
+ fc->addr_mask.s_addr = ~fc->addr_mask.s_addr;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -401,8 +447,9 @@ lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args)
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -423,7 +470,9 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
f->cisco = 1;
fc = &f->u.cfilter;
fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -439,8 +488,9 @@ lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -461,7 +511,9 @@ static int lib_access_list_entry_destination_host_modify(
fc = &f->u.cfilter;
fc->extended = 1;
yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
- fc->mask_mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -478,8 +530,9 @@ static int lib_access_list_entry_destination_host_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -503,6 +556,9 @@ static int lib_access_list_entry_destination_network_modify(
yang_dnode_get_prefix(&p, args->dnode, NULL);
fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
masklen2ip(p.prefixlen, &fc->mask_mask);
+ fc->mask_mask.s_addr = ~fc->mask_mask.s_addr;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -519,8 +575,9 @@ static int lib_access_list_entry_destination_network_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -541,7 +598,9 @@ static int lib_access_list_entry_destination_any_create(
fc = &f->u.cfilter;
fc->extended = 1;
fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -558,8 +617,9 @@ static int lib_access_list_entry_destination_any_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -594,6 +654,8 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
break;
}
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -609,6 +671,8 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
fz->prefix.family = 0;
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
return NB_OK;
}
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index fbb97d2dd5..2066e4c96d 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -55,7 +55,7 @@ int main(int argc, char **argv)
vty_init(master, true);
lib_cmd_init();
yang_init(true);
- nb_init(master, NULL, 0);
+ nb_init(master, NULL, 0, false);
vty_stdio(vty_do_exit);
diff --git a/lib/hash.c b/lib/hash.c
index 7f8a237047..85982774ac 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -77,9 +77,20 @@ void *hash_alloc_intern(void *arg)
return arg;
}
+/*
+ * ssq = ssq + (new^2 - old^2)
+ * = ssq + ((new + old) * (new - old))
+ */
#define hash_update_ssq(hz, old, new) \
- atomic_fetch_add_explicit(&hz->stats.ssq, (new + old) * (new - old), \
- memory_order_relaxed);
+ do { \
+ int _adjust = (new + old) * (new - old); \
+ if (_adjust < 0) \
+ atomic_fetch_sub_explicit(&hz->stats.ssq, -_adjust, \
+ memory_order_relaxed); \
+ else \
+ atomic_fetch_add_explicit(&hz->stats.ssq, _adjust, \
+ memory_order_relaxed); \
+ } while (0)
/* Expand hash if the chain length exceeds the threshold. */
static void hash_expand(struct hash *hash)
diff --git a/lib/if.c b/lib/if.c
index d8392708e1..10db574dc4 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -188,7 +188,9 @@ void if_destroy_via_zapi(struct interface *ifp)
if (ifp_master.destroy_hook)
(*ifp_master.destroy_hook)(ifp);
+ ifp->oldifindex = ifp->ifindex;
if_set_index(ifp, IFINDEX_INTERNAL);
+
if (!ifp->configured)
if_delete(&ifp);
}
diff --git a/lib/if.h b/lib/if.h
index 1fb0757db2..a2a40d0957 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -224,6 +224,8 @@ struct interface {
not work as expected.
*/
ifindex_t ifindex;
+ ifindex_t oldifindex;
+
/*
* ifindex of parent interface, if any
*/
diff --git a/lib/keychain.c b/lib/keychain.c
index 251211734b..82fd6a65f2 100644
--- a/lib/keychain.c
+++ b/lib/keychain.c
@@ -1041,6 +1041,8 @@ static int keychain_config_write(struct vty *vty)
}
vty_out(vty, "\n");
}
+
+ vty_out(vty, " exit\n");
}
vty_out(vty, "!\n");
}
diff --git a/lib/ldp_sync.c b/lib/ldp_sync.c
new file mode 100644
index 0000000000..5dd045d88d
--- /dev/null
+++ b/lib/ldp_sync.c
@@ -0,0 +1,93 @@
+/*
+ * ldp_sync.c: LDP-SYNC handling routines
+ * Copyright (C) 2020 Volta 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 the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "log.h"
+#include "thread.h"
+#include "stream.h"
+#include "zclient.h"
+#include "table.h"
+#include "vty.h"
+#include "ldp_sync.h"
+
+/* Library code */
+DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info")
+
+/*
+ * ldp_sync_info_create - Allocate the LDP_SYNC information
+ */
+struct ldp_sync_info *ldp_sync_info_create(void)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ ldp_sync_info = XCALLOC(MTYPE_LDP_SYNC_INFO,
+ sizeof(struct ldp_sync_info));
+ assert(ldp_sync_info);
+
+ ldp_sync_info->flags = 0;
+ ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ ldp_sync_info->t_holddown = NULL;
+ return ldp_sync_info;
+}
+
+/*
+ * ldp_sync_info_free - Free the LDP_SYNC information.
+ */
+void ldp_sync_info_free(struct ldp_sync_info **ldp_sync_info)
+{
+ if (*ldp_sync_info)
+ XFREE(MTYPE_LDP_SYNC_INFO, *ldp_sync_info);
+}
+
+bool ldp_sync_if_is_enabled(struct ldp_sync_info *ldp_sync_info)
+{
+ /* return true if LDP-SYNC is configured on this interface */
+ if (ldp_sync_info &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+ ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP)
+ return true;
+
+ return false;
+}
+
+bool ldp_sync_if_down(struct ldp_sync_info *ldp_sync_info)
+{
+ /* Stop LDP-SYNC on this interface:
+ * if holddown timer is running stop it
+ * update state
+ */
+ if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) {
+ if (ldp_sync_info->t_holddown != NULL) {
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ }
+ if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_UP)
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/ldp_sync.h b/lib/ldp_sync.h
new file mode 100644
index 0000000000..daede566f0
--- /dev/null
+++ b/lib/ldp_sync.h
@@ -0,0 +1,91 @@
+/*
+ * Defines and structures common to LDP-Sync for OSPFv2 and OSPFv3 and ISIS
+ * Copyright (C) 2020 Volta 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 the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBLDPSYNC_H
+#define _LIBLDPSYNC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* LDP-IGP Sync values */
+#define LDP_SYNC_FLAG_ENABLE (1 << 0) /* LDP-SYNC enabled */
+#define LDP_SYNC_FLAG_HOLDDOWN (1 << 1) /* Holddown timer enabled */
+#define LDP_SYNC_FLAG_IF_CONFIG (1 << 2) /* LDP-SYNC enabled on interface */
+#define LDP_SYNC_FLAG_SET_METRIC (1 << 3) /* Metric has been set on ISIS intf */
+
+#define LDP_IGP_SYNC_DEFAULT 0
+#define LDP_IGP_SYNC_ENABLED 1
+
+#define LDP_IGP_SYNC_STATE_NOT_REQUIRED 0
+#define LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP 1
+#define LDP_IGP_SYNC_STATE_REQUIRED_UP 2
+
+#define LDP_IGP_SYNC_HOLDDOWN_DEFAULT 0
+
+#define LDP_IGP_SYNC_HELLO_TIMEOUT 1
+
+/* LDP-IGP Sync structures */
+struct ldp_sync_info_cmd {
+ uint16_t flags;
+ uint16_t holddown; /* timer value */
+ uint32_t sequence; /* hello sequence number */
+ struct thread *t_hello; /* hello timer for detecting LDP going down */
+};
+
+struct ldp_sync_info {
+ uint16_t flags; /* indicate if set on interface or globally */
+ uint8_t enabled; /* enabled */
+ uint8_t state; /* running state */
+ uint16_t holddown; /* timer value */
+ struct thread *t_holddown; /* holddown timer*/
+ uint32_t metric[2]; /* isis interface metric */
+};
+
+/* Prototypes. */
+extern struct ldp_sync_info *ldp_sync_info_create(void);
+extern bool ldp_sync_if_is_enabled(struct ldp_sync_info *ldp_sync_info);
+extern bool ldp_sync_if_down(struct ldp_sync_info *ldp_sync_info);
+extern void ldp_sync_info_free(struct ldp_sync_info **ldp_sync_info);
+
+struct ldp_igp_sync_announce {
+ int proto;
+};
+
+struct ldp_igp_sync_if_state {
+ ifindex_t ifindex;
+ bool sync_start;
+};
+
+struct ldp_igp_sync_if_state_req {
+ int proto;
+ ifindex_t ifindex;
+ char name[INTERFACE_NAMSIZ];
+};
+
+struct ldp_igp_sync_hello {
+ int proto;
+ unsigned int sequence;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBLDPSYNC_H */
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 2597eb61e2..800596c563 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -45,6 +45,7 @@
#include "defaults.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
+DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
DEFINE_KOOH(frr_fini, (), ())
@@ -719,7 +720,7 @@ struct thread_master *frr_init(void)
debug_init_cli();
- nb_init(master, di->yang_modules, di->n_yang_modules);
+ nb_init(master, di->yang_modules, di->n_yang_modules, true);
if (nb_db_init() != NB_OK)
flog_warn(EC_LIB_NB_DATABASE,
"%s: failed to initialize northbound database",
@@ -913,6 +914,8 @@ static int frr_config_read_in(struct thread *t)
__func__, nb_err_name(ret), errmsg);
}
+ hook_call(frr_very_late_init, master);
+
return 0;
}
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 9d91ea9154..ab72299206 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -136,6 +136,7 @@ extern const char *frr_get_progname(void);
extern enum frr_cli_mode frr_get_cli_mode(void);
DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
+DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
extern void frr_config_fork(void);
extern void frr_run(struct thread_master *master);
diff --git a/lib/mpls.h b/lib/mpls.h
index 8922a36664..74bd7aae3e 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -72,8 +72,7 @@ extern "C" {
/* Maximum # labels that can be pushed. */
#define MPLS_MAX_LABELS 16
-#define IS_MPLS_RESERVED_LABEL(label) \
- (label >= MPLS_LABEL_RESERVED_MIN && label <= MPLS_LABEL_RESERVED_MAX)
+#define IS_MPLS_RESERVED_LABEL(label) (label <= MPLS_LABEL_RESERVED_MAX)
#define IS_MPLS_UNRESERVED_LABEL(label) \
(label >= MPLS_LABEL_UNRESERVED_MIN \
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 97815ceeb9..687cac4062 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -940,6 +940,12 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nhg_hooks.add_nexthop(nhgc, nh);
}
+ if (intf) {
+ struct interface *ifp = if_lookup_by_name_all_vrf(intf);
+
+ if (ifp)
+ ifp->configured = true;
+ }
return CMD_SUCCESS;
}
@@ -952,24 +958,29 @@ static struct cmd_node nexthop_group_node = {
.config_write = nexthop_group_write,
};
-void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
+void nexthop_group_write_nexthop_simple(struct vty *vty,
+ const struct nexthop *nh,
+ char *altifname)
{
char buf[100];
- struct vrf *vrf;
- int i;
+ char *ifname;
vty_out(vty, "nexthop ");
+ if (altifname)
+ ifname = altifname;
+ else
+ ifname = (char *)ifindex2ifname(nh->ifindex, nh->vrf_id);
+
switch (nh->type) {
case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, "%s", ifindex2ifname(nh->ifindex, nh->vrf_id));
+ vty_out(vty, "%s", ifname);
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));
+ vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4), ifname);
break;
case NEXTHOP_TYPE_IPV6:
vty_out(vty, "%s",
@@ -978,15 +989,23 @@ void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
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));
+ ifname);
break;
case NEXTHOP_TYPE_BLACKHOLE:
break;
}
+}
+
+void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
+{
+ struct vrf *vrf;
+ int i;
+
+ nexthop_group_write_nexthop_simple(vty, nh, NULL);
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, " nexthop-vrf %s", VRF_LOGNAME(vrf));
}
if (nh->nh_label && nh->nh_label->num_labels > 0) {
@@ -1229,6 +1248,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
if (ifp->ifindex != nhop.ifindex)
continue;
+ ifp->configured = true;
nh = nexthop_new();
memcpy(nh, &nhop, sizeof(nhop));
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 0b5ac91bb2..5f7bde0def 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -135,6 +135,9 @@ extern bool nexthop_group_equal(const struct nexthop_group *nhg1,
extern struct nexthop_group_cmd *nhgc_find(const char *name);
+extern void nexthop_group_write_nexthop_simple(struct vty *vty,
+ const struct nexthop *nh,
+ char *altifname);
extern void nexthop_group_write_nexthop(struct vty *vty,
const struct nexthop *nh);
diff --git a/lib/northbound.c b/lib/northbound.c
index 11007e4309..895647cfb7 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -57,6 +57,8 @@ static struct {
const void *owner_user;
} running_config_mgmt_lock;
+/* Knob to record config transaction */
+static bool nb_db_enabled;
/*
* Global lock used to prevent multiple configuration transactions from
* happening concurrently.
@@ -381,6 +383,10 @@ static void nb_config_diff_add_change(struct nb_config_cbs *changes,
{
struct nb_config_change *change;
+ /* Ignore unimplemented nodes. */
+ if (!dnode->schema->priv)
+ return;
+
change = XCALLOC(MTYPE_TMP, sizeof(*change));
change->cb.operation = operation;
change->cb.seq = *seq;
@@ -414,6 +420,10 @@ static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
enum nb_operation operation;
struct lyd_node *child;
+ /* Ignore unimplemented nodes. */
+ if (!dnode->schema->priv)
+ return;
+
switch (dnode->schema->nodetype) {
case LYS_LEAF:
case LYS_LEAFLIST:
@@ -448,6 +458,10 @@ static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq,
struct nb_config_cbs *changes)
{
+ /* Ignore unimplemented nodes. */
+ if (!dnode->schema->priv)
+ return;
+
if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode);
else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
@@ -616,7 +630,7 @@ static int nb_candidate_validate_code(struct nb_context *context,
struct nb_node *nb_node;
nb_node = child->schema->priv;
- if (!nb_node->cbs.pre_validate)
+ if (!nb_node || !nb_node->cbs.pre_validate)
goto next;
ret = nb_callback_pre_validate(context, nb_node, child,
@@ -680,8 +694,12 @@ int nb_candidate_commit_prepare(struct nb_context *context,
RB_INIT(nb_config_cbs, &changes);
nb_config_diff(running_config, candidate, &changes);
- if (RB_EMPTY(nb_config_cbs, &changes))
+ if (RB_EMPTY(nb_config_cbs, &changes)) {
+ snprintf(
+ errmsg, errmsg_len,
+ "No changes to apply were found during preparation phase");
return NB_ERR_NO_CHANGES;
+ }
if (nb_candidate_validate_code(context, candidate, &changes, errmsg,
errmsg_len)
@@ -707,30 +725,28 @@ int nb_candidate_commit_prepare(struct nb_context *context,
errmsg_len);
}
-void nb_candidate_commit_abort(struct nb_transaction *transaction)
+void nb_candidate_commit_abort(struct nb_transaction *transaction, char *errmsg,
+ size_t errmsg_len)
{
- char errmsg[BUFSIZ] = {0};
-
(void)nb_transaction_process(NB_EV_ABORT, transaction, errmsg,
- sizeof(errmsg));
+ errmsg_len);
nb_transaction_free(transaction);
}
void nb_candidate_commit_apply(struct nb_transaction *transaction,
- bool save_transaction, uint32_t *transaction_id)
+ bool save_transaction, uint32_t *transaction_id,
+ char *errmsg, size_t errmsg_len)
{
- char errmsg[BUFSIZ] = {0};
-
(void)nb_transaction_process(NB_EV_APPLY, transaction, errmsg,
- sizeof(errmsg));
- nb_transaction_apply_finish(transaction, errmsg, sizeof(errmsg));
+ errmsg_len);
+ nb_transaction_apply_finish(transaction, errmsg, errmsg_len);
/* Replace running by candidate. */
transaction->config->version++;
nb_config_replace(running_config, transaction->config, true);
/* Record transaction. */
- if (save_transaction
+ if (save_transaction && nb_db_enabled
&& nb_db_transaction_save(transaction, transaction_id) != NB_OK)
flog_warn(EC_LIB_NB_TRANSACTION_RECORD_FAILED,
"%s: failed to record transaction", __func__);
@@ -754,9 +770,9 @@ int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate,
*/
if (ret == NB_OK)
nb_candidate_commit_apply(transaction, save_transaction,
- transaction_id);
+ transaction_id, errmsg, errmsg_len);
else if (transaction != NULL)
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, errmsg_len);
return ret;
}
@@ -1381,7 +1397,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction,
struct nb_node *nb_node;
nb_node = dnode->schema->priv;
- if (!nb_node->cbs.apply_finish)
+ if (!nb_node || !nb_node->cbs.apply_finish)
goto next;
/*
@@ -2214,7 +2230,7 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module)
void nb_init(struct thread_master *tm,
const struct frr_yang_module_info *const modules[],
- size_t nmodules)
+ size_t nmodules, bool db_enabled)
{
unsigned int errors = 0;
@@ -2239,6 +2255,8 @@ void nb_init(struct thread_master *tm,
exit(1);
}
+ nb_db_enabled = db_enabled;
+
/* Create an empty running configuration. */
running_config = nb_config_new(NULL);
running_config_entries = hash_create(running_config_entry_key_make,
diff --git a/lib/northbound.h b/lib/northbound.h
index d5028ea7d2..7b481273cb 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -910,8 +910,15 @@ extern int nb_candidate_commit_prepare(struct nb_context *context,
*
* transaction
* Candidate configuration to abort. It's consumed by this function.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
*/
-extern void nb_candidate_commit_abort(struct nb_transaction *transaction);
+extern void nb_candidate_commit_abort(struct nb_transaction *transaction,
+ char *errmsg, size_t errmsg_len);
/*
* Commit a previously created configuration transaction.
@@ -925,10 +932,17 @@ extern void nb_candidate_commit_abort(struct nb_transaction *transaction);
*
* transaction_id
* Optional output parameter providing the ID of the committed transaction.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
*/
extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
bool save_transaction,
- uint32_t *transaction_id);
+ uint32_t *transaction_id, char *errmsg,
+ size_t errmsg_len);
/*
* Create a new transaction to commit a candidate configuration. This is a
@@ -1225,10 +1239,13 @@ extern const char *nb_client_name(enum nb_client client);
*
* nmodules
* Size of the modules array.
+ *
+ * db_enabled
+ * Set this to record the transactions in the transaction log.
*/
extern void nb_init(struct thread_master *tm,
const struct frr_yang_module_info *const modules[],
- size_t nmodules);
+ size_t nmodules, bool db_enabled);
/*
* Finish the northbound layer gracefully. Should be called only when the daemon
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 534b5128ee..6ce520149a 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -63,7 +63,15 @@ static int nb_cli_classic_commit(struct vty *vty)
context.user = vty;
ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL,
NULL, errmsg, sizeof(errmsg));
- if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
+ switch (ret) {
+ case NB_OK:
+ /* Successful commit. Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
+ break;
+ case NB_ERR_NO_CHANGES:
+ break;
+ default:
vty_out(vty, "%% Configuration failed.\n\n");
vty_show_nb_errors(vty, ret, errmsg);
if (vty->t_pending_commit)
@@ -318,11 +326,14 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty)
&context, vty->confirmed_commit_rollback, true,
"Rollback to previous configuration - confirmed commit has timed out",
&transaction_id, errmsg, sizeof(errmsg));
- if (ret == NB_OK)
+ if (ret == NB_OK) {
vty_out(vty,
"Rollback performed successfully (Transaction ID #%u).\n",
transaction_id);
- else {
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
+ } else {
vty_out(vty,
"Failed to rollback to previous configuration.\n\n");
vty_show_nb_errors(vty, ret, errmsg);
@@ -407,6 +418,9 @@ static int nb_cli_commit(struct vty *vty, bool force,
vty_out(vty,
"%% Configuration committed successfully (Transaction ID #%u).\n\n",
transaction_id);
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
return CMD_SUCCESS;
case NB_ERR_NO_CHANGES:
vty_out(vty, "%% No configuration changes to commit.\n\n");
@@ -559,7 +573,7 @@ void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
struct nb_node *nb_node;
nb_node = child->schema->priv;
- if (!nb_node->cbs.cli_show)
+ if (!nb_node || !nb_node->cbs.cli_show)
goto next;
/* Skip default values. */
@@ -577,7 +591,7 @@ void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
parent = ly_iter_next_up(child);
if (parent != NULL) {
nb_node = parent->schema->priv;
- if (nb_node->cbs.cli_show_end)
+ if (nb_node && nb_node->cbs.cli_show_end)
(*nb_node->cbs.cli_show_end)(vty, parent);
}
@@ -1666,6 +1680,9 @@ static int nb_cli_rollback_configuration(struct vty *vty,
case NB_OK:
vty_out(vty,
"%% Configuration was successfully rolled back.\n\n");
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
return CMD_SUCCESS;
case NB_ERR_NO_CHANGES:
vty_out(vty,
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index a3aaf02f08..1f480f3d02 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -375,8 +375,10 @@ static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen)
/* Apply the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_apply(transaction, true, NULL);
+ nb_candidate_commit_apply(transaction, true, NULL, errmsg,
+ sizeof(errmsg));
nb_config_free(candidate);
}
@@ -400,8 +402,9 @@ static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen)
/* Abort the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg));
nb_config_free(candidate);
}
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 83d7e0ce95..f35b4bb31b 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -677,11 +677,13 @@ class NorthboundImpl
switch (phase) {
case frr::CommitRequest::VALIDATE:
+ zlog_debug("`-> Performing VALIDATE");
ret = nb_candidate_validate(
&context, candidate->config, errmsg,
sizeof(errmsg));
break;
case frr::CommitRequest::PREPARE:
+ zlog_debug("`-> Performing PREPARE");
ret = nb_candidate_commit_prepare(
&context, candidate->config,
comment.c_str(),
@@ -689,15 +691,20 @@ class NorthboundImpl
sizeof(errmsg));
break;
case frr::CommitRequest::ABORT:
+ zlog_debug("`-> Performing ABORT");
nb_candidate_commit_abort(
- candidate->transaction);
+ candidate->transaction, errmsg,
+ sizeof(errmsg));
break;
case frr::CommitRequest::APPLY:
+ zlog_debug("`-> Performing ABORT");
nb_candidate_commit_apply(
candidate->transaction, true,
- &transaction_id);
+ &transaction_id, errmsg,
+ sizeof(errmsg));
break;
case frr::CommitRequest::ALL:
+ zlog_debug("`-> Performing ALL");
ret = nb_candidate_commit(
&context, candidate->config, true,
comment.c_str(), &transaction_id,
@@ -735,12 +742,20 @@ class NorthboundImpl
grpc::StatusCode::INTERNAL, errmsg);
break;
}
+
+ if (nb_dbg_client_grpc)
+ zlog_debug("`-> Result: %s (message: '%s')",
+ nb_err_name((enum nb_error)ret),
+ errmsg);
+
if (ret == NB_OK) {
// Response: uint32 transaction_id = 1;
if (transaction_id)
tag->response.set_transaction_id(
transaction_id);
}
+ if (strlen(errmsg) > 0)
+ tag->response.set_error_message(errmsg);
tag->responder.Finish(tag->response, status, tag);
tag->state = FINISH;
@@ -1281,10 +1296,13 @@ class NorthboundImpl
void delete_candidate(struct candidate *candidate)
{
+ char errmsg[BUFSIZ] = {0};
+
_candidates.erase(candidate->id);
nb_config_free(candidate->config);
if (candidate->transaction)
- nb_candidate_commit_abort(candidate->transaction);
+ nb_candidate_commit_abort(candidate->transaction,
+ errmsg, sizeof(errmsg));
}
struct candidate *get_candidate(uint32_t candidate_id)
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 500203173c..b5ef040a3f 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -37,13 +37,11 @@ DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module")
static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"};
static struct thread_master *master;
-static struct list *sysrepo_threads;
static sr_session_ctx_t *session;
static sr_conn_ctx_t *connection;
static struct nb_transaction *transaction;
static int frr_sr_read_cb(struct thread *thread);
-static int frr_sr_write_cb(struct thread *thread);
static int frr_sr_finish(void);
/* Convert FRR YANG data value to sysrepo YANG data value. */
@@ -176,6 +174,9 @@ static int frr_sr_process_change(struct nb_config *candidate,
xpath = sr_data->xpath;
+ DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: processing change [xpath %s]",
+ xpath);
+
/* Non-presence container - nothing to do. */
if (sr_data->type == SR_CONTAINER_T)
return NB_OK;
@@ -225,7 +226,7 @@ static int frr_sr_process_change(struct nb_config *candidate,
ret = nb_candidate_edit(candidate, nb_node, nb_op, xpath, NULL, data);
yang_data_free(data);
- if (ret != NB_OK) {
+ if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
flog_warn(
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
@@ -236,25 +237,22 @@ static int frr_sr_process_change(struct nb_config *candidate,
return NB_OK;
}
-static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
- const char *module_name,
- bool startup_config)
+static int frr_sr_config_change_cb_prepare(sr_session_ctx_t *session,
+ const char *module_name)
{
sr_change_iter_t *it;
int ret;
sr_change_oper_t sr_op;
sr_val_t *sr_old_val, *sr_new_val;
- char xpath[XPATH_MAXLEN];
struct nb_context context = {};
struct nb_config *candidate;
char errmsg[BUFSIZ] = {0};
- snprintf(xpath, sizeof(xpath), "/%s:*", module_name);
- ret = sr_get_changes_iter(session, xpath, &it);
+ ret = sr_get_changes_iter(session, "//*", &it);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO,
- "%s: sr_get_changes_iter() failed for xpath %s",
- __func__, xpath);
+ "%s: sr_get_changes_iter() failed for \"%s\"",
+ __func__, module_name);
return ret;
}
@@ -279,40 +277,26 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
transaction = NULL;
context.client = NB_CLIENT_SYSREPO;
- if (startup_config) {
- /*
- * sysrepod sends the entire startup configuration using a
- * single event (SR_EV_ENABLED). This means we need to perform
- * the full two-phase commit protocol in one go here.
- */
- ret = nb_candidate_commit(&context, candidate, true, NULL, NULL,
- errmsg, sizeof(errmsg));
- if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
- flog_warn(
- EC_LIB_LIBSYSREPO,
- "%s: failed to apply startup configuration: %s (%s)",
- __func__, nb_err_name(ret), errmsg);
- } else {
- /*
- * Validate the configuration changes and allocate all resources
- * required to apply them.
- */
- ret = nb_candidate_commit_prepare(&context, candidate, NULL,
- &transaction, errmsg,
- sizeof(errmsg));
- if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
- flog_warn(
- EC_LIB_LIBSYSREPO,
- "%s: failed to prepare configuration transaction: %s (%s)",
- __func__, nb_err_name(ret), errmsg);
- }
+ /*
+ * Validate the configuration changes and allocate all resources
+ * required to apply them.
+ */
+ ret = nb_candidate_commit_prepare(&context, candidate, NULL,
+ &transaction, errmsg, sizeof(errmsg));
+ if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
+ flog_warn(
+ EC_LIB_LIBSYSREPO,
+ "%s: failed to prepare configuration transaction: %s (%s)",
+ __func__, nb_err_name(ret), errmsg);
+
+ if (!transaction)
+ nb_config_free(candidate);
/* Map northbound return code to sysrepo return code. */
switch (ret) {
case NB_OK:
return SR_ERR_OK;
case NB_ERR_NO_CHANGES:
- nb_config_free(candidate);
return SR_ERR_OK;
case NB_ERR_LOCKED:
return SR_ERR_LOCKED;
@@ -329,8 +313,10 @@ static int frr_sr_config_change_cb_apply(sr_session_ctx_t *session,
/* Apply the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_apply(transaction, true, NULL);
+ nb_candidate_commit_apply(transaction, true, NULL, errmsg,
+ sizeof(errmsg));
nb_config_free(candidate);
}
@@ -343,8 +329,9 @@ static int frr_sr_config_change_cb_abort(sr_session_ctx_t *session,
/* Abort the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg));
nb_config_free(candidate);
}
@@ -353,22 +340,20 @@ static int frr_sr_config_change_cb_abort(sr_session_ctx_t *session,
/* Callback for changes in the running configuration. */
static int frr_sr_config_change_cb(sr_session_ctx_t *session,
- const char *module_name,
- sr_notif_event_t sr_ev, void *private_ctx)
+ const char *module_name, const char *xpath,
+ sr_event_t sr_ev, uint32_t request_id,
+ void *private_data)
{
switch (sr_ev) {
case SR_EV_ENABLED:
- return frr_sr_config_change_cb_verify(session, module_name,
- true);
- case SR_EV_VERIFY:
- return frr_sr_config_change_cb_verify(session, module_name,
- false);
- case SR_EV_APPLY:
+ case SR_EV_CHANGE:
+ return frr_sr_config_change_cb_prepare(session, module_name);
+ case SR_EV_DONE:
return frr_sr_config_change_cb_apply(session, module_name);
case SR_EV_ABORT:
return frr_sr_config_change_cb_abort(session, module_name);
default:
- flog_err(EC_LIB_LIBSYSREPO, "%s: unknown sysrepo event: %u",
+ flog_err(EC_LIB_LIBSYSREPO, "%s: unexpected sysrepo event: %u",
__func__, sr_ev);
return SR_ERR_INTERNAL;
}
@@ -378,70 +363,49 @@ static int frr_sr_state_data_iter_cb(const struct lys_node *snode,
struct yang_translator *translator,
struct yang_data *data, void *arg)
{
- struct list *elements = arg;
-
- listnode_add(elements, data);
+ struct lyd_node *dnode = arg;
+
+ ly_errno = 0;
+ dnode = lyd_new_path(dnode, ly_native_ctx, data->xpath, data->value, 0,
+ LYD_PATH_OPT_UPDATE);
+ if (!dnode && ly_errno) {
+ flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed",
+ __func__);
+ yang_data_free(data);
+ return NB_ERR;
+ }
+ yang_data_free(data);
return NB_OK;
}
/* 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,
- const char *original_xpath, void *private_ctx)
+static int frr_sr_state_cb(sr_session_ctx_t *session, const char *module_name,
+ const char *xpath, const char *request_xpath,
+ uint32_t request_id, struct lyd_node **parent,
+ void *private_ctx)
{
- struct list *elements;
- struct yang_data *data;
- struct listnode *node;
- sr_val_t *v;
- int ret, count, i = 0;
+ struct lyd_node *dnode;
- elements = yang_data_list_new();
- if (nb_oper_data_iterate(xpath, NULL, NB_OPER_DATA_ITER_NORECURSE,
- frr_sr_state_data_iter_cb, elements)
+ dnode = *parent;
+ if (nb_oper_data_iterate(request_xpath, NULL, 0,
+ frr_sr_state_data_iter_cb, dnode)
!= NB_OK) {
flog_warn(EC_LIB_NB_OPERATIONAL_DATA,
"%s: failed to obtain operational data [xpath %s]",
__func__, xpath);
- goto exit;
- }
-
- if (list_isempty(elements))
- goto exit;
-
- count = listcount(elements);
- ret = sr_new_values(count, &v);
- if (ret != SR_ERR_OK) {
- flog_err(EC_LIB_LIBSYSREPO, "%s: sr_new_values(): %s", __func__,
- sr_strerror(ret));
- goto exit;
- }
-
- for (ALL_LIST_ELEMENTS_RO(elements, node, data)) {
- if (yang_data_frr2sr(data, &v[i++]) != 0) {
- flog_err(EC_LIB_SYSREPO_DATA_CONVERT,
- "%s: failed to convert data to sysrepo format",
- __func__);
- }
+ return SR_ERR_INTERNAL;
}
- *values = v;
- *values_cnt = count;
-
- list_delete(&elements);
-
- return SR_ERR_OK;
-
-exit:
- list_delete(&elements);
- *values = NULL;
- *values_cnt = 0;
+ *parent = dnode;
return SR_ERR_OK;
}
-static int frr_sr_config_rpc_cb(const char *xpath, const sr_val_t *sr_input,
- const size_t input_cnt, sr_val_t **sr_output,
+static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, const char *xpath,
+ const sr_val_t *sr_input,
+ const size_t input_cnt, sr_event_t sr_ev,
+ uint32_t request_id, sr_val_t **sr_output,
size_t *sr_output_cnt, void *private_ctx)
{
struct nb_node *nb_node;
@@ -548,8 +512,7 @@ static int frr_sr_notification_send(const char *xpath, struct list *arguments)
}
}
- ret = sr_event_notif_send(session, xpath, values, values_cnt,
- SR_EV_NOTIF_DEFAULT);
+ ret = sr_event_notif_send(session, xpath, values, values_cnt);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO,
"%s: sr_event_notif_send() failed for xpath %s",
@@ -560,102 +523,13 @@ static int frr_sr_notification_send(const char *xpath, struct list *arguments)
return NB_OK;
}
-/* Code to integrate the sysrepo client into FRR main event loop. */
-struct sysrepo_thread {
- struct thread *thread;
- sr_fd_event_t event;
- int fd;
-};
-
-static struct sysrepo_thread *frr_sr_fd_lookup(sr_fd_event_t event, int fd)
-{
- struct sysrepo_thread *sr_thread;
- struct listnode *node;
-
- for (ALL_LIST_ELEMENTS_RO(sysrepo_threads, node, sr_thread)) {
- if (sr_thread->event == event && sr_thread->fd == fd)
- return sr_thread;
- }
-
- return NULL;
-}
-
-static void frr_sr_fd_add(int event, int fd)
-{
- struct sysrepo_thread *sr_thread;
-
- if (frr_sr_fd_lookup(event, fd) != NULL)
- return;
-
- sr_thread = XCALLOC(MTYPE_SYSREPO, sizeof(*sr_thread));
- sr_thread->event = event;
- sr_thread->fd = fd;
- listnode_add(sysrepo_threads, sr_thread);
-
- switch (event) {
- case SR_FD_INPUT_READY:
- thread_add_read(master, frr_sr_read_cb, NULL, fd,
- &sr_thread->thread);
- break;
- case SR_FD_OUTPUT_READY:
- thread_add_write(master, frr_sr_write_cb, NULL, fd,
- &sr_thread->thread);
- break;
- default:
- return;
- }
-}
-
-static void frr_sr_fd_free(struct sysrepo_thread *sr_thread)
-{
- THREAD_OFF(sr_thread->thread);
- XFREE(MTYPE_SYSREPO, sr_thread);
-}
-
-static void frr_sr_fd_del(int event, int fd)
-{
- struct sysrepo_thread *sr_thread;
-
- sr_thread = frr_sr_fd_lookup(event, fd);
- if (!sr_thread)
- return;
-
- listnode_delete(sysrepo_threads, sr_thread);
- frr_sr_fd_free(sr_thread);
-}
-
-static void frr_sr_fd_update(sr_fd_change_t *fd_change_set,
- size_t fd_change_set_cnt)
-{
- for (size_t i = 0; i < fd_change_set_cnt; i++) {
- int fd = fd_change_set[i].fd;
- int event = fd_change_set[i].events;
-
- if (event != SR_FD_INPUT_READY && event != SR_FD_OUTPUT_READY)
- continue;
-
- switch (fd_change_set[i].action) {
- case SR_FD_START_WATCHING:
- frr_sr_fd_add(event, fd);
- break;
- case SR_FD_STOP_WATCHING:
- frr_sr_fd_del(event, fd);
- break;
- default:
- break;
- }
- }
-}
-
static int frr_sr_read_cb(struct thread *thread)
{
+ sr_subscription_ctx_t *sr_subscription = THREAD_ARG(thread);
int fd = THREAD_FD(thread);
- sr_fd_change_t *fd_change_set = NULL;
- size_t fd_change_set_cnt = 0;
int ret;
- ret = sr_fd_event_process(fd, SR_FD_INPUT_READY, &fd_change_set,
- &fd_change_set_cnt);
+ ret = sr_process_events(sr_subscription, session, NULL);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO, "%s: sr_fd_event_process(): %s",
__func__, sr_strerror(ret));
@@ -663,31 +537,7 @@ static int frr_sr_read_cb(struct thread *thread)
}
thread = NULL;
- thread_add_read(master, frr_sr_read_cb, NULL, fd, &thread);
-
- frr_sr_fd_update(fd_change_set, fd_change_set_cnt);
- free(fd_change_set);
-
- return 0;
-}
-
-static int frr_sr_write_cb(struct thread *thread)
-{
- int fd = THREAD_FD(thread);
- sr_fd_change_t *fd_change_set = NULL;
- size_t fd_change_set_cnt = 0;
- int ret;
-
- ret = sr_fd_event_process(fd, SR_FD_OUTPUT_READY, &fd_change_set,
- &fd_change_set_cnt);
- if (ret != SR_ERR_OK) {
- flog_err(EC_LIB_LIBSYSREPO, "%s: sr_fd_event_process(): %s",
- __func__, sr_strerror(ret));
- return -1;
- }
-
- frr_sr_fd_update(fd_change_set, fd_change_set_cnt);
- free(fd_change_set);
+ thread_add_read(master, frr_sr_read_cb, sr_subscription, fd, &thread);
return 0;
}
@@ -696,9 +546,13 @@ static void frr_sr_subscribe_config(struct yang_module *module)
{
int ret;
+ DEBUGD(&nb_dbg_client_sysrepo,
+ "sysrepo: subscribing for configuration changes made in the '%s' module",
+ module->name);
+
ret = sr_module_change_subscribe(
- session, module->name, frr_sr_config_change_cb, NULL, 0,
- SR_SUBSCR_DEFAULT | SR_SUBSCR_EV_ENABLED,
+ session, module->name, NULL, frr_sr_config_change_cb, NULL, 0,
+ SR_SUBSCR_DEFAULT | SR_SUBSCR_ENABLED | SR_SUBSCR_NO_THREAD,
&module->sr_subscription);
if (ret != SR_ERR_OK)
flog_err(EC_LIB_LIBSYSREPO, "sr_module_change_subscribe(): %s",
@@ -719,14 +573,14 @@ static int frr_sr_subscribe_state(const struct lys_node *snode, void *arg)
nb_node = snode->priv;
- DEBUGD(&nb_dbg_client_sysrepo, "%s: providing data to '%s'", __func__,
+ DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: providing data to '%s'",
nb_node->xpath);
- ret = sr_dp_get_items_subscribe(
- session, nb_node->xpath, frr_sr_state_cb, NULL,
- SR_SUBSCR_CTX_REUSE, &module->sr_subscription);
+ ret = sr_oper_get_items_subscribe(
+ session, snode->module->name, nb_node->xpath, frr_sr_state_cb,
+ NULL, SR_SUBSCR_CTX_REUSE, &module->sr_subscription);
if (ret != SR_ERR_OK)
- flog_err(EC_LIB_LIBSYSREPO, "sr_dp_get_items_subscribe(): %s",
+ flog_err(EC_LIB_LIBSYSREPO, "sr_oper_get_items_subscribe(): %s",
sr_strerror(ret));
return YANG_ITER_CONTINUE;
@@ -743,11 +597,11 @@ static int frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg)
nb_node = snode->priv;
- DEBUGD(&nb_dbg_client_sysrepo, "%s: providing RPC to '%s'", __func__,
+ DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: providing RPC to '%s'",
nb_node->xpath);
ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
- NULL, SR_SUBSCR_CTX_REUSE,
+ NULL, 0, SR_SUBSCR_CTX_REUSE,
&module->sr_subscription);
if (ret != SR_ERR_OK)
flog_err(EC_LIB_LIBSYSREPO, "sr_rpc_subscribe(): %s",
@@ -756,30 +610,6 @@ static int frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg)
return YANG_ITER_CONTINUE;
}
-static int frr_sr_subscribe_action(const struct lys_node *snode, void *arg)
-{
- struct yang_module *module = arg;
- struct nb_node *nb_node;
- int ret;
-
- if (snode->nodetype != LYS_ACTION)
- return YANG_ITER_CONTINUE;
-
- nb_node = snode->priv;
-
- DEBUGD(&nb_dbg_client_sysrepo, "%s: providing action to '%s'", __func__,
- nb_node->xpath);
-
- ret = sr_action_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
- NULL, SR_SUBSCR_CTX_REUSE,
- &module->sr_subscription);
- if (ret != SR_ERR_OK)
- flog_err(EC_LIB_LIBSYSREPO, "sr_action_subscribe(): %s",
- sr_strerror(ret));
-
- return YANG_ITER_CONTINUE;
-}
-
/* CLI commands. */
DEFUN (debug_nb_sr,
debug_nb_sr_cmd,
@@ -827,22 +657,13 @@ static void frr_sr_cli_init(void)
}
/* FRR's Sysrepo initialization. */
-static int frr_sr_init(const char *program_name)
+static int frr_sr_init(void)
{
struct yang_module *module;
- int sysrepo_fd, ret;
-
- sysrepo_threads = list_new();
-
- ret = sr_fd_watcher_init(&sysrepo_fd, NULL);
- if (ret != SR_ERR_OK) {
- flog_err(EC_LIB_SYSREPO_INIT, "%s: sr_fd_watcher_init(): %s",
- __func__, sr_strerror(ret));
- goto cleanup;
- }
+ int ret;
/* Connect to Sysrepo. */
- ret = sr_connect(program_name, SR_CONN_DEFAULT, &connection);
+ ret = sr_connect(SR_CONN_DEFAULT, &connection);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_SYSREPO_INIT, "%s: sr_connect(): %s", __func__,
sr_strerror(ret));
@@ -850,8 +671,7 @@ static int frr_sr_init(const char *program_name)
}
/* Start session. */
- ret = sr_session_start(connection, SR_DS_RUNNING, SR_SESS_DEFAULT,
- &session);
+ ret = sr_session_start(connection, SR_DS_RUNNING, &session);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_SYSREPO_INIT, "%s: sr_session_start(): %s",
__func__, sr_strerror(ret));
@@ -860,19 +680,28 @@ static int frr_sr_init(const char *program_name)
/* Perform subscriptions. */
RB_FOREACH (module, yang_modules, &yang_modules) {
+ int event_pipe;
+
frr_sr_subscribe_config(module);
yang_snodes_iterate_module(module->info, frr_sr_subscribe_state,
0, module);
yang_snodes_iterate_module(module->info, frr_sr_subscribe_rpc,
0, module);
- yang_snodes_iterate_module(module->info,
- frr_sr_subscribe_action, 0, module);
+
+ /* Watch subscriptions. */
+ ret = sr_get_event_pipe(module->sr_subscription, &event_pipe);
+ if (ret != SR_ERR_OK) {
+ flog_err(EC_LIB_SYSREPO_INIT,
+ "%s: sr_get_event_pipe(): %s", __func__,
+ sr_strerror(ret));
+ goto cleanup;
+ }
+ thread_add_read(master, frr_sr_read_cb, module->sr_subscription,
+ event_pipe, &module->sr_thread);
}
hook_register(nb_notification_send, frr_sr_notification_send);
- frr_sr_fd_add(SR_FD_INPUT_READY, sysrepo_fd);
-
return 0;
cleanup:
@@ -888,7 +717,8 @@ static int frr_sr_finish(void)
RB_FOREACH (module, yang_modules, &yang_modules) {
if (!module->sr_subscription)
continue;
- sr_unsubscribe(session, module->sr_subscription);
+ sr_unsubscribe(module->sr_subscription);
+ THREAD_OFF(module->sr_thread);
}
if (session)
@@ -896,24 +726,26 @@ static int frr_sr_finish(void)
if (connection)
sr_disconnect(connection);
- sysrepo_threads->del = (void (*)(void *))frr_sr_fd_free;
- list_delete(&sysrepo_threads);
- sr_fd_watcher_cleanup();
-
return 0;
}
-static int frr_sr_module_late_init(struct thread_master *tm)
+static int frr_sr_module_very_late_init(struct thread_master *tm)
{
master = tm;
- if (frr_sr_init(frr_get_progname()) < 0) {
+ if (frr_sr_init() < 0) {
flog_err(EC_LIB_SYSREPO_INIT,
"failed to initialize the Sysrepo module");
return -1;
}
hook_register(frr_fini, frr_sr_finish);
+
+ return 0;
+}
+
+static int frr_sr_module_late_init(struct thread_master *tm)
+{
frr_sr_cli_init();
return 0;
@@ -922,6 +754,7 @@ static int frr_sr_module_late_init(struct thread_master *tm)
static int frr_sr_module_init(void)
{
hook_register(frr_late_init, frr_sr_module_late_init);
+ hook_register(frr_very_late_init, frr_sr_module_very_late_init);
return 0;
}
diff --git a/lib/pbr.h b/lib/pbr.h
index fd183d7115..e365888662 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -97,7 +97,8 @@ struct pbr_rule {
uint32_t unique;
struct pbr_filter filter;
struct pbr_action action;
- ifindex_t ifindex;
+
+ char ifname[INTERFACE_NAMSIZ + 1];
};
/* TCP flags value shared
@@ -129,6 +130,8 @@ struct pbr_rule {
#define MATCH_FRAGMENT_INVERSE_SET (1 << 9)
#define MATCH_ICMP_SET (1 << 10)
#define MATCH_PROTOCOL_SET (1 << 11)
+#define MATCH_FLOW_LABEL_SET (1 << 12)
+#define MATCH_FLOW_LABEL_INVERSE_SET (1 << 13)
extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
struct pbr_rule *zrule);
diff --git a/lib/prefix.c b/lib/prefix.c
index 697e1a6239..0a88f9eca6 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -188,6 +188,10 @@ int prefix_match(const struct prefix *n, const struct prefix *p)
if (n->family == AF_FLOWSPEC) {
/* prefixlen is unused. look at fs prefix len */
+ if (n->u.prefix_flowspec.family !=
+ p->u.prefix_flowspec.family)
+ return 0;
+
if (n->u.prefix_flowspec.prefixlen >
p->u.prefix_flowspec.prefixlen)
return 0;
@@ -325,6 +329,8 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc)
len = src->u.prefix_flowspec.prefixlen;
dest->u.prefix_flowspec.prefixlen =
src->u.prefix_flowspec.prefixlen;
+ dest->u.prefix_flowspec.family =
+ src->u.prefix_flowspec.family;
dest->family = src->family;
temp = XCALLOC(MTYPE_PREFIX_FLOWSPEC, len);
dest->u.prefix_flowspec.ptr = (uintptr_t)temp;
@@ -374,6 +380,9 @@ int prefix_same(union prefixconstptr up1, union prefixconstptr up2)
sizeof(struct evpn_addr)))
return 1;
if (p1->family == AF_FLOWSPEC) {
+ if (p1->u.prefix_flowspec.family !=
+ p2->u.prefix_flowspec.family)
+ return 0;
if (p1->u.prefix_flowspec.prefixlen !=
p2->u.prefix_flowspec.prefixlen)
return 0;
@@ -415,6 +424,10 @@ int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2)
pp1 = (const uint8_t *)p1->u.prefix_flowspec.ptr;
pp2 = (const uint8_t *)p2->u.prefix_flowspec.ptr;
+ if (p1->u.prefix_flowspec.family !=
+ p2->u.prefix_flowspec.family)
+ return 1;
+
if (p1->u.prefix_flowspec.prefixlen !=
p2->u.prefix_flowspec.prefixlen)
return numcmp(p1->u.prefix_flowspec.prefixlen,
diff --git a/lib/prefix.h b/lib/prefix.h
index 400f07386f..2a33d532c8 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -176,6 +176,7 @@ struct evpn_addr {
#endif
struct flowspec_prefix {
+ uint8_t family;
uint16_t prefixlen; /* length in bytes */
uintptr_t ptr;
};
diff --git a/lib/privs.c b/lib/privs.c
index 5c7e1240e2..dc43b7279d 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -1020,11 +1020,11 @@ void zprivs_get_ids(struct zprivs_ids_t *ids)
ids->uid_priv = getuid();
(zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
- : (ids->uid_normal = -1);
+ : (ids->uid_normal = (uid_t)-1);
(zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
- : (ids->gid_normal = -1);
+ : (ids->gid_normal = (uid_t)-1);
(zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
- : (ids->gid_vty = -1);
+ : (ids->gid_vty = (uid_t)-1);
return;
}
diff --git a/lib/stream.c b/lib/stream.c
index 768114e69b..dc207c16a4 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -256,6 +256,42 @@ void stream_forward_getp(struct stream *s, size_t size)
s->getp += size;
}
+bool stream_forward_getp2(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (!GETP_VALID(s, s->getp + size))
+ return false;
+
+ s->getp += size;
+
+ return true;
+}
+
+void stream_rewind_getp(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (size > s->getp || !GETP_VALID(s, s->getp - size)) {
+ STREAM_BOUND_WARN(s, "rewind getp");
+ return;
+ }
+
+ s->getp -= size;
+}
+
+bool stream_rewind_getp2(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (size > s->getp || !GETP_VALID(s, s->getp - size))
+ return false;
+
+ s->getp -= size;
+
+ return true;
+}
+
void stream_forward_endp(struct stream *s, size_t size)
{
STREAM_VERIFY_SANE(s);
@@ -268,6 +304,18 @@ void stream_forward_endp(struct stream *s, size_t size)
s->endp += size;
}
+bool stream_forward_endp2(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (!ENDP_VALID(s, s->endp + size))
+ return false;
+
+ s->endp += size;
+
+ return true;
+}
+
/* Copy from stream to destination. */
bool stream_get2(void *dst, struct stream *s, size_t size)
{
diff --git a/lib/stream.h b/lib/stream.h
index 1250b6944d..23f85d809b 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -160,7 +160,6 @@ extern size_t stream_resize_inplace(struct stream **sptr, size_t newsize);
extern size_t stream_get_getp(const struct stream *s);
extern size_t stream_get_endp(const struct stream *s);
extern size_t stream_get_size(const struct stream *s);
-extern uint8_t *stream_get_data(struct stream *s);
/**
* Create a new stream structure; copy offset bytes from s1 to the new
@@ -173,7 +172,11 @@ extern struct stream *stream_dupcat(const struct stream *s1,
extern void stream_set_getp(struct stream *, size_t);
extern void stream_set_endp(struct stream *, size_t);
extern void stream_forward_getp(struct stream *, size_t);
+extern bool stream_forward_getp2(struct stream *, size_t);
+extern void stream_rewind_getp(struct stream *s, size_t size);
+extern bool stream_rewind_getp2(struct stream *s, size_t size);
extern void stream_forward_endp(struct stream *, size_t);
+extern bool stream_forward_endp2(struct stream *, size_t);
/* steam_put: NULL source zeroes out size_t bytes of stream */
extern void stream_put(struct stream *, const void *, size_t);
@@ -453,6 +456,24 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
goto stream_failure; \
} while (0)
+#define STREAM_FORWARD_GETP(STR, SIZE) \
+ do { \
+ if (!stream_forward_getp2((STR), (SIZE))) \
+ goto stream_failure; \
+ } while (0)
+
+#define STREAM_REWIND_GETP(STR, SIZE) \
+ do { \
+ if (!stream_rewind_getp2((STR), (SIZE))) \
+ goto stream_failure; \
+ } while (0)
+
+#define STREAM_FORWARD_ENDP(STR, SIZE) \
+ do { \
+ if (!stream_forward_endp2((STR), (SIZE))) \
+ goto stream_failure; \
+ } while (0)
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/subdir.am b/lib/subdir.am
index 1feaa56d13..b8bcee139b 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -42,6 +42,7 @@ lib_libfrr_la_SOURCES = \
lib/jhash.c \
lib/json.c \
lib/keychain.c \
+ lib/ldp_sync.c \
lib/lib_errors.c \
lib/lib_vty.c \
lib/libfrr.c \
@@ -198,6 +199,7 @@ pkginclude_HEADERS += \
lib/jhash.h \
lib/json.h \
lib/keychain.h \
+ lib/ldp_sync.h \
lib/lib_errors.h \
lib/lib_vty.h \
lib/libfrr.h \
diff --git a/lib/thread.c b/lib/thread.c
index 19e4827283..db35a3f031 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -438,7 +438,8 @@ struct thread_master *thread_master_create(const char *name)
pthread_cond_init(&rv->cancel_cond, NULL);
/* Set name */
- rv->name = name ? XSTRDUP(MTYPE_THREAD_MASTER, name) : NULL;
+ name = name ? name : "default";
+ rv->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
/* Initialize I/O task data structures */
getrlimit(RLIMIT_NOFILE, &limit);
@@ -449,10 +450,13 @@ struct thread_master *thread_master_create(const char *name)
rv->write = XCALLOC(MTYPE_THREAD_POLL,
sizeof(struct thread *) * rv->fd_limit);
+ char tmhashname[strlen(name) + 32];
+ snprintf(tmhashname, sizeof(tmhashname), "%s - threadmaster event hash",
+ name);
rv->cpu_record = hash_create_size(
8, (unsigned int (*)(const void *))cpu_record_hash_key,
(bool (*)(const void *, const void *))cpu_record_hash_cmp,
- "Thread Hash");
+ tmhashname);
thread_list_init(&rv->event);
thread_list_init(&rv->ready);
diff --git a/lib/vrf.c b/lib/vrf.c
index 20e08b03d8..cc7445558c 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -159,10 +159,6 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
struct vrf *vrf = NULL;
int new = 0;
- if (debug_vrf)
- zlog_debug("VRF_GET: %s(%u)", name == NULL ? "(NULL)" : name,
- vrf_id);
-
/* Nothing to see, move along here */
if (!name && vrf_id == VRF_UNKNOWN)
return NULL;
@@ -225,7 +221,8 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
void vrf_delete(struct vrf *vrf)
{
if (debug_vrf)
- zlog_debug("VRF %u is to be deleted.", vrf->vrf_id);
+ zlog_debug("VRF %s(%u) is to be deleted.", vrf->name,
+ vrf->vrf_id);
if (vrf_is_enabled(vrf))
vrf_disable(vrf);
@@ -282,7 +279,7 @@ int vrf_enable(struct vrf *vrf)
return 1;
if (debug_vrf)
- zlog_debug("VRF %u is enabled.", vrf->vrf_id);
+ zlog_debug("VRF %s(%u) is enabled.", vrf->name, vrf->vrf_id);
SET_FLAG(vrf->status, VRF_ACTIVE);
@@ -312,11 +309,20 @@ void vrf_disable(struct vrf *vrf)
UNSET_FLAG(vrf->status, VRF_ACTIVE);
if (debug_vrf)
- zlog_debug("VRF %u is to be disabled.", vrf->vrf_id);
+ zlog_debug("VRF %s(%u) is to be disabled.", vrf->name,
+ vrf->vrf_id);
/* Till now, nothing to be done for the default VRF. */
// Pending: see why this statement.
+
+ /*
+ * When the vrf is disabled let's
+ * handle all nexthop-groups associated
+ * with this vrf
+ */
+ nexthop_group_disable_vrf(vrf);
+
if (vrf_master.vrf_disable_hook)
(*vrf_master.vrf_disable_hook)(vrf);
}
diff --git a/lib/yang.c b/lib/yang.c
index 6ab9492d52..9bfdcb858c 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -84,6 +84,9 @@ static const char *yang_module_imp_clb(const char *mod_name,
static const char *const frr_native_modules[] = {
"frr-interface",
"frr-vrf",
+ "frr-routing",
+ "frr-route-map",
+ "frr-nexthop",
"frr-ripd",
"frr-ripngd",
"frr-isisd",
diff --git a/lib/yang.h b/lib/yang.h
index cc048c44e8..94bbed233d 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -63,6 +63,7 @@ struct yang_module {
#endif
#ifdef HAVE_SYSREPO
sr_subscription_ctx_t *sr_subscription;
+ struct thread *sr_thread;
#endif
};
RB_HEAD(yang_modules, yang_module);
diff --git a/lib/zclient.c b/lib/zclient.c
index 808aa18bbe..c5016d22e2 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -871,6 +871,37 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1,
break;
}
+ if (next1->srte_color < next2->srte_color)
+ return -1;
+ if (next1->srte_color > next2->srte_color)
+ return 1;
+
+ if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) ||
+ CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+
+ if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return -1;
+
+ if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return 1;
+
+ if (next1->backup_num > 0 || next2->backup_num > 0) {
+
+ if (next1->backup_num < next2->backup_num)
+ return -1;
+
+ if (next1->backup_num > next2->backup_num)
+ return 1;
+
+ ret = memcmp(next1->backup_idx,
+ next2->backup_idx, next1->backup_num);
+ if (ret != 0)
+ return ret;
+ }
+ }
+
return 0;
}
@@ -1393,7 +1424,7 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
stream_putw(s, zrule->filter.fwmark); /* fwmark */
stream_putl(s, zrule->action.table);
- stream_putl(s, zrule->ifindex);
+ stream_put(s, zrule->ifname, INTERFACE_NAMSIZ);
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
@@ -1423,26 +1454,23 @@ stream_failure:
}
bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
- uint32_t *priority, uint32_t *unique,
- ifindex_t *ifindex,
+ uint32_t *priority, uint32_t *unique, char *ifname,
enum zapi_rule_notify_owner *note)
{
uint32_t prio, seq, uni;
- ifindex_t ifi;
STREAM_GET(note, s, sizeof(*note));
STREAM_GETL(s, seq);
STREAM_GETL(s, prio);
STREAM_GETL(s, uni);
- STREAM_GETL(s, ifi);
+ STREAM_GET(ifname, s, INTERFACE_NAMSIZ);
if (zclient_debug)
- zlog_debug("%s: %u %u %u %u", __func__, seq, prio, uni, ifi);
+ zlog_debug("%s: %u %u %u %s", __func__, seq, prio, uni, ifname);
*seqno = seq;
*priority = prio;
*unique = uni;
- *ifindex = ifi;
return true;
@@ -2037,7 +2065,7 @@ static void zebra_interface_if_set_value(struct stream *s,
uint8_t link_params_status = 0;
ifindex_t old_ifindex, new_ifindex;
- old_ifindex = ifp->ifindex;
+ old_ifindex = ifp->oldifindex;
/* Read interface's index. */
STREAM_GETL(s, new_ifindex);
if_set_index(ifp, new_ifindex);
diff --git a/lib/zclient.h b/lib/zclient.h
index dab384d5ec..f99b3ad743 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -391,6 +391,11 @@ struct zmsghdr {
} __attribute__((packed));
#define ZAPI_HEADER_CMD_LOCATION offsetof(struct zmsghdr, command)
+/*
+ * ZAPI nexthop. Note that these are sorted when associated with ZAPI routes,
+ * and that sorting must be aligned with the sorting of nexthops in
+ * lib/nexthop.c. Any new fields must be accounted for in zapi_nexthop_cmp().
+ */
struct zapi_nexthop {
enum nexthop_types_t type;
vrf_id_t vrf_id;
@@ -839,8 +844,7 @@ bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
uint32_t *tableid,
enum zapi_route_notify_owner *note);
bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
- uint32_t *priority, uint32_t *unique,
- ifindex_t *ifindex,
+ uint32_t *priority, uint32_t *unique, char *ifname,
enum zapi_rule_notify_owner *note);
bool zapi_ipset_notify_decode(struct stream *s,
uint32_t *unique,
@@ -950,6 +954,14 @@ enum zapi_opaque_registry {
LINK_STATE_REQUEST = 1,
/* Update containing link-state db info */
LINK_STATE_UPDATE = 2,
+ /* Request LDP-SYNC state from LDP */
+ LDP_IGP_SYNC_IF_STATE_REQUEST = 3,
+ /* Update containing LDP IGP Sync State info */
+ LDP_IGP_SYNC_IF_STATE_UPDATE = 4,
+ /* Announce that LDP is up */
+ LDP_IGP_SYNC_ANNOUNCE_UPDATE = 5,
+ /* Heartbeat indicating that LDP is running */
+ LDP_IGP_SYNC_HELLO_UPDATE = 6,
};
/* Send the hello message.
diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c
index b23ab073b4..8f4c2a46a8 100644
--- a/lib/zlog_targets.c
+++ b/lib/zlog_targets.c
@@ -225,10 +225,11 @@ static bool zlog_file_cycle(struct zlog_cfg_file *zcf)
zlt->zt.logfn_sigsafe = zlog_fd_sigsafe;
} while (0);
- old = zlog_target_replace(&zcf->active->zt, &zlt->zt);
+ old = zlog_target_replace(zcf->active ? &zcf->active->zt : NULL,
+ zlt ? &zlt->zt : NULL);
zcf->active = zlt;
- zlog_file_target_free(container_of(old, struct zlt_fd, zt));
+ zlog_file_target_free(container_of_null(old, struct zlt_fd, zt));
return rv;
}