summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/filter.h8
-rw-r--r--lib/filter_cli.c23
-rw-r--r--lib/filter_nb.c184
-rw-r--r--lib/link_state.c1425
-rw-r--r--lib/link_state.h405
-rw-r--r--lib/nexthop.c89
-rw-r--r--lib/northbound.h17
-rw-r--r--lib/northbound_cli.c114
-rw-r--r--lib/prefix.c115
-rw-r--r--lib/prefix.h2
-rw-r--r--lib/printf/glue.c60
-rw-r--r--lib/printf/printflocal.h8
-rw-r--r--lib/printf/vfprintf.c179
-rw-r--r--lib/printfrr.h159
-rw-r--r--lib/routemap.c296
-rw-r--r--lib/routemap.h531
-rw-r--r--lib/routemap_cli.c803
-rw-r--r--lib/routemap_northbound.c213
-rw-r--r--lib/sockunion.c144
-rw-r--r--lib/sockunion.h12
-rw-r--r--lib/srcdest_table.c18
-rw-r--r--lib/strformat.c272
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/vrf.c4
-rw-r--r--lib/vrf.h12
-rw-r--r--lib/vty.c3
-rw-r--r--lib/zclient.h2
27 files changed, 3997 insertions, 1102 deletions
diff --git a/lib/filter.h b/lib/filter.h
index 091a5197f6..28f5202022 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -182,6 +182,9 @@ struct acl_dup_args {
/** Access list name. */
const char *ada_name;
+ /** Entry action. */
+ const char *ada_action;
+
#define ADA_MAX_VALUES 4
/** Entry XPath for value. */
const char *ada_xpath[ADA_MAX_VALUES];
@@ -209,6 +212,9 @@ struct plist_dup_args {
/** Access list name. */
const char *pda_name;
+ /** Entry action. */
+ const char *pda_action;
+
#define PDA_MAX_VALUES 4
/** Entry XPath for value. */
const char *pda_xpath[PDA_MAX_VALUES];
@@ -234,10 +240,12 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda);
struct lyd_node;
struct vty;
+extern int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
extern void access_list_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+extern int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
extern void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode,
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
index 5d66a9fc73..96444ac970 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -173,6 +173,7 @@ DEFPY_YANG(
if (seq_str == NULL) {
ada.ada_type = "ipv4";
ada.ada_name = name;
+ ada.ada_action = action;
if (host_str && mask_str == NULL) {
ada.ada_xpath[0] = "./host";
ada.ada_value[0] = host_str;
@@ -309,6 +310,7 @@ DEFPY_YANG(
if (seq_str == NULL) {
ada.ada_type = "ipv4";
ada.ada_name = name;
+ ada.ada_action = action;
if (src_str && src_mask_str == NULL) {
ada.ada_xpath[idx] = "./host";
ada.ada_value[idx] = src_str;
@@ -504,6 +506,7 @@ DEFPY_YANG(
if (seq_str == NULL) {
ada.ada_type = "ipv4";
ada.ada_name = name;
+ ada.ada_action = action;
if (prefix_str) {
ada.ada_xpath[0] = "./ipv4-prefix";
@@ -701,6 +704,7 @@ DEFPY_YANG(
if (seq_str == NULL) {
ada.ada_type = "ipv6";
ada.ada_name = name;
+ ada.ada_action = action;
if (prefix_str) {
ada.ada_xpath[0] = "./ipv6-prefix";
@@ -902,6 +906,7 @@ DEFPY_YANG(
if (seq_str == NULL) {
ada.ada_type = "mac";
ada.ada_name = name;
+ ada.ada_action = action;
if (mac_str) {
ada.ada_xpath[0] = "./mac";
@@ -1072,6 +1077,14 @@ ALIAS(
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
+int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+{
+ uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
+ uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
+
+ return seq1 - seq2;
+}
+
void access_list_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
@@ -1331,6 +1344,7 @@ DEFPY_YANG(
if (seq_str == NULL) {
pda.pda_type = "ipv4";
pda.pda_name = name;
+ pda.pda_action = action;
if (prefix_str) {
pda.pda_xpath[arg_idx] = "./ipv4-prefix";
pda.pda_value[arg_idx] = prefix_str;
@@ -1526,6 +1540,7 @@ DEFPY_YANG(
if (seq_str == NULL) {
pda.pda_type = "ipv6";
pda.pda_name = name;
+ pda.pda_action = action;
if (prefix_str) {
pda.pda_xpath[arg_idx] = "./ipv6-prefix";
pda.pda_value[arg_idx] = prefix_str;
@@ -1693,6 +1708,14 @@ ALIAS(
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
+int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+{
+ uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
+ uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
+
+ return seq1 - seq2;
+}
+
void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index c83738e729..3aa362ad63 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -152,6 +152,27 @@ prefix_list_nb_validate_v6_af_type(const struct lyd_node *plist_dnode,
return NB_OK;
}
+static int lib_prefix_list_entry_prefix_length_greater_or_equal_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
struct nb_cb_modify_args *args)
{
@@ -238,6 +259,9 @@ static int _acl_is_dup(const struct lyd_node *dnode, void *arg)
&& ada->ada_entry_dnode == dnode)
return YANG_ITER_CONTINUE;
+ if (strcmp(yang_dnode_get_string(dnode, "action"), ada->ada_action))
+ return YANG_ITER_CONTINUE;
+
/* Check if all values match. */
for (idx = 0; idx < ADA_MAX_VALUES; idx++) {
/* No more values. */
@@ -292,6 +316,7 @@ static bool acl_cisco_is_dup(const struct lyd_node *dnode)
/* Initialize. */
ada.ada_type = "ipv4";
ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
+ ada.ada_action = yang_dnode_get_string(entry_dnode, "action");
ada.ada_entry_dnode = entry_dnode;
/* Load all values/XPaths. */
@@ -341,6 +366,7 @@ static bool acl_zebra_is_dup(const struct lyd_node *dnode,
break;
}
ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
+ ada.ada_action = yang_dnode_get_string(entry_dnode, "action");
ada.ada_entry_dnode = entry_dnode;
/* Load all values/XPaths. */
@@ -370,6 +396,9 @@ static int _plist_is_dup(const struct lyd_node *dnode, void *arg)
&& pda->pda_entry_dnode == dnode)
return YANG_ITER_CONTINUE;
+ if (strcmp(yang_dnode_get_string(dnode, "action"), pda->pda_action))
+ return YANG_ITER_CONTINUE;
+
/* Check if all values match. */
for (idx = 0; idx < PDA_MAX_VALUES; idx++) {
/* No more values. */
@@ -403,6 +432,46 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda)
return pda->pda_found;
}
+static bool plist_is_dup_nb(const struct lyd_node *dnode)
+{
+ const struct lyd_node *entry_dnode =
+ yang_dnode_get_parent(dnode, "entry");
+ struct plist_dup_args pda = {};
+ int idx = 0, arg_idx = 0;
+ static const char *entries[] = {
+ "./ipv4-prefix",
+ "./ipv4-prefix-length-greater-or-equal",
+ "./ipv4-prefix-length-lesser-or-equal",
+ "./ipv6-prefix",
+ "./ipv6-prefix-length-greater-or-equal",
+ "./ipv6-prefix-length-lesser-or-equal",
+ "./any",
+ NULL
+ };
+
+ /* Initialize. */
+ pda.pda_type = yang_dnode_get_string(entry_dnode, "../type");
+ pda.pda_name = yang_dnode_get_string(entry_dnode, "../name");
+ pda.pda_action = yang_dnode_get_string(entry_dnode, "action");
+ pda.pda_entry_dnode = entry_dnode;
+
+ /* Load all values/XPaths. */
+ while (entries[idx] != NULL) {
+ if (!yang_dnode_exists(entry_dnode, entries[idx])) {
+ idx++;
+ continue;
+ }
+
+ pda.pda_xpath[arg_idx] = entries[idx];
+ pda.pda_value[arg_idx] =
+ yang_dnode_get_string(entry_dnode, entries[idx]);
+ arg_idx++;
+ idx++;
+ }
+
+ return plist_is_dup(entry_dnode, &pda);
+}
+
/*
* XPath: /frr-filter:lib/access-list
*/
@@ -1265,6 +1334,13 @@ lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
const struct lyd_node *plist_dnode =
yang_dnode_get_parent(args->dnode, "prefix-list");
+ if (plist_is_dup_nb(args->dnode)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "duplicated prefix list value: %s",
+ yang_dnode_get_string(args->dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
return prefix_list_nb_validate_v4_af_type(
plist_dnode, args->errmsg, args->errmsg_len);
}
@@ -1293,6 +1369,13 @@ lib_prefix_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args)
const struct lyd_node *plist_dnode =
yang_dnode_get_parent(args->dnode, "prefix-list");
+ if (plist_is_dup_nb(args->dnode)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "duplicated prefix list value: %s",
+ yang_dnode_get_string(args->dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
return prefix_list_nb_validate_v6_af_type(
plist_dnode, args->errmsg, args->errmsg_len);
}
@@ -1316,26 +1399,27 @@ lib_prefix_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args)
static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
struct nb_cb_modify_args *args)
{
- struct prefix_list_entry *ple;
-
- if (args->event == NB_EV_VALIDATE &&
- prefix_list_length_validate(args) != NB_OK)
+ if (args->event == NB_EV_VALIDATE
+ && prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- ple = nb_running_get_entry(args->dnode, NULL, true);
-
- /* Start prefix entry update procedure. */
- prefix_list_entry_update_start(ple);
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
- ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
+ if (plist_is_dup_nb(args->dnode)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "duplicated prefix list value: %s",
+ yang_dnode_get_string(args->dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
+ return prefix_list_nb_validate_v4_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
- return NB_OK;
+ return lib_prefix_list_entry_prefix_length_greater_or_equal_modify(
+ args);
}
static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
@@ -1367,11 +1451,19 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
const struct lyd_node *plist_dnode =
yang_dnode_get_parent(args->dnode, "prefix-list");
+ if (plist_is_dup_nb(args->dnode)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "duplicated prefix list value: %s",
+ yang_dnode_get_string(args->dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
return prefix_list_nb_validate_v4_af_type(
plist_dnode, args->errmsg, args->errmsg_len);
}
- return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args);
+ return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
+ args);
}
static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
@@ -1395,8 +1487,6 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify(
struct nb_cb_modify_args *args)
{
- struct prefix_list_entry *ple;
-
if (args->event == NB_EV_VALIDATE
&& prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
@@ -1405,24 +1495,19 @@ static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify(
const struct lyd_node *plist_dnode =
yang_dnode_get_parent(args->dnode, "prefix-list");
+ if (plist_is_dup_nb(args->dnode)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "duplicated prefix list value: %s",
+ yang_dnode_get_string(args->dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
return prefix_list_nb_validate_v6_af_type(
plist_dnode, args->errmsg, args->errmsg_len);
}
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- ple = nb_running_get_entry(args->dnode, NULL, true);
-
- /* Start prefix entry update procedure. */
- prefix_list_entry_update_start(ple);
-
- ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
-
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
- return NB_OK;
+ return lib_prefix_list_entry_prefix_length_greater_or_equal_modify(
+ args);
}
static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy(
@@ -1454,28 +1539,30 @@ static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify(
const struct lyd_node *plist_dnode =
yang_dnode_get_parent(args->dnode, "prefix-list");
+ if (plist_is_dup_nb(args->dnode)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "duplicated prefix list value: %s",
+ yang_dnode_get_string(args->dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
return prefix_list_nb_validate_v6_af_type(
plist_dnode, args->errmsg, args->errmsg_len);
}
- return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args);
+ return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
+ args);
}
static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy(
struct nb_cb_destroy_args *args)
{
- int af_type;
-
if (args->event == NB_EV_VALIDATE) {
const struct lyd_node *plist_dnode =
yang_dnode_get_parent(args->dnode, "prefix-list");
- af_type = yang_dnode_get_enum(plist_dnode, "./type");
- if (af_type != YPLT_IPV6) {
- snprintf(args->errmsg, args->errmsg_len,
- "prefix-list type %u is mismatched.", af_type);
- return NB_ERR_VALIDATION;
- }
- return NB_OK;
+
+ return prefix_list_nb_validate_v6_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
}
return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
@@ -1490,6 +1577,17 @@ static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
struct prefix_list_entry *ple;
int type;
+ if (args->event == NB_EV_VALIDATE) {
+ if (plist_is_dup_nb(args->dnode)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "duplicated prefix list value: %s",
+ yang_dnode_get_string(args->dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
+ return NB_OK;
+ }
+
if (args->event != NB_EV_APPLY)
return NB_OK;
@@ -1567,6 +1665,7 @@ const struct frr_yang_module_info frr_filter_info = {
.cbs = {
.create = lib_access_list_entry_create,
.destroy = lib_access_list_entry_destroy,
+ .cli_cmp = access_list_cmp,
.cli_show = access_list_show,
}
},
@@ -1690,6 +1789,7 @@ const struct frr_yang_module_info frr_filter_info = {
.cbs = {
.create = lib_prefix_list_entry_create,
.destroy = lib_prefix_list_entry_destroy,
+ .cli_cmp = prefix_list_cmp,
.cli_show = prefix_list_show,
}
},
diff --git a/lib/link_state.c b/lib/link_state.c
index 7f0d2a1245..8606f8eb09 100644
--- a/lib/link_state.c
+++ b/lib/link_state.c
@@ -33,6 +33,9 @@
#include "vty.h"
#include "zclient.h"
#include "stream.h"
+#include "sbuf.h"
+#include "printfrr.h"
+#include <lib/json.h>
#include "link_state.h"
/* Link State Memory allocation */
@@ -46,7 +49,7 @@ struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid,
{
struct ls_node *new;
- if (adv.origin == NONE)
+ if (adv.origin == UNKNOWN)
return NULL;
new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node));
@@ -70,6 +73,9 @@ struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid,
void ls_node_del(struct ls_node *node)
{
+ if (!node)
+ return;
+
XFREE(MTYPE_LS_DB, node);
node = NULL;
}
@@ -111,7 +117,7 @@ struct ls_attributes *ls_attributes_new(struct ls_node_id adv,
{
struct ls_attributes *new;
- if (adv.origin == NONE)
+ if (adv.origin == UNKNOWN)
return NULL;
new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes));
@@ -139,7 +145,7 @@ struct ls_attributes *ls_attributes_new(struct ls_node_id adv,
return new;
}
-void ls_attributes_del(struct ls_attributes *attr)
+void ls_attributes_srlg_del(struct ls_attributes *attr)
{
if (!attr)
return;
@@ -147,6 +153,18 @@ void ls_attributes_del(struct ls_attributes *attr)
if (attr->srlgs)
XFREE(MTYPE_LS_DB, attr->srlgs);
+ attr->srlgs = NULL;
+ attr->srlg_len = 0;
+ UNSET_FLAG(attr->flags, LS_ATTR_SRLG);
+}
+
+void ls_attributes_del(struct ls_attributes *attr)
+{
+ if (!attr)
+ return;
+
+ ls_attributes_srlg_del(attr);
+
XFREE(MTYPE_LS_DB, attr);
attr = NULL;
}
@@ -179,75 +197,155 @@ int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2)
}
/**
- * Link State Vertices management functions
+ * Link State prefix management functions
*/
-struct ls_vertex *ls_vertex_new(struct ls_node *node)
+struct ls_prefix *ls_prefix_new(struct ls_node_id adv, struct prefix p)
{
- struct ls_vertex *new;
+ struct ls_prefix *new;
- if (node == NULL)
+ if (adv.origin == UNKNOWN)
return NULL;
- new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_vertex));
- new->node = node;
- new->incoming_edges = list_new();
- new->outgoing_edges = list_new();
- new->prefixes = list_new();
+ new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes));
+ new->adv = adv;
+ new->pref = p;
return new;
}
-void ls_vertex_del(struct ls_vertex *vertex)
+void ls_prefix_del(struct ls_prefix *pref)
{
- if (vertex == NULL)
+ if (!pref)
return;
- list_delete_all_node(vertex->incoming_edges);
- list_delete_all_node(vertex->outgoing_edges);
- list_delete_all_node(vertex->prefixes);
- XFREE(MTYPE_LS_DB, vertex);
- vertex = NULL;
+ XFREE(MTYPE_LS_DB, pref);
+ pref = NULL;
}
+int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2)
+{
+ if ((p1 && !p2) || (!p1 && p2))
+ return 0;
+
+ if (p1 == p2)
+ return 1;
+
+ if (p1->flags != p2->flags)
+ return 0;
+
+ if (p1->adv.origin != p2->adv.origin)
+ return 0;
+
+ if (!memcmp(&p1->adv.id, &p2->adv.id, sizeof(struct ls_node_id)))
+ return 0;
+
+ /* Do we need to test individually each field, instead performing a
+ * global memcmp? There is a risk that an old value that is bit masked
+ * i.e. corresponding flag = 0, will result into a false negative
+ */
+ if (!memcmp(p1, p2, sizeof(struct ls_prefix)))
+ return 0;
+ else
+ return 1;
+}
+
+/**
+ * Link State Vertices management functions
+ */
struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node)
{
struct ls_vertex *new;
+ uint64_t key = 0;
if ((ted == NULL) || (node == NULL))
return NULL;
- new = ls_vertex_new(node);
- if (!new)
- return NULL;
-
/* set Key as the IPv4/Ipv6 Router ID or ISO System ID */
switch (node->adv.origin) {
case OSPFv2:
case STATIC:
case DIRECT:
- memcpy(&new->key, &node->adv.id.ip.addr, IPV4_MAX_BYTELEN);
+ key = ((uint64_t)ntohl(node->adv.id.ip.addr.s_addr))
+ & 0xffffffff;
break;
case ISIS_L1:
case ISIS_L2:
- memcpy(&new->key, &node->adv.id.iso.sys_id, ISO_SYS_ID_LEN);
+ memcpy(&key, &node->adv.id.iso.sys_id, ISO_SYS_ID_LEN);
break;
default:
- new->key = 0;
+ key = 0;
break;
}
- /* Remove Vertex if key is not set */
- if (new->key == 0) {
- ls_vertex_del(new);
+ /* Check that key is valid */
+ if (key == 0)
return NULL;
- }
- /* Add Vertex to TED */
+ /* Create Vertex and add it to the TED */
+ new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_vertex));
+ if (!new)
+ return NULL;
+
+ new->key = key;
+ new->node = node;
+ new->status = NEW;
+ new->type = VERTEX;
+ new->incoming_edges = list_new();
+ new->incoming_edges->cmp = (int (*)(void *, void *))edge_cmp;
+ new->outgoing_edges = list_new();
+ new->outgoing_edges->cmp = (int (*)(void *, void *))edge_cmp;
+ new->prefixes = list_new();
+ new->prefixes->cmp = (int (*)(void *, void *))subnet_cmp;
vertices_add(&ted->vertices, new);
return new;
}
+void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex)
+{
+ struct listnode *node, *nnode;
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+
+ if (!ted || !vertex)
+ return;
+
+ /* Remove outgoing Edges and list */
+ for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge))
+ ls_edge_del_all(ted, edge);
+ list_delete(&vertex->outgoing_edges);
+
+ /* Disconnect incoming Edges and remove list */
+ for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) {
+ ls_disconnect(vertex, edge, false);
+ if (edge->source == NULL)
+ ls_edge_del_all(ted, edge);
+ }
+ list_delete(&vertex->incoming_edges);
+
+ /* Remove subnet and list */
+ for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet))
+ ls_subnet_del_all(ted, subnet);
+ list_delete(&vertex->prefixes);
+
+ /* Then remove Vertex from Link State Data Base and free memory */
+ vertices_del(&ted->vertices, vertex);
+ XFREE(MTYPE_LS_DB, vertex);
+ vertex = NULL;
+}
+
+void ls_vertex_del_all(struct ls_ted *ted, struct ls_vertex *vertex)
+{
+ if (!ted || !vertex)
+ return;
+
+ /* First remove associated Link State Node */
+ ls_node_del(vertex->node);
+
+ /* Then, Vertex itself */
+ ls_vertex_del(ted, vertex);
+}
+
struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node)
{
struct ls_vertex *old;
@@ -261,49 +359,46 @@ struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node)
ls_node_del(old->node);
old->node = node;
}
+ old->status = UPDATE;
return old;
}
return ls_vertex_add(ted, node);
}
-void ls_vertex_remove(struct ls_ted *ted, struct ls_vertex *vertex)
-{
- vertices_del(&ted->vertices, vertex);
- ls_vertex_del(vertex);
-}
-
struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key)
{
- struct ls_vertex node = {};
+ struct ls_vertex vertex = {};
if (key == 0)
return NULL;
- node.key = key;
- return vertices_find(&ted->vertices, &node);
+ vertex.key = key;
+ return vertices_find(&ted->vertices, &vertex);
}
struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted,
struct ls_node_id nid)
{
- struct ls_vertex node = {};
+ struct ls_vertex vertex = {};
+ vertex.key = 0;
switch (nid.origin) {
case OSPFv2:
case STATIC:
case DIRECT:
- memcpy(&node.key, &nid.id.ip.addr, IPV4_MAX_BYTELEN);
+ vertex.key =
+ ((uint64_t)ntohl(nid.id.ip.addr.s_addr)) & 0xffffffff;
break;
case ISIS_L1:
case ISIS_L2:
- memcpy(&node.key, &nid.id.iso.sys_id, ISO_SYS_ID_LEN);
+ memcpy(&vertex.key, &nid.id.iso.sys_id, ISO_SYS_ID_LEN);
break;
default:
return NULL;
}
- return vertices_find(&ted->vertices, &node);
+ return vertices_find(&ted->vertices, &vertex);
}
int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2)
@@ -323,6 +418,49 @@ int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2)
return ls_node_same(v1->node, v2->node);
}
+void ls_vertex_clean(struct ls_ted *ted, struct ls_vertex *vertex,
+ struct zclient *zclient)
+{
+ struct listnode *node, *nnode;
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+ struct ls_message msg;
+
+ /* Remove Orphan Edge ... */
+ for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) {
+ if (edge->status == ORPHAN) {
+ if (zclient) {
+ edge->status = DELETE;
+ ls_edge2msg(&msg, edge);
+ ls_send_msg(zclient, &msg, NULL);
+ }
+ ls_edge_del_all(ted, edge);
+ }
+ }
+ for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) {
+ if (edge->status == ORPHAN) {
+ if (zclient) {
+ edge->status = DELETE;
+ ls_edge2msg(&msg, edge);
+ ls_send_msg(zclient, &msg, NULL);
+ }
+ ls_edge_del_all(ted, edge);
+ }
+ }
+
+ /* ... and Subnet from the Vertex */
+ for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) {
+ if (subnet->status == ORPHAN) {
+ if (zclient) {
+ subnet->status = DELETE;
+ ls_subnet2msg(&msg, subnet);
+ ls_send_msg(zclient, &msg, NULL);
+ }
+ ls_subnet_del_all(ted, subnet);
+ }
+ }
+}
+
/**
* Link State Edges management functions
*/
@@ -354,18 +492,18 @@ static void ls_edge_connect_to(struct ls_ted *ted, struct ls_edge *edge)
vertex = ls_vertex_add(ted, node);
}
/* and attach the edge as source to the vertex */
- listnode_add(vertex->outgoing_edges, edge);
+ listnode_add_sort_nodup(vertex->outgoing_edges, edge);
edge->source = vertex;
/* Then search if there is a reverse Edge */
dst = ls_find_edge_by_destination(ted, edge->attributes);
/* attach the destination edge to the vertex */
if (dst) {
- listnode_add(vertex->incoming_edges, dst);
+ listnode_add_sort_nodup(vertex->incoming_edges, dst);
dst->destination = vertex;
/* and destination vertex to this edge */
vertex = dst->source;
- listnode_add(vertex->incoming_edges, edge);
+ listnode_add_sort_nodup(vertex->incoming_edges, edge);
edge->destination = vertex;
}
}
@@ -374,37 +512,43 @@ struct ls_edge *ls_edge_add(struct ls_ted *ted,
struct ls_attributes *attributes)
{
struct ls_edge *new;
+ uint64_t key = 0;
if (attributes == NULL)
return NULL;
- new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge));
- new->attributes = attributes;
/* Key is the IPv4 local address */
if (!IPV4_NET0(attributes->standard.local.s_addr))
- new->key = ((uint64_t)attributes->standard.local.s_addr)
- & 0xffffffff;
+ key = ((uint64_t)ntohl(attributes->standard.local.s_addr))
+ & 0xffffffff;
/* or the IPv6 local address if IPv4 is not defined */
else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6))
- new->key = (uint64_t)(attributes->standard.local6.s6_addr32[0]
- & 0xffffffff)
- | ((uint64_t)attributes->standard.local6.s6_addr32[1]
- << 32);
+ key = (uint64_t)(attributes->standard.local6.s6_addr32[0]
+ & 0xffffffff)
+ | ((uint64_t)attributes->standard.local6.s6_addr32[1]
+ << 32);
/* of local identifier if no IP addresses are defined */
else if (attributes->standard.local_id != 0)
- new->key = (uint64_t)(
+ key = (uint64_t)(
(attributes->standard.local_id & 0xffffffff)
| ((uint64_t)attributes->standard.remote_id << 32));
- /* Remove Edge if key is not known */
- if (new->key == 0) {
- XFREE(MTYPE_LS_DB, new);
+ /* Check that key is valid */
+ if (key == 0)
+ return NULL;
+
+ /* Create Edge and add it to the TED */
+ new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge));
+ if (!new)
return NULL;
- }
+ new->attributes = attributes;
+ new->key = key;
+ new->status = NEW;
+ new->type = EDGE;
edges_add(&ted->edges, new);
- /* Finally, connect edge to vertices */
+ /* Finally, connect Edge to Vertices */
ls_edge_connect_to(ted, new);
return new;
@@ -429,9 +573,10 @@ struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted,
if (attributes == NULL)
return NULL;
+ edge.key = 0;
/* Key is the IPv4 local address */
if (!IPV4_NET0(attributes->standard.local.s_addr))
- edge.key = ((uint64_t)attributes->standard.local.s_addr)
+ edge.key = ((uint64_t)ntohl(attributes->standard.local.s_addr))
& 0xffffffff;
/* or the IPv6 local address if IPv4 is not defined */
else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6))
@@ -459,18 +604,19 @@ struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted,
if (attributes == NULL)
return NULL;
- /* Key is the IPv4 local address */
+ edge.key = 0;
+ /* Key is the IPv4 remote address */
if (!IPV4_NET0(attributes->standard.remote.s_addr))
- edge.key = ((uint64_t)attributes->standard.remote.s_addr)
+ edge.key = ((uint64_t)ntohl(attributes->standard.remote.s_addr))
& 0xffffffff;
- /* or the IPv6 local address if IPv4 is not defined */
+ /* or the IPv6 remote address if IPv4 is not defined */
else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.remote6))
edge.key =
(uint64_t)(attributes->standard.remote6.s6_addr32[0]
& 0xffffffff)
| ((uint64_t)attributes->standard.remote6.s6_addr32[1]
<< 32);
- /* of local identifier if no IP addresses are defined */
+ /* of remote identifier if no IP addresses are defined */
else if (attributes->standard.remote_id != 0)
edge.key = (uint64_t)(
(attributes->standard.remote_id & 0xffffffff)
@@ -498,6 +644,7 @@ struct ls_edge *ls_edge_update(struct ls_ted *ted,
ls_attributes_del(old->attributes);
old->attributes = attributes;
}
+ old->status = UPDATE;
return old;
}
@@ -505,15 +652,46 @@ struct ls_edge *ls_edge_update(struct ls_ted *ted,
return ls_edge_add(ted, attributes);
}
+int ls_edge_same(struct ls_edge *e1, struct ls_edge *e2)
+{
+ if ((e1 && !e2) || (!e1 && e2))
+ return 0;
+
+ if (!e1 && !e2)
+ return 1;
+
+ if (e1->key != e2->key)
+ return 0;
+
+ if (e1->attributes == e2->attributes)
+ return 1;
+
+ return ls_attributes_same(e1->attributes, e2->attributes);
+}
+
void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge)
{
- /* Fist disconnect Edge */
+ if (!ted || !edge)
+ return;
+
+ /* Fist disconnect Edge from Vertices */
ls_disconnect_edge(edge);
/* Then remove it from the Data Base */
edges_del(&ted->edges, edge);
XFREE(MTYPE_LS_DB, edge);
}
+void ls_edge_del_all(struct ls_ted *ted, struct ls_edge *edge)
+{
+ if (!ted || !edge)
+ return;
+
+ /* Remove associated Link State Attributes */
+ ls_attributes_del(edge->attributes);
+ /* Then Edge itself */
+ ls_edge_del(ted, edge);
+}
+
/**
* Link State Subnet Management functions.
*/
@@ -531,6 +709,8 @@ struct ls_subnet *ls_subnet_add(struct ls_ted *ted,
new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_subnet));
new->ls_pref = ls_pref;
new->key = ls_pref->pref;
+ new->status = NEW;
+ new->type = SUBNET;
/* Find Vertex */
vertex = ls_find_vertex_by_id(ted, ls_pref->adv);
@@ -541,19 +721,73 @@ struct ls_subnet *ls_subnet_add(struct ls_ted *ted,
}
/* And attach the subnet to the corresponding Vertex */
new->vertex = vertex;
- listnode_add(vertex->prefixes, new);
+ listnode_add_sort_nodup(vertex->prefixes, new);
subnets_add(&ted->subnets, new);
return new;
}
+struct ls_subnet *ls_subnet_update(struct ls_ted *ted, struct ls_prefix *pref)
+{
+ struct ls_subnet *old;
+
+ if (pref == NULL)
+ return NULL;
+
+ old = ls_find_subnet(ted, pref->pref);
+ if (old) {
+ if (!ls_prefix_same(old->ls_pref, pref)) {
+ ls_prefix_del(old->ls_pref);
+ old->ls_pref = pref;
+ }
+ old->status = UPDATE;
+ return old;
+ }
+
+ return ls_subnet_add(ted, pref);
+}
+
+int ls_subnet_same(struct ls_subnet *s1, struct ls_subnet *s2)
+{
+ if ((s1 && !s2) || (!s1 && s2))
+ return 0;
+
+ if (!s1 && !s2)
+ return 1;
+
+ if (!prefix_same(&s1->key, &s2->key))
+ return 0;
+
+ if (s1->ls_pref == s2->ls_pref)
+ return 1;
+
+ return ls_prefix_same(s1->ls_pref, s2->ls_pref);
+}
+
void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet)
{
+ if (!ted || !subnet)
+ return;
+
+ /* First, disconnect Subnet from associated Vertex */
+ listnode_delete(subnet->vertex->prefixes, subnet);
+ /* Then delete Subnet */
subnets_del(&ted->subnets, subnet);
XFREE(MTYPE_LS_DB, subnet);
}
+void ls_subnet_del_all(struct ls_ted *ted, struct ls_subnet *subnet)
+{
+ if (!ted || !subnet)
+ return;
+
+ /* First, remove associated Link State Subnet */
+ ls_prefix_del(subnet->ls_pref);
+ /* Then, delete Subnet itself */
+ ls_subnet_del(ted, subnet);
+}
+
struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix)
{
struct ls_subnet subnet = {};
@@ -592,6 +826,11 @@ void ls_ted_del(struct ls_ted *ted)
if (ted == NULL)
return;
+ /* Check that TED is empty */
+ if (vertices_count(&ted->vertices) || edges_count(&ted->edges)
+ || subnets_count(&ted->subnets))
+ return;
+
/* Release RB Tree */
vertices_fini(&ted->vertices);
edges_fini(&ted->edges);
@@ -601,16 +840,63 @@ void ls_ted_del(struct ls_ted *ted)
ted = NULL;
}
+void ls_ted_del_all(struct ls_ted *ted)
+{
+ struct ls_vertex *vertex;
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+
+ if (ted == NULL)
+ return;
+
+ /* First remove Vertices, Edges and Subnets and associated Link State */
+ frr_each (vertices, &ted->vertices, vertex)
+ ls_vertex_del_all(ted, vertex);
+ frr_each (edges, &ted->edges, edge)
+ ls_edge_del_all(ted, edge);
+ frr_each (subnets, &ted->subnets, subnet)
+ ls_subnet_del_all(ted, subnet);
+
+ /* then remove TED itself */
+ ls_ted_del(ted);
+}
+
+void ls_ted_clean(struct ls_ted *ted)
+{
+ struct ls_vertex *vertex;
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+
+ if (ted == NULL)
+ return;
+
+ /* First, start with Vertices */
+ frr_each (vertices, &ted->vertices, vertex)
+ if (vertex->status == ORPHAN)
+ ls_vertex_del_all(ted, vertex);
+
+ /* Then Edges */
+ frr_each (edges, &ted->edges, edge)
+ if (edge->status == ORPHAN)
+ ls_edge_del_all(ted, edge);
+
+ /* and Subnets */
+ frr_each (subnets, &ted->subnets, subnet)
+ if (subnet->status == ORPHAN)
+ ls_subnet_del_all(ted, subnet);
+
+}
+
void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source)
{
if (vertex == NULL || edge == NULL)
return;
if (source) {
- listnode_add(vertex->outgoing_edges, edge);
+ listnode_add_sort_nodup(vertex->outgoing_edges, edge);
edge->source = vertex;
} else {
- listnode_add(vertex->incoming_edges, edge);
+ listnode_add_sort_nodup(vertex->incoming_edges, edge);
edge->destination = vertex;
}
}
@@ -640,11 +926,10 @@ void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst,
edge->destination = dst;
if (src != NULL)
- listnode_add(src->outgoing_edges, edge);
+ listnode_add_sort_nodup(src->outgoing_edges, edge);
if (dst != NULL)
- listnode_add(dst->incoming_edges, edge);
-
+ listnode_add_sort_nodup(dst->incoming_edges, edge);
}
void ls_disconnect_edge(struct ls_edge *edge)
@@ -654,12 +939,68 @@ void ls_disconnect_edge(struct ls_edge *edge)
ls_disconnect(edge->source, edge, true);
ls_disconnect(edge->destination, edge, false);
+
+ /* Mark this Edge as ORPHAN for future cleanup */
+ edge->status = ORPHAN;
}
/**
* Link State Message management functions
*/
+int ls_register(struct zclient *zclient, bool server)
+{
+ int rc;
+
+ if (server)
+ rc = zclient_register_opaque(zclient, LINK_STATE_SYNC);
+ else
+ rc = zclient_register_opaque(zclient, LINK_STATE_UPDATE);
+
+ return rc;
+}
+
+int ls_unregister(struct zclient *zclient, bool server)
+{
+ int rc;
+
+ if (server)
+ rc = zclient_unregister_opaque(zclient, LINK_STATE_SYNC);
+ else
+ rc = zclient_unregister_opaque(zclient, LINK_STATE_UPDATE);
+
+ return rc;
+}
+
+int ls_request_sync(struct zclient *zclient)
+{
+ struct stream *s;
+ uint16_t flags = 0;
+
+ /* Check buffer size */
+ if (STREAM_SIZE(zclient->obuf)
+ < (ZEBRA_HEADER_SIZE + 3 * sizeof(uint32_t)))
+ return -1;
+
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT);
+
+ /* Set type and flags */
+ stream_putl(s, LINK_STATE_SYNC);
+ stream_putw(s, flags);
+ /* Send destination client info */
+ stream_putc(s, zclient->redist_default);
+ stream_putw(s, zclient->instance);
+ stream_putl(s, zclient->session_id);
+
+ /* Put length into the header at the start of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zclient_send_message(zclient);
+}
+
static struct ls_node *ls_parse_node(struct stream *s)
{
struct ls_node *node;
@@ -723,7 +1064,7 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s)
STREAM_GET(attr->name, s, len);
}
if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC))
- STREAM_GETL(s, attr->standard.metric);
+ STREAM_GETL(s, attr->metric);
if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
STREAM_GETL(s, attr->standard.te_metric);
if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
@@ -804,7 +1145,7 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s)
stream_failure:
zlog_err("LS(%s): Could not parse Link State Attributes. Abort!",
__func__);
- /* Clean memeory allocation */
+ /* Clean memory allocation */
if (attr->srlgs != NULL)
XFREE(MTYPE_LS_DB, attr->srlgs);
XFREE(MTYPE_LS_DB, attr);
@@ -947,7 +1288,7 @@ static int ls_format_attributes(struct stream *s, struct ls_attributes *attr)
stream_putc(s, '\0');
}
if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC))
- stream_putl(s, attr->standard.metric);
+ stream_putl(s, attr->metric);
if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
stream_putl(s, attr->standard.te_metric);
if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
@@ -1084,6 +1425,10 @@ int ls_send_msg(struct zclient *zclient, struct ls_message *msg,
struct stream *s;
uint16_t flags = 0;
+ /* Check if we have a valid message */
+ if (msg->event == LS_MSG_EVENT_UNDEF)
+ return -1;
+
/* Check buffer size */
if (STREAM_SIZE(zclient->obuf) <
(ZEBRA_HEADER_SIZE + sizeof(uint32_t) + sizeof(msg)))
@@ -1094,7 +1439,7 @@ int ls_send_msg(struct zclient *zclient, struct ls_message *msg,
zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT);
- /* Send sub-type, flags and destination for unicast message */
+ /* Set sub-type, flags and destination for unicast message */
stream_putl(s, LINK_STATE_UPDATE);
if (dst != NULL) {
SET_FLAG(flags, ZAPI_OPAQUE_FLAG_UNICAST);
@@ -1103,8 +1448,9 @@ int ls_send_msg(struct zclient *zclient, struct ls_message *msg,
stream_putc(s, dst->proto);
stream_putw(s, dst->instance);
stream_putl(s, dst->session_id);
- } else
+ } else {
stream_putw(s, flags);
+ }
/* Format Link State message */
if (ls_format_msg(s, msg) < 0) {
@@ -1128,8 +1474,25 @@ struct ls_message *ls_vertex2msg(struct ls_message *msg,
memset(msg, 0, sizeof(*msg));
msg->type = LS_MSG_TYPE_NODE;
+ switch (vertex->status) {
+ case NEW:
+ msg->event = LS_MSG_EVENT_ADD;
+ break;
+ case UPDATE:
+ msg->event = LS_MSG_EVENT_UPDATE;
+ break;
+ case DELETE:
+ msg->event = LS_MSG_EVENT_DELETE;
+ break;
+ case SYNC:
+ msg->event = LS_MSG_EVENT_SYNC;
+ break;
+ default:
+ msg->event = LS_MSG_EVENT_UNDEF;
+ break;
+ }
msg->data.node = vertex->node;
- msg->remote_id.origin = NONE;
+ msg->remote_id.origin = UNKNOWN;
return msg;
}
@@ -1143,11 +1506,28 @@ struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge)
memset(msg, 0, sizeof(*msg));
msg->type = LS_MSG_TYPE_ATTRIBUTES;
+ switch (edge->status) {
+ case NEW:
+ msg->event = LS_MSG_EVENT_ADD;
+ break;
+ case UPDATE:
+ msg->event = LS_MSG_EVENT_UPDATE;
+ break;
+ case DELETE:
+ msg->event = LS_MSG_EVENT_DELETE;
+ break;
+ case SYNC:
+ msg->event = LS_MSG_EVENT_SYNC;
+ break;
+ default:
+ msg->event = LS_MSG_EVENT_UNDEF;
+ break;
+ }
msg->data.attr = edge->attributes;
if (edge->destination != NULL)
msg->remote_id = edge->destination->node->adv;
else
- msg->remote_id.origin = NONE;
+ msg->remote_id.origin = UNKNOWN;
return msg;
}
@@ -1162,34 +1542,189 @@ struct ls_message *ls_subnet2msg(struct ls_message *msg,
memset(msg, 0, sizeof(*msg));
msg->type = LS_MSG_TYPE_PREFIX;
+ switch (subnet->status) {
+ case NEW:
+ msg->event = LS_MSG_EVENT_ADD;
+ break;
+ case UPDATE:
+ msg->event = LS_MSG_EVENT_UPDATE;
+ break;
+ case DELETE:
+ msg->event = LS_MSG_EVENT_DELETE;
+ break;
+ case SYNC:
+ msg->event = LS_MSG_EVENT_SYNC;
+ break;
+ default:
+ msg->event = LS_MSG_EVENT_UNDEF;
+ break;
+ }
msg->data.prefix = subnet->ls_pref;
- msg->remote_id.origin = NONE;
+ msg->remote_id.origin = UNKNOWN;
return msg;
}
-void ls_delete_msg(struct ls_message *msg)
+struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg,
+ bool delete)
{
- if (msg == NULL)
- return;
+ struct ls_node *node = (struct ls_node *)msg->data.node;
+ struct ls_vertex *vertex = NULL;
+
+ switch (msg->event) {
+ case LS_MSG_EVENT_SYNC:
+ vertex = ls_vertex_add(ted, node);
+ if (vertex)
+ vertex->status = SYNC;
+ break;
+ case LS_MSG_EVENT_ADD:
+ vertex = ls_vertex_add(ted, node);
+ if (vertex)
+ vertex->status = NEW;
+ break;
+ case LS_MSG_EVENT_UPDATE:
+ vertex = ls_vertex_update(ted, node);
+ if (vertex)
+ vertex->status = UPDATE;
+ break;
+ case LS_MSG_EVENT_DELETE:
+ vertex = ls_find_vertex_by_id(ted, node->adv);
+ if (vertex) {
+ if (delete)
+ ls_vertex_del_all(ted, vertex);
+ else
+ vertex->status = DELETE;
+ }
+ break;
+ default:
+ vertex = NULL;
+ break;
+ }
+
+ return vertex;
+}
+
+struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg,
+ bool delete)
+{
+ struct ls_attributes *attr = (struct ls_attributes *)msg->data.attr;
+ struct ls_edge *edge = NULL;
+
+ switch (msg->event) {
+ case LS_MSG_EVENT_SYNC:
+ edge = ls_edge_add(ted, attr);
+ if (edge)
+ edge->status = SYNC;
+ break;
+ case LS_MSG_EVENT_ADD:
+ edge = ls_edge_add(ted, attr);
+ if (edge)
+ edge->status = NEW;
+ break;
+ case LS_MSG_EVENT_UPDATE:
+ edge = ls_edge_update(ted, attr);
+ if (edge)
+ edge->status = UPDATE;
+ break;
+ case LS_MSG_EVENT_DELETE:
+ edge = ls_find_edge_by_source(ted, attr);
+ if (edge) {
+ if (delete)
+ ls_edge_del_all(ted, edge);
+ else
+ edge->status = DELETE;
+ }
+ break;
+ default:
+ edge = NULL;
+ break;
+ }
+
+ return edge;
+}
+
+struct ls_subnet *ls_msg2subnet(struct ls_ted *ted, struct ls_message *msg,
+ bool delete)
+{
+ struct ls_prefix *pref = (struct ls_prefix *)msg->data.prefix;
+ struct ls_subnet *subnet = NULL;
+
+ switch (msg->event) {
+ case LS_MSG_EVENT_SYNC:
+ subnet = ls_subnet_add(ted, pref);
+ if (subnet)
+ subnet->status = SYNC;
+ break;
+ case LS_MSG_EVENT_ADD:
+ subnet = ls_subnet_add(ted, pref);
+ if (subnet)
+ subnet->status = NEW;
+ break;
+ case LS_MSG_EVENT_UPDATE:
+ subnet = ls_subnet_update(ted, pref);
+ if (subnet)
+ subnet->status = UPDATE;
+ break;
+ case LS_MSG_EVENT_DELETE:
+ subnet = ls_find_subnet(ted, pref->pref);
+ if (subnet) {
+ if (delete)
+ ls_subnet_del_all(ted, subnet);
+ else
+ subnet->status = DELETE;
+ }
+ break;
+ default:
+ subnet = NULL;
+ break;
+ }
+
+ return subnet;
+}
+
+struct ls_element *ls_msg2ted(struct ls_ted *ted, struct ls_message *msg,
+ bool delete)
+{
+ struct ls_element *lse = NULL;
switch (msg->type) {
case LS_MSG_TYPE_NODE:
- if (msg->data.node)
- XFREE(MTYPE_LS_DB, msg->data.node);
+ lse = (struct ls_element *)ls_msg2vertex(ted, msg, delete);
break;
case LS_MSG_TYPE_ATTRIBUTES:
- if (msg->data.attr)
- XFREE(MTYPE_LS_DB, msg->data.attr);
+ lse = (struct ls_element *)ls_msg2edge(ted, msg, delete);
break;
case LS_MSG_TYPE_PREFIX:
- if (msg->data.prefix)
- XFREE(MTYPE_LS_DB, msg->data.prefix);
+ lse = (struct ls_element *)ls_msg2subnet(ted, msg, delete);
break;
default:
+ lse = NULL;
break;
}
+ return lse;
+}
+
+struct ls_element *ls_stream2ted(struct ls_ted *ted, struct stream *s,
+ bool delete)
+{
+ struct ls_message *msg;
+ struct ls_element *lse = NULL;
+
+ msg = ls_parse_msg(s);
+ if (msg) {
+ lse = ls_msg2ted(ted, msg, delete);
+ ls_delete_msg(msg);
+ }
+
+ return lse;
+}
+
+void ls_delete_msg(struct ls_message *msg)
+{
+ if (msg == NULL)
+ return;
+
XFREE(MTYPE_LS_DB, msg);
}
@@ -1201,9 +1736,6 @@ int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient,
struct ls_subnet *subnet;
struct ls_message msg;
- /* Prepare message */
- msg.event = LS_MSG_EVENT_SYNC;
-
/* Loop TED, start sending Node, then Attributes and finally Prefix */
frr_each(vertices, &ted->vertices, vertex) {
ls_vertex2msg(&msg, vertex);
@@ -1220,33 +1752,696 @@ int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient,
return 0;
}
+/**
+ * Link State Show functions
+ */
+static const char *const origin2txt[] = {
+ "Unknown",
+ "ISIS_L1",
+ "ISIS_L2",
+ "OSPFv2",
+ "Direct",
+ "Static"
+};
+
+static const char *const type2txt[] = {
+ "Unknown",
+ "Standard",
+ "ABR",
+ "ASBR",
+ "Remote ASBR",
+ "Pseudo"
+};
+
+static const char *const status2txt[] = {
+ "Unknown",
+ "New",
+ "Update",
+ "Delete",
+ "Sync",
+ "Orphan"
+};
+
+static const char *ls_node_id_to_text(struct ls_node_id lnid, char *str,
+ size_t size)
+{
+ if (lnid.origin == ISIS_L1 || lnid.origin == ISIS_L2) {
+ uint8_t *id;
+
+ id = lnid.id.iso.sys_id;
+ snprintfrr(str, size, "%02x%02x.%02x%02x.%02x%02x", id[0],
+ id[1], id[2], id[3], id[4], id[5]);
+ } else
+ snprintfrr(str, size, "%pI4", &lnid.id.ip.addr);
+
+ return str;
+}
+
+static void ls_show_vertex_vty(struct ls_vertex *vertex, struct vty *vty,
+ bool verbose)
+{
+ struct listnode *node;
+ struct ls_node *lsn;
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+ struct sbuf sbuf;
+ uint32_t upper;
+
+ /* Sanity Check */
+ if (!vertex)
+ return;
+
+ lsn = vertex->node;
+
+ sbuf_init(&sbuf, NULL, 0);
+
+ sbuf_push(&sbuf, 2, "Vertex (%" PRIu64 "): %s", vertex->key, lsn->name);
+ sbuf_push(&sbuf, 0, "\tRouter Id: %pI4", &lsn->router_id);
+ sbuf_push(&sbuf, 0, "\tOrigin: %s", origin2txt[lsn->adv.origin]);
+ sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[vertex->status]);
+ if (!verbose) {
+ sbuf_push(
+ &sbuf, 0,
+ "\t%d Outgoing Edges, %d Incoming Edges, %d Subnets\n",
+ listcount(vertex->outgoing_edges),
+ listcount(vertex->incoming_edges),
+ listcount(vertex->prefixes));
+ goto end;
+ }
+
+ if (CHECK_FLAG(lsn->flags, LS_NODE_TYPE))
+ sbuf_push(&sbuf, 4, "Type: %s\n", type2txt[lsn->type]);
+ if (CHECK_FLAG(lsn->flags, LS_NODE_AS_NUMBER))
+ sbuf_push(&sbuf, 4, "AS number: %u\n", lsn->as_number);
+ if (CHECK_FLAG(lsn->flags, LS_NODE_SR)) {
+ sbuf_push(&sbuf, 4, "Segment Routing Capabilities:\n");
+ upper = lsn->srgb.lower_bound + lsn->srgb.range_size - 1;
+ sbuf_push(&sbuf, 8, "SRGB: [%d/%d]", lsn->srgb.lower_bound,
+ upper);
+ if (CHECK_FLAG(lsn->flags, LS_NODE_SRLB)) {
+ upper = lsn->srlb.lower_bound + lsn->srlb.range_size
+ - 1;
+ sbuf_push(&sbuf, 0, "\tSRLB: [%d/%d]",
+ lsn->srlb.lower_bound, upper);
+ }
+ sbuf_push(&sbuf, 0, "\tAlgo: ");
+ for (int i = 0; i < 2; i++) {
+ if (lsn->algo[i] == 255)
+ continue;
+
+ sbuf_push(&sbuf, 0,
+ lsn->algo[i] == 0 ? "SPF " : "S-SPF ");
+ }
+ if (CHECK_FLAG(lsn->flags, LS_NODE_MSD))
+ sbuf_push(&sbuf, 0, "\tMSD: %d", lsn->msd);
+ sbuf_push(&sbuf, 0, "\n");
+ }
+
+ sbuf_push(&sbuf, 4, "Outgoing Edges: %d\n",
+ listcount(vertex->outgoing_edges));
+ for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) {
+ if (edge->destination) {
+ lsn = edge->destination->node;
+ sbuf_push(&sbuf, 6, "To:\t%s(%pI4)", lsn->name,
+ &lsn->router_id);
+ } else {
+ sbuf_push(&sbuf, 6, "To:\t- (0.0.0.0)");
+ }
+ sbuf_push(&sbuf, 0, "\tLocal: %pI4\tRemote: %pI4\n",
+ &edge->attributes->standard.local,
+ &edge->attributes->standard.remote);
+ }
+
+ sbuf_push(&sbuf, 4, "Incoming Edges: %d\n",
+ listcount(vertex->incoming_edges));
+ for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, node, edge)) {
+ if (edge->source) {
+ lsn = edge->source->node;
+ sbuf_push(&sbuf, 6, "From:\t%s(%pI4)", lsn->name,
+ &lsn->router_id);
+ } else {
+ sbuf_push(&sbuf, 6, "From:\t- (0.0.0.0)");
+ }
+ sbuf_push(&sbuf, 0, "\tRemote: %pI4\tLocal: %pI4\n",
+ &edge->attributes->standard.local,
+ &edge->attributes->standard.remote);
+ }
+
+ sbuf_push(&sbuf, 4, "Subnets: %d\n", listcount(vertex->prefixes));
+ for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet))
+ sbuf_push(&sbuf, 6, "Prefix:\t%pFX\n", &subnet->key);
+
+end:
+ vty_out(vty, "%s\n", sbuf_buf(&sbuf));
+ sbuf_free(&sbuf);
+}
+
+static void ls_show_vertex_json(struct ls_vertex *vertex,
+ struct json_object *json)
+{
+ struct ls_node *lsn;
+ json_object *jsr, *jalgo, *jobj;
+ char buf[INET6_BUFSIZ];
+
+ /* Sanity Check */
+ if (!vertex)
+ return;
+
+ lsn = vertex->node;
+
+ json_object_int_add(json, "vertex-id", vertex->key);
+ json_object_string_add(json, "status", status2txt[vertex->status]);
+ json_object_string_add(json, "origin", origin2txt[lsn->adv.origin]);
+ if (CHECK_FLAG(lsn->flags, LS_NODE_NAME))
+ json_object_string_add(json, "name", lsn->name);
+ if (CHECK_FLAG(lsn->flags, LS_NODE_ROUTER_ID)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI4", &lsn->router_id);
+ json_object_string_add(json, "router-id", buf);
+ }
+ if (CHECK_FLAG(lsn->flags, LS_NODE_ROUTER_ID6)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI6", &lsn->router6_id);
+ json_object_string_add(json, "router-id-v6", buf);
+ }
+ if (CHECK_FLAG(lsn->flags, LS_NODE_TYPE))
+ json_object_string_add(json, "vertex-type",
+ type2txt[lsn->type]);
+ if (CHECK_FLAG(lsn->flags, LS_NODE_AS_NUMBER))
+ json_object_int_add(json, "asn", lsn->as_number);
+ if (CHECK_FLAG(lsn->flags, LS_NODE_SR)) {
+ jsr = json_object_new_object();
+ json_object_object_add(json, "segment-routing", jsr);
+ json_object_int_add(jsr, "srgb-size", lsn->srgb.range_size);
+ json_object_int_add(jsr, "srgb-lower", lsn->srgb.lower_bound);
+ jalgo = json_object_new_array();
+ json_object_object_add(jsr, "algorithms", jalgo);
+ for (int i = 0; i < 2; i++) {
+ if (lsn->algo[i] == 255)
+ continue;
+ jobj = json_object_new_object();
+
+ snprintfrr(buf, 2, "%u", i);
+ json_object_string_add(
+ jobj, buf, lsn->algo[i] == 0 ? "SPF" : "S-SPF");
+ json_object_array_add(jalgo, jobj);
+ }
+ if (CHECK_FLAG(lsn->flags, LS_NODE_SRLB)) {
+ json_object_int_add(jsr, "srlb-size",
+ lsn->srlb.range_size);
+ json_object_int_add(jsr, "srlb-lower",
+ lsn->srlb.lower_bound);
+ }
+ if (CHECK_FLAG(lsn->flags, LS_NODE_MSD))
+ json_object_int_add(jsr, "msd", lsn->msd);
+ }
+}
+
+void ls_show_vertex(struct ls_vertex *vertex, struct vty *vty,
+ struct json_object *json, bool verbose)
+{
+ if (json)
+ ls_show_vertex_json(vertex, json);
+ else if (vty)
+ ls_show_vertex_vty(vertex, vty, verbose);
+}
+
+void ls_show_vertices(struct ls_ted *ted, struct vty *vty,
+ struct json_object *json, bool verbose)
+{
+ struct ls_vertex *vertex;
+ json_object *jnodes, *jnode;
+
+ if (json) {
+ jnodes = json_object_new_array();
+ json_object_object_add(json, "vertices", jnodes);
+ frr_each (vertices, &ted->vertices, vertex) {
+ jnode = json_object_new_object();
+ ls_show_vertex(vertex, NULL, jnode, verbose);
+ json_object_array_add(jnodes, jnode);
+ }
+ } else if (vty) {
+ frr_each (vertices, &ted->vertices, vertex)
+ ls_show_vertex(vertex, vty, NULL, verbose);
+ }
+}
+
+static void ls_show_edge_vty(struct ls_edge *edge, struct vty *vty,
+ bool verbose)
+{
+ struct ls_attributes *attr;
+ struct sbuf sbuf;
+ char buf[INET6_BUFSIZ];
+
+ attr = edge->attributes;
+ sbuf_init(&sbuf, NULL, 0);
+
+ sbuf_push(&sbuf, 2, "Edge (%" PRIu64 "): ", edge->key);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR))
+ sbuf_push(&sbuf, 0, "%pI4", &attr->standard.local);
+ else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6))
+ sbuf_push(&sbuf, 0, "%pI6", &attr->standard.local6);
+ else
+ sbuf_push(&sbuf, 0, "%u/%u", attr->standard.local_id,
+ attr->standard.remote_id);
+ ls_node_id_to_text(attr->adv, buf, INET6_BUFSIZ);
+ sbuf_push(&sbuf, 0, "\tAdv. Vertex: %s", buf);
+ sbuf_push(&sbuf, 0, "\tMetric: %u", attr->metric);
+ sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[edge->status]);
+
+ if (!verbose)
+ goto end;
+
+ sbuf_push(&sbuf, 4, "Origin: %s\n", origin2txt[attr->adv.origin]);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NAME))
+ sbuf_push(&sbuf, 4, "Name: %s\n", attr->name);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
+ sbuf_push(&sbuf, 4, "TE Metric: %u\n",
+ attr->standard.te_metric);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
+ sbuf_push(&sbuf, 4, "Admin Group: 0x%x\n",
+ attr->standard.admin_group);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR))
+ sbuf_push(&sbuf, 4, "Local IPv4 address: %pI4\n",
+ &attr->standard.local);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR))
+ sbuf_push(&sbuf, 4, "Remote IPv4 address: %pI4\n",
+ &attr->standard.remote);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6))
+ sbuf_push(&sbuf, 4, "Local IPv6 address: %pI6\n",
+ &attr->standard.local6);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6))
+ sbuf_push(&sbuf, 4, "Remote IPv6 address: %pI6\n",
+ &attr->standard.remote6);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID))
+ sbuf_push(&sbuf, 4, "Local Identifier: %u\n",
+ attr->standard.local_id);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID))
+ sbuf_push(&sbuf, 4, "Remote Identifier: %u\n",
+ attr->standard.remote_id);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW))
+ sbuf_push(&sbuf, 4, "Maximum Bandwidth: %g (Bytes/s)\n",
+ attr->standard.max_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW))
+ sbuf_push(&sbuf, 4,
+ "Maximum Reservable Bandwidth: %g (Bytes/s)\n",
+ attr->standard.max_rsv_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) {
+ sbuf_push(&sbuf, 4, "Unreserved Bandwidth per Class Type\n");
+ for (int i = 0; i < MAX_CLASS_TYPE; i += 2)
+ sbuf_push(&sbuf, 8,
+ "[%d]: %g (Bytes/sec)\t[%d]: %g (Bytes/s)\n",
+ i, attr->standard.unrsv_bw[i], i + 1,
+ attr->standard.unrsv_bw[i + 1]);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS))
+ sbuf_push(&sbuf, 4, "Remote AS: %u\n",
+ attr->standard.remote_as);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR))
+ sbuf_push(&sbuf, 4, "Remote ASBR IPv4 address: %pI4\n",
+ &attr->standard.remote_addr);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6))
+ sbuf_push(&sbuf, 4, "Remote ASBR IPv6 address: %pI6\n",
+ &attr->standard.remote_addr6);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY))
+ sbuf_push(&sbuf, 4, "Average Link Delay: %d (micro-sec)\n",
+ attr->extended.delay);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY))
+ sbuf_push(&sbuf, 4, "Min/Max Link Delay: %d/%d (micro-sec)\n",
+ attr->extended.min_delay, attr->extended.max_delay);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER))
+ sbuf_push(&sbuf, 4, "Delay Variation: %d (micro-sec)\n",
+ attr->extended.jitter);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS))
+ sbuf_push(&sbuf, 4, "Link Loss: %g (%%)\n",
+ (float)(attr->extended.pkt_loss * LOSS_PRECISION));
+ if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW))
+ sbuf_push(&sbuf, 4, "Available Bandwidth: %g (Bytes/s)\n",
+ attr->extended.ava_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW))
+ sbuf_push(&sbuf, 4, "Residual Bandwidth: %g (Bytes/s)\n",
+ attr->extended.rsv_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW))
+ sbuf_push(&sbuf, 4, "Utilized Bandwidth: %g (Bytes/s)\n",
+ attr->extended.used_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) {
+ sbuf_push(&sbuf, 4, "Adjacency-SID: %u", attr->adj_sid[0].sid);
+ sbuf_push(&sbuf, 0, "\tFlags: 0x%x\tWeight: 0x%x\n",
+ attr->adj_sid[0].flags, attr->adj_sid[0].weight);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) {
+ sbuf_push(&sbuf, 4, "Bck. Adjacency-SID: %u",
+ attr->adj_sid[1].sid);
+ sbuf_push(&sbuf, 0, "\tFlags: 0x%x\tWeight: 0x%x\n",
+ attr->adj_sid[1].flags, attr->adj_sid[1].weight);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) {
+ sbuf_push(&sbuf, 4, "SRLGs: %d", attr->srlg_len);
+ for (int i = 1; i < attr->srlg_len; i++) {
+ if (i % 8)
+ sbuf_push(&sbuf, 8, "\n%u", attr->srlgs[i]);
+ else
+ sbuf_push(&sbuf, 8, ", %u", attr->srlgs[i]);
+ }
+ sbuf_push(&sbuf, 0, "\n");
+ }
+
+end:
+ vty_out(vty, "%s\n", sbuf_buf(&sbuf));
+ sbuf_free(&sbuf);
+}
+
+static void ls_show_edge_json(struct ls_edge *edge, struct json_object *json)
+{
+ struct ls_attributes *attr;
+ struct json_object *jte, *jbw, *jobj, *jsr = NULL, *jsrlg;
+ char buf[INET6_BUFSIZ];
+
+ attr = edge->attributes;
+
+ json_object_int_add(json, "edge-id", edge->key);
+ json_object_string_add(json, "status", status2txt[edge->status]);
+ json_object_string_add(json, "origin", origin2txt[attr->adv.origin]);
+ ls_node_id_to_text(attr->adv, buf, INET6_BUFSIZ);
+ json_object_string_add(json, "advertised-router", buf);
+ if (edge->source)
+ json_object_int_add(json, "local-vertex-id", edge->source->key);
+ if (edge->destination)
+ json_object_int_add(json, "remote-vertex-id",
+ edge->destination->key);
+ json_object_int_add(json, "metric", attr->metric);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NAME))
+ json_object_string_add(json, "name", attr->name);
+ jte = json_object_new_object();
+ json_object_object_add(json, "edge-attributes", jte);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
+ json_object_int_add(jte, "te-metric", attr->standard.te_metric);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
+ json_object_int_add(jte, "admin-group",
+ attr->standard.admin_group);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI4", &attr->standard.local);
+ json_object_string_add(jte, "local-address", buf);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI4", &attr->standard.remote);
+ json_object_string_add(jte, "remote-address", buf);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI6", &attr->standard.local6);
+ json_object_string_add(jte, "local-address-v6", buf);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI6", &attr->standard.remote6);
+ json_object_string_add(jte, "remote-address-v6", buf);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID))
+ json_object_int_add(jte, "local-identifier",
+ attr->standard.local_id);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID))
+ json_object_int_add(jte, "remote-identifier",
+ attr->standard.remote_id);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW))
+ json_object_double_add(jte, "max-link-bandwidth",
+ attr->standard.max_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW))
+ json_object_double_add(jte, "max-resv-link-bandwidth",
+ attr->standard.max_rsv_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) {
+ jbw = json_object_new_array();
+ json_object_object_add(jte, "unreserved-bandwidth", jbw);
+ for (int i = 0; i < MAX_CLASS_TYPE; i++) {
+ jobj = json_object_new_object();
+ snprintfrr(buf, 13, "class-type-%u", i);
+ json_object_double_add(jobj, buf,
+ attr->standard.unrsv_bw[i]);
+ json_object_array_add(jbw, jobj);
+ }
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS))
+ json_object_int_add(jte, "remote-asn",
+ attr->standard.remote_as);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI4",
+ &attr->standard.remote_addr);
+ json_object_string_add(jte, "remote-as-address", buf);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6)) {
+ snprintfrr(buf, INET6_BUFSIZ, "%pI6",
+ &attr->standard.remote_addr6);
+ json_object_string_add(jte, "remote-as-address-v6", buf);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY))
+ json_object_int_add(jte, "delay", attr->extended.delay);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) {
+ json_object_int_add(jte, "min-delay", attr->extended.min_delay);
+ json_object_int_add(jte, "max-delay", attr->extended.max_delay);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER))
+ json_object_int_add(jte, "jitter", attr->extended.jitter);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS))
+ json_object_double_add(
+ jte, "loss", attr->extended.pkt_loss * LOSS_PRECISION);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW))
+ json_object_double_add(jte, "available-bandwidth",
+ attr->extended.ava_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW))
+ json_object_double_add(jte, "residual-bandwidth",
+ attr->extended.rsv_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW))
+ json_object_double_add(jte, "utilized-bandwidth",
+ attr->extended.used_bw);
+ if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) {
+ jsrlg = json_object_new_array();
+ json_object_object_add(jte, "srlgs", jsrlg);
+ for (int i = 1; i < attr->srlg_len; i++) {
+ jobj = json_object_new_object();
+ json_object_int_add(jobj, "srlg", attr->srlgs[i]);
+ json_object_array_add(jsrlg, jobj);
+ }
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) {
+ jsr = json_object_new_array();
+ json_object_object_add(json, "segment-routing", jsr);
+ jobj = json_object_new_object();
+ json_object_int_add(jobj, "adj-sid", attr->adj_sid[0].sid);
+ snprintfrr(buf, 6, "0x%x", attr->adj_sid[0].flags);
+ json_object_string_add(jobj, "flags", buf);
+ json_object_int_add(jobj, "weight", attr->adj_sid[0].weight);
+ json_object_array_add(jsr, jobj);
+ }
+ if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) {
+ if (!jsr) {
+ jsr = json_object_new_array();
+ json_object_object_add(json, "segment-routing", jsr);
+ }
+ jobj = json_object_new_object();
+ json_object_int_add(jobj, "adj-sid", attr->adj_sid[1].sid);
+ snprintfrr(buf, 6, "0x%x", attr->adj_sid[1].flags);
+ json_object_string_add(jobj, "flags", buf);
+ json_object_int_add(jobj, "weight", attr->adj_sid[1].weight);
+ json_object_array_add(jsr, jobj);
+ }
+}
+
+void ls_show_edge(struct ls_edge *edge, struct vty *vty,
+ struct json_object *json, bool verbose)
+{
+ /* Sanity Check */
+ if (!edge)
+ return;
+
+ if (json)
+ ls_show_edge_json(edge, json);
+ else if (vty)
+ ls_show_edge_vty(edge, vty, verbose);
+}
+
+void ls_show_edges(struct ls_ted *ted, struct vty *vty,
+ struct json_object *json, bool verbose)
+{
+ struct ls_edge *edge;
+ json_object *jedges, *jedge;
+
+ if (json) {
+ jedges = json_object_new_array();
+ json_object_object_add(json, "edges", jedges);
+ frr_each (edges, &ted->edges, edge) {
+ jedge = json_object_new_object();
+ ls_show_edge(edge, NULL, jedge, verbose);
+ json_object_array_add(jedges, jedge);
+ }
+ } else if (vty) {
+ frr_each (edges, &ted->edges, edge)
+ ls_show_edge(edge, vty, NULL, verbose);
+ }
+}
+
+static void ls_show_subnet_vty(struct ls_subnet *subnet, struct vty *vty,
+ bool verbose)
+{
+ struct ls_prefix *pref;
+ struct sbuf sbuf;
+ char buf[INET6_BUFSIZ];
+
+ pref = subnet->ls_pref;
+ sbuf_init(&sbuf, NULL, 0);
+
+ sbuf_push(&sbuf, 2, "Subnet: %pFX", &subnet->key);
+ ls_node_id_to_text(pref->adv, buf, INET6_BUFSIZ);
+ sbuf_push(&sbuf, 0, "\tAdv. Vertex: %s", buf);
+ sbuf_push(&sbuf, 0, "\tMetric: %d", pref->metric);
+ sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[subnet->status]);
+
+ if (!verbose)
+ goto end;
+
+ sbuf_push(&sbuf, 4, "Origin: %s\n", origin2txt[pref->adv.origin]);
+ if (CHECK_FLAG(pref->flags, LS_PREF_IGP_FLAG))
+ sbuf_push(&sbuf, 4, "Flags: %d\n", pref->igp_flag);
+
+ if (CHECK_FLAG(pref->flags, LS_PREF_ROUTE_TAG))
+ sbuf_push(&sbuf, 4, "Tag: %d\n", pref->route_tag);
+
+ if (CHECK_FLAG(pref->flags, LS_PREF_EXTENDED_TAG))
+ sbuf_push(&sbuf, 4, "Extended Tag: %" PRIu64 "\n",
+ pref->extended_tag);
+
+ if (CHECK_FLAG(pref->flags, LS_PREF_SR))
+ sbuf_push(&sbuf, 4, "SID: %d\tAlgorithm: %d\tFlags: 0x%x\n",
+ pref->sr.sid, pref->sr.algo, pref->sr.sid_flag);
+
+end:
+ vty_out(vty, "%s\n", sbuf_buf(&sbuf));
+ sbuf_free(&sbuf);
+}
+
+static void ls_show_subnet_json(struct ls_subnet *subnet,
+ struct json_object *json)
+{
+ struct ls_prefix *pref;
+ json_object *jsr;
+ char buf[INET6_BUFSIZ];
+
+ pref = subnet->ls_pref;
+
+ snprintfrr(buf, INET6_BUFSIZ, "%pFX", &subnet->key);
+ json_object_string_add(json, "subnet-id", buf);
+ json_object_string_add(json, "status", status2txt[subnet->status]);
+ json_object_string_add(json, "origin", origin2txt[pref->adv.origin]);
+ ls_node_id_to_text(pref->adv, buf, INET6_BUFSIZ);
+ json_object_string_add(json, "advertised-router", buf);
+ if (subnet->vertex)
+ json_object_int_add(json, "vertex-id", subnet->vertex->key);
+ json_object_int_add(json, "metric", pref->metric);
+ if (CHECK_FLAG(pref->flags, LS_PREF_IGP_FLAG)) {
+ snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->igp_flag);
+ json_object_string_add(json, "flags", buf);
+ }
+ if (CHECK_FLAG(pref->flags, LS_PREF_ROUTE_TAG))
+ json_object_int_add(json, "tag", pref->route_tag);
+ if (CHECK_FLAG(pref->flags, LS_PREF_EXTENDED_TAG))
+ json_object_int_add(json, "extended-tag", pref->extended_tag);
+ if (CHECK_FLAG(pref->flags, LS_PREF_SR)) {
+ jsr = json_object_new_object();
+ json_object_object_add(json, "segment-routing", jsr);
+ json_object_int_add(jsr, "pref-sid", pref->sr.sid);
+ json_object_int_add(jsr, "algo", pref->sr.algo);
+ snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->sr.sid_flag);
+ json_object_string_add(jsr, "flags", buf);
+ }
+}
+
+void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty,
+ struct json_object *json, bool verbose)
+{
+ /* Sanity Check */
+ if (!subnet)
+ return;
+
+ if (json)
+ ls_show_subnet_json(subnet, json);
+ else if (vty)
+ ls_show_subnet_vty(subnet, vty, verbose);
+}
+
+void ls_show_subnets(struct ls_ted *ted, struct vty *vty,
+ struct json_object *json, bool verbose)
+{
+ struct ls_subnet *subnet;
+ json_object *jsubs, *jsub;
+
+ if (json) {
+ jsubs = json_object_new_array();
+ json_object_object_add(json, "subnets", jsubs);
+ frr_each (subnets, &ted->subnets, subnet) {
+ jsub = json_object_new_object();
+ ls_show_subnet(subnet, NULL, jsub, verbose);
+ json_object_array_add(jsubs, jsub);
+ }
+ } else if (vty) {
+ frr_each (subnets, &ted->subnets, subnet)
+ ls_show_subnet(subnet, vty, NULL, verbose);
+ }
+}
+
+void ls_show_ted(struct ls_ted *ted, struct vty *vty, struct json_object *json,
+ bool verbose)
+{
+ json_object *jted;
+
+ if (json) {
+ jted = json_object_new_object();
+ json_object_object_add(json, "ted", jted);
+ json_object_string_add(jted, "name", ted->name);
+ json_object_int_add(jted, "key", ted->key);
+ json_object_int_add(jted, "verticesCount",
+ vertices_count(&ted->vertices));
+ json_object_int_add(jted, "edgesCount",
+ edges_count(&ted->edges));
+ json_object_int_add(jted, "subnetsCount",
+ subnets_count(&ted->subnets));
+ ls_show_vertices(ted, NULL, jted, verbose);
+ ls_show_edges(ted, NULL, jted, verbose);
+ ls_show_subnets(ted, NULL, jted, verbose);
+ return;
+ }
+
+ if (vty) {
+ vty_out(vty,
+ "\n\tTraffic Engineering Database: %s (key: %d)\n\n",
+ ted->name, ted->key);
+ ls_show_vertices(ted, vty, NULL, verbose);
+ ls_show_edges(ted, vty, NULL, verbose);
+ ls_show_subnets(ted, vty, NULL, verbose);
+ vty_out(vty,
+ "\n\tTotal: %zu Vertices, %zu Edges, %zu Subnets\n\n",
+ vertices_count(&ted->vertices),
+ edges_count(&ted->edges), subnets_count(&ted->subnets));
+ }
+}
+
void ls_dump_ted(struct ls_ted *ted)
{
struct ls_vertex *vertex;
struct ls_edge *edge;
struct ls_subnet *subnet;
- struct ls_message msg;
+ const struct in_addr inaddr_any = {.s_addr = INADDR_ANY};
zlog_debug("(%s) Ted init", __func__);
- /* Prepare message */
- msg.event = LS_MSG_EVENT_SYNC;
/* Loop TED, start printing Node, then Attributes and finally Prefix */
- frr_each(vertices, &ted->vertices, vertex) {
- ls_vertex2msg(&msg, vertex);
+ frr_each (vertices, &ted->vertices, vertex) {
zlog_debug(" Ted node (%s %pI4 %s)",
vertex->node->name[0] ? vertex->node->name
: "no name node",
&vertex->node->router_id,
- vertex->node->adv.origin == DIRECT ? "DIRECT"
- : "NO DIRECT");
+ origin2txt[vertex->node->adv.origin]);
struct listnode *lst_node;
struct ls_edge *vertex_edge;
for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, lst_node,
vertex_edge)) {
zlog_debug(
- " inc edge key:%"PRIu64"n attr key:%pI4 loc:(%pI4) rmt:(%pI4)",
+ " inc edge key:%" PRIu64 " attr key:%pI4 loc:(%pI4) rmt:(%pI4)",
vertex_edge->key,
&vertex_edge->attributes->adv.id.ip.addr,
&vertex_edge->attributes->standard.local,
@@ -1255,29 +2450,25 @@ void ls_dump_ted(struct ls_ted *ted)
for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, lst_node,
vertex_edge)) {
zlog_debug(
- " out edge key:%"PRIu64" attr key:%pI4 loc:(%pI4) rmt:(%pI4)",
+ " out edge key:%" PRIu64 " attr key:%pI4 loc:(%pI4) rmt:(%pI4)",
vertex_edge->key,
&vertex_edge->attributes->adv.id.ip.addr,
&vertex_edge->attributes->standard.local,
&vertex_edge->attributes->standard.remote);
}
}
- frr_each(edges, &ted->edges, edge) {
- ls_edge2msg(&msg, edge);
- zlog_debug(" Ted edge key:%"PRIu64" src:%s dst:%s",
- edge->key,
- edge->source ? edge->source->node->name
- : "no_source",
- edge->destination ? edge->destination->node->name
- : "no_dest");
+ frr_each (edges, &ted->edges, edge) {
+ zlog_debug(" Ted edge key:%" PRIu64 "src:%pI4 dst:%pI4", edge->key,
+ edge->source ? &edge->source->node->router_id
+ : &inaddr_any,
+ edge->destination
+ ? &edge->destination->node->router_id
+ : &inaddr_any);
}
- frr_each(subnets, &ted->subnets, subnet) {
- ls_subnet2msg(&msg, subnet);
- zlog_debug(
- " Ted subnet key:%pFX vertex:%pI4 pfx:%pFX",
- &subnet->key,
- &subnet->vertex->node->adv.id.ip.addr,
- &subnet->ls_pref->pref);
+ frr_each (subnets, &ted->subnets, subnet) {
+ zlog_debug(" Ted subnet key:%pFX vertex:%pI4",
+ &subnet->ls_pref->pref,
+ &subnet->vertex->node->adv.id.ip.addr);
}
zlog_debug("(%s) Ted end", __func__);
}
diff --git a/lib/link_state.h b/lib/link_state.h
index f9eb59b76a..de116df89e 100644
--- a/lib/link_state.h
+++ b/lib/link_state.h
@@ -53,20 +53,26 @@ extern "C" {
* id for OSPF and the ISO System id plus the IS-IS level for IS-IS.
*/
+/* external reference */
+struct zapi_opaque_reg_info;
+struct zclient;
+
/* Link State Common definitions */
#define MAX_NAME_LENGTH 256
#define ISO_SYS_ID_LEN 6
/* Type of Node */
enum ls_node_type {
+ NONE = 0, /* Unknown */
STANDARD, /* a P or PE node */
ABR, /* an Array Border Node */
ASBR, /* an Autonomous System Border Node */
- PSEUDO, /* a Pseudo Node */
+ RMT_ASBR, /* Remote ASBR */
+ PSEUDO /* a Pseudo Node */
};
/* Origin of the Link State information */
-enum ls_origin {NONE = 0, ISIS_L1, ISIS_L2, OSPFv2, DIRECT, STATIC};
+enum ls_origin { UNKNOWN = 0, ISIS_L1, ISIS_L2, OSPFv2, DIRECT, STATIC };
/**
* Link State Node Identifier as:
@@ -108,19 +114,17 @@ struct ls_node {
struct in_addr router_id; /* IPv4 Router ID */
struct in6_addr router6_id; /* IPv6 Router ID */
uint8_t node_flag; /* IS-IS or OSPF Node flag */
- enum node_type type; /* Type of Node */
+ enum ls_node_type type; /* Type of Node */
uint32_t as_number; /* Local or neighbor AS number */
- struct { /* Segment Routing Global Block */
+ struct ls_srgb { /* Segment Routing Global Block */
uint32_t lower_bound; /* MPLS label lower bound */
uint32_t range_size; /* MPLS label range size */
uint8_t flag; /* IS-IS SRGB flags */
} srgb;
-#define LS_NODE_SRGB_SIZE 9
- struct { /* Segment Routing Local Block */
+ struct ls_srlb { /* Segment Routing Local Block */
uint32_t lower_bound; /* MPLS label lower bound */
uint32_t range_size; /* MPLS label range size */
} srlb;
-#define LS_NODE_SRLB_SIZE 8
uint8_t algo[2]; /* Segment Routing Algorithms */
uint8_t msd; /* Maximum Stack Depth */
};
@@ -150,17 +154,17 @@ struct ls_node {
#define LS_ATTR_AVA_BW 0x00100000
#define LS_ATTR_RSV_BW 0x00200000
#define LS_ATTR_USE_BW 0x00400000
-#define LS_ATTR_ADJ_SID 0x00800000
-#define LS_ATTR_BCK_ADJ_SID 0x01000000
-#define LS_ATTR_SRLG 0x02000000
+#define LS_ATTR_ADJ_SID 0x01000000
+#define LS_ATTR_BCK_ADJ_SID 0x02000000
+#define LS_ATTR_SRLG 0x10000000
/* Link State Attributes */
struct ls_attributes {
uint32_t flags; /* Flag for parameters validity */
struct ls_node_id adv; /* Adv. Router of this Link State */
char name[MAX_NAME_LENGTH]; /* Name of the Edge. Could be null */
- struct { /* Standard TE metrics */
- uint32_t metric; /* IGP standard metric */
+ uint32_t metric; /* IGP standard metric */
+ struct ls_standard { /* Standard TE metrics */
uint32_t te_metric; /* Traffic Engineering metric */
uint32_t admin_group; /* Administrative Group */
struct in_addr local; /* Local IPv4 address */
@@ -176,8 +180,7 @@ struct ls_attributes {
struct in_addr remote_addr; /* Remote IPv4 address */
struct in6_addr remote_addr6; /* Remote IPv6 address */
} standard;
-#define LS_ATTR_STANDARD_SIZE 124
- struct { /* Extended TE Metrics */
+ struct ls_extended { /* Extended TE Metrics */
uint32_t delay; /* Unidirectional average delay */
uint32_t min_delay; /* Unidirectional minimum delay */
uint32_t max_delay; /* Unidirectional maximum delay */
@@ -187,8 +190,7 @@ struct ls_attributes {
float rsv_bw; /* Reserved Bandwidth */
float used_bw; /* Utilized Bandwidth */
} extended;
-#define LS_ATTR_EXTENDED_SIZE 32
- struct { /* (LAN)-Adjacency SID for OSPF */
+ struct ls_adjacency { /* (LAN)-Adjacency SID for OSPF */
uint32_t sid; /* SID as MPLS label or index */
uint8_t flags; /* Flags */
uint8_t weight; /* Administrative weight */
@@ -197,7 +199,6 @@ struct ls_attributes {
uint8_t sysid[ISO_SYS_ID_LEN]; /* or Sys-ID for ISIS */
} neighbor;
} adj_sid[2]; /* Primary & Backup (LAN)-Adj. SID */
-#define LS_ATTR_ADJ_SID_SIZE 120
uint32_t *srlgs; /* List of Shared Risk Link Group */
uint8_t srlg_len; /* number of SRLG in the list */
};
@@ -219,7 +220,7 @@ struct ls_prefix {
uint32_t route_tag; /* IGP Route Tag */
uint64_t extended_tag; /* IGP Extended Route Tag */
uint32_t metric; /* Route metric for this prefix */
- struct {
+ struct ls_sid {
uint32_t sid; /* Segment Routing ID */
uint8_t sid_flag; /* Segment Routing Flags */
uint8_t algo; /* Algorithm for Segment Routing */
@@ -273,9 +274,16 @@ extern struct ls_attributes *ls_attributes_new(struct ls_node_id adv,
uint32_t local_id);
/**
+ * Remove SRLGs from Link State Attributes if defined.
+ *
+ * @param attr Pointer to a valid Link State Attribute structure
+ */
+extern void ls_attributes_srlg_del(struct ls_attributes *attr);
+
+/**
* Remove Link State Attributes. Data structure is freed.
*
- * @param attr Pointer to a valid Link State Attribute structure
+ * @param attr Pointer to a valid Link State Attribute structure
*/
extern void ls_attributes_del(struct ls_attributes *attr);
@@ -292,6 +300,34 @@ extern int ls_attributes_same(struct ls_attributes *a1,
struct ls_attributes *a2);
/**
+ * Create a new Link State Prefix. Structure is dynamically allocated.
+ *
+ * @param adv Mandatory Link State Node ID i.e. advertise router ID
+ * @param p Mandatory Prefix
+ *
+ * @return New Link State Prefix
+ */
+extern struct ls_prefix *ls_prefix_new(struct ls_node_id adv, struct prefix p);
+
+/**
+ * Remove Link State Prefix. Data Structure is freed.
+ *
+ * @param pref Pointer to a valid Link State Attribute Prefix.
+ */
+extern void ls_prefix_del(struct ls_prefix *pref);
+
+/**
+ * Check if two Link State Prefix are equal. Note that this routine has the
+ * same return value sense as '==' (which is different from a comparison).
+ *
+ * @param p1 First Link State Prefix to be compare
+ * @param p2 Second Link State Prefix to be compare
+ *
+ * @return 1 if equal, 0 otherwise
+ */
+extern int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2);
+
+/**
* In addition a Graph model is defined as an overlay on top of link state
* database in order to ease Path Computation algorithm implementation.
* Denoted G(V, E), a graph is composed by a list of Vertices (V) which
@@ -323,9 +359,14 @@ extern int ls_attributes_same(struct ls_attributes *a1,
*
*/
+enum ls_status { UNSET = 0, NEW, UPDATE, DELETE, SYNC, ORPHAN };
+enum ls_type { GENERIC = 0, VERTEX, EDGE, SUBNET };
+
/* Link State Vertex structure */
PREDECL_RBTREE_UNIQ(vertices);
struct ls_vertex {
+ enum ls_type type; /* Link State Type */
+ enum ls_status status; /* Status of the Vertex in the TED */
struct vertices_item entry; /* Entry in RB Tree */
uint64_t key; /* Unique Key identifier */
struct ls_node *node; /* Link State Node */
@@ -337,6 +378,8 @@ struct ls_vertex {
/* Link State Edge structure */
PREDECL_RBTREE_UNIQ(edges);
struct ls_edge {
+ enum ls_type type; /* Link State Type */
+ enum ls_status status; /* Status of the Edge in the TED */
struct edges_item entry; /* Entry in RB tree */
uint64_t key; /* Unique Key identifier */
struct ls_attributes *attributes; /* Link State attributes */
@@ -347,10 +390,12 @@ struct ls_edge {
/* Link State Subnet structure */
PREDECL_RBTREE_UNIQ(subnets);
struct ls_subnet {
+ enum ls_type type; /* Link State Type */
+ enum ls_status status; /* Status of the Subnet in the TED */
struct subnets_item entry; /* Entry in RB tree */
struct prefix key; /* Unique Key identifier */
- struct ls_vertex *vertex; /* Back pointer to the Vertex owner */
struct ls_prefix *ls_pref; /* Link State Prefix */
+ struct ls_vertex *vertex; /* Back pointer to the Vertex owner */
};
/* Declaration of Vertices, Edges and Prefixes RB Trees */
@@ -386,37 +431,45 @@ struct ls_ted {
struct subnets_head subnets; /* List of Subnets */
};
+/* Generic Link State Element */
+struct ls_element {
+ enum ls_type type; /* Link State Element Type */
+ enum ls_status status; /* Link State Status in the TED */
+ void *data; /* Link State payload */
+};
+
/**
- * Create a new Link State Vertex structure and initialize is with the Link
- * State Node parameter.
+ * Add new vertex to the Link State DB. Vertex is created from the Link State
+ * Node. Vertex data structure is dynamically allocated.
*
+ * @param ted Traffic Engineering Database structure
* @param node Link State Node
*
- * @return New Vertex
+ * @return New Vertex or NULL in case of error
*/
-extern struct ls_vertex *ls_vertex_new(struct ls_node *node);
+extern struct ls_vertex *ls_vertex_add(struct ls_ted *ted,
+ struct ls_node *node);
/**
* Delete Link State Vertex. This function clean internal Vertex lists (incoming
- * and outgoing Link State Edge and Link State Subnet). Note that referenced
- * objects of the different lists (Edges & SubNet) are not removed as they could
- * be connected to other Vertices.
+ * and outgoing Link State Edge and Link State Subnet). Vertex Data structure
+ * is freed but not the Link State Node. Link State DB is not modified if Vertex
+ * is NULL or not found in the Data Base. Note that referenced to Link State
+ * Edges & SubNets are not removed as they could be connected to other Vertices.
*
+ * @param ted Traffic Engineering Database structure
* @param vertex Link State Vertex to be removed
*/
-extern void ls_vertex_del(struct ls_vertex *vertex);
+extern void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex);
/**
- * Add new vertex to the Link State DB. Vertex is created from the Link State
- * Node. Vertex data structure is dynamically allocated.
+ * Delete Link State Vertex as ls_vertex_del() but also removed associated
+ * Link State Node.
*
- * @param ted Traffic Engineering Database structure
- * @param node Link State Node
- *
- * @return New Vertex or NULL in case of error
+ * @param ted Traffic Engineering Database structure
+ * @param vertex Link State Vertex to be removed
*/
-extern struct ls_vertex *ls_vertex_add(struct ls_ted *ted,
- struct ls_node *node);
+extern void ls_vertex_del_all(struct ls_ted *ted, struct ls_vertex *vertex);
/**
* Update Vertex with the Link State Node. A new vertex is created if no one
@@ -431,15 +484,15 @@ extern struct ls_vertex *ls_vertex_update(struct ls_ted *ted,
struct ls_node *node);
/**
- * Remove Vertex from the Link State DB. Vertex Data structure is freed but
- * not the Link State Node. Link State DB is not modified if Vertex is NULL or
- * not found in the Data Base.
+ * Clean Vertex structure by removing all Edges and Subnets marked as ORPHAN
+ * from this vertex. Link State Update message is sent if zclient is not NULL.
*
* @param ted Link State Data Base
- * @param vertex Vertex to be removed
+ * @param vertex Link State Vertex to be cleaned
+ * @param zclient Reference to Zebra Client
*/
-extern void ls_vertex_remove(struct ls_ted *ted, struct ls_vertex *vertex);
-
+extern void ls_vertex_clean(struct ls_ted *ted, struct ls_vertex *vertex,
+ struct zclient *zclient);
/**
* Find Vertex in the Link State DB by its unique key.
*
@@ -498,6 +551,17 @@ extern struct ls_edge *ls_edge_update(struct ls_ted *ted,
struct ls_attributes *attributes);
/**
+ * Check if two Edges are equal. Note that this routine has the same return
+ * value sense as '==' (which is different from a comparison).
+ *
+ * @param e1 First edge to compare
+ * @param e2 Second edge to compare
+ *
+ * @return 1 if equal, 0 otherwise
+ */
+extern int ls_edge_same(struct ls_edge *e1, struct ls_edge *e2);
+
+/**
* Remove Edge from the Link State DB. Edge data structure is freed but not the
* Link State Attributes data structure. Link State DB is not modified if Edge
* is NULL or not found in the Data Base.
@@ -508,6 +572,15 @@ extern struct ls_edge *ls_edge_update(struct ls_ted *ted,
extern void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge);
/**
+ * Remove Edge and associated Link State Attributes from the Link State DB.
+ * Link State DB is not modified if Edge is NULL or not found.
+ *
+ * @param ted Link State Data Base
+ * @param edge Edge to be removed
+ */
+extern void ls_edge_del_all(struct ls_ted *ted, struct ls_edge *edge);
+
+/**
* Find Edge in the Link State Data Base by Edge key.
*
* @param ted Link State Data Base
@@ -520,8 +593,7 @@ extern struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted,
/**
* Find Edge in the Link State Data Base by the source (local IPv4 or IPv6
- * address or local ID) informations of the Link
- * State Attributes
+ * address or local ID) informations of the Link State Attributes
*
* @param ted Link State Data Base
* @param attributes Link State Attributes
@@ -557,6 +629,29 @@ extern struct ls_subnet *ls_subnet_add(struct ls_ted *ted,
struct ls_prefix *pref);
/**
+ * Update the Link State Prefix information of an existing Subnet. If there is
+ * no corresponding Subnet in the Link State Data Base, a new Subnet is created.
+ *
+ * @param ted Link State Data Base
+ * @param pref Link State Prefix
+ *
+ * @return Updated Link State Subnet, or NULL in case of error
+ */
+extern struct ls_subnet *ls_subnet_update(struct ls_ted *ted,
+ struct ls_prefix *pref);
+
+/**
+ * Check if two Subnets are equal. Note that this routine has the same return
+ * value sense as '==' (which is different from a comparison).
+ *
+ * @param s1 First subnet to compare
+ * @param s2 Second subnet to compare
+ *
+ * @return 1 if equal, 0 otherwise
+ */
+extern int ls_subnet_same(struct ls_subnet *s1, struct ls_subnet *s2);
+
+/**
* Remove Subnet from the Link State DB. Subnet data structure is freed but
* not the Link State prefix data structure. Link State DB is not modified
* if Subnet is NULL or not found in the Data Base.
@@ -567,6 +662,15 @@ extern struct ls_subnet *ls_subnet_add(struct ls_ted *ted,
extern void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet);
/**
+ * Remove Subnet and the associated Link State Prefix from the Link State DB.
+ * Link State DB is not modified if Subnet is NULL or not found.
+ *
+ * @param ted Link State Data Base
+ * @param subnet Subnet to be removed
+ */
+extern void ls_subnet_del_all(struct ls_ted *ted, struct ls_subnet *subnet);
+
+/**
* Find Subnet in the Link State Data Base by prefix.
*
* @param ted Link State Data Base
@@ -582,7 +686,7 @@ extern struct ls_subnet *ls_find_subnet(struct ls_ted *ted,
*
* @param key Unique key of the data base. Must be different from 0
* @param name Name of the data base (may be NULL)
- * @param asn AS Number for this data base. Must be different from 0
+ * @param asn AS Number for this data base. 0 if unknown
*
* @return New Link State Database or NULL in case of error
*/
@@ -590,13 +694,29 @@ extern struct ls_ted *ls_ted_new(const uint32_t key, const char *name,
uint32_t asn);
/**
- * Delete existing Link State Data Base.
+ * Delete existing Link State Data Base. Vertices, Edges, and Subnets are not
+ * removed.
*
* @param ted Link State Data Base
*/
extern void ls_ted_del(struct ls_ted *ted);
/**
+ * Delete all Link State Vertices, Edges and SubNets and the Link State DB.
+ *
+ * @param ted Link State Data Base
+ */
+extern void ls_ted_del_all(struct ls_ted *ted);
+
+/**
+ * Clean Link State Data Base by removing all Vertices, Edges and SubNets marked
+ * as ORPHAN.
+ *
+ * @param ted Link State Data Base
+ */
+extern void ls_ted_clean(struct ls_ted *ted);
+
+/**
* Connect Source and Destination Vertices by given Edge. Only non NULL source
* and destination vertices are connected.
*
@@ -657,6 +777,7 @@ extern void ls_disconnect_edge(struct ls_edge *edge);
*/
/* ZAPI Opaque Link State Message Event */
+#define LS_MSG_EVENT_UNDEF 0
#define LS_MSG_EVENT_SYNC 1
#define LS_MSG_EVENT_ADD 2
#define LS_MSG_EVENT_UPDATE 3
@@ -680,6 +801,35 @@ struct ls_message {
};
/**
+ * Register Link State daemon as a server or client for Zebra OPAQUE API.
+ *
+ * @param zclient Zebra client structure
+ * @param server Register daemon as a server (true) or as a client (false)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+extern int ls_register(struct zclient *zclient, bool server);
+
+/**
+ * Unregister Link State daemon as a server or client for Zebra OPAQUE API.
+ *
+ * @param zclient Zebra client structure
+ * @param server Unregister daemon as a server (true) or as a client (false)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+extern int ls_unregister(struct zclient *zclient, bool server);
+
+/**
+ * Send Link State SYNC message to request the complete Link State Database.
+ *
+ * @param zclient Zebra client
+ *
+ * @return 0 if success, -1 otherwise
+ */
+extern int ls_request_sync(struct zclient *zclient);
+
+/**
* Parse Link State Message from stream. Used this function once receiving a
* new ZAPI Opaque message of type Link State.
*
@@ -690,7 +840,7 @@ struct ls_message {
extern struct ls_message *ls_parse_msg(struct stream *s);
/**
- * Delete existing message, freeing all substructure.
+ * Delete existing message. Data structure is freed.
*
* @param msg Link state message to be deleted
*/
@@ -751,6 +901,81 @@ extern struct ls_message *ls_subnet2msg(struct ls_message *msg,
struct ls_subnet *subnet);
/**
+ * Convert Link State Message into Vertex and update TED accordingly to
+ * the message event: SYNC, ADD, UPDATE or DELETE.
+ *
+ * @param ted Link State Database
+ * @param msg Link State Message
+ * @param delete True to delete the Link State Vertex from the Database,
+ * False otherwise. If true, return value is NULL in case
+ * of deletion.
+ *
+ * @return Vertex if success, NULL otherwise or if Vertex is removed
+ */
+extern struct ls_vertex *ls_msg2vertex(struct ls_ted *ted,
+ struct ls_message *msg, bool delete);
+
+/**
+ * Convert Link State Message into Edge and update TED accordingly to
+ * the message event: SYNC, ADD, UPDATE or DELETE.
+ *
+ * @param ted Link State Database
+ * @param msg Link State Message
+ * @param delete True to delete the Link State Edge from the Database,
+ * False otherwise. If true, return value is NULL in case
+ * of deletion.
+ *
+ * @return Edge if success, NULL otherwise or if Edge is removed
+ */
+extern struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg,
+ bool delete);
+
+/**
+ * Convert Link State Message into Subnet and update TED accordingly to
+ * the message event: SYNC, ADD, UPDATE or DELETE.
+ *
+ * @param ted Link State Database
+ * @param msg Link State Message
+ * @param delete True to delete the Link State Subnet from the Database,
+ * False otherwise. If true, return value is NULL in case
+ * of deletion.
+ *
+ * @return Subnet if success, NULL otherwise or if Subnet is removed
+ */
+extern struct ls_subnet *ls_msg2subnet(struct ls_ted *ted,
+ struct ls_message *msg, bool delete);
+
+/**
+ * Convert Link State Message into Link State element (Vertex, Edge or Subnet)
+ * and update TED accordingly to the message event: SYNC, ADD, UPDATE or DELETE.
+ *
+ * @param ted Link State Database
+ * @param msg Link State Message
+ * @param delete True to delete the Link State Element from the Database,
+ * False otherwise. If true, return value is NULL in case
+ * of deletion.
+ *
+ * @return Element if success, NULL otherwise or if Element is removed
+ */
+extern struct ls_element *ls_msg2ted(struct ls_ted *ted, struct ls_message *msg,
+ bool delete);
+
+/**
+ * Convert stream buffer into Link State element (Vertex, Edge or Subnet) and
+ * update TED accordingly to the message event: SYNC, ADD, UPDATE or DELETE.
+ *
+ * @param ted Link State Database
+ * @param s Stream buffer
+ * @param delete True to delete the Link State Element from the Database,
+ * False otherwise. If true, return value is NULL in case
+ * of deletion.
+ *
+ * @return Element if success, NULL otherwise or if Element is removed
+ */
+extern struct ls_element *ls_stream2ted(struct ls_ted *ted, struct stream *s,
+ bool delete);
+
+/**
* Send all the content of the Link State Data Base to the given destination.
* Link State content is sent is this order: Vertices, Edges, Subnet.
* This function must be used when a daemon request a Link State Data Base
@@ -765,6 +990,92 @@ extern struct ls_message *ls_subnet2msg(struct ls_message *msg,
extern int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient,
struct zapi_opaque_reg_info *dst);
+struct json_object;
+struct vty;
+/**
+ * Show Link State Vertex information. If both vty and json are specified,
+ * Json format output supersedes standard vty output.
+ *
+ * @param vertex Link State Vertex to show. Must not be NULL
+ * @param vty Pointer to vty output, could be NULL
+ * @param json Pointer to json output, could be NULL
+ * @param verbose Set to true for more detail
+ */
+extern void ls_show_vertex(struct ls_vertex *vertex, struct vty *vty,
+ struct json_object *json, bool verbose);
+
+/**
+ * Show all Link State Vertices information. If both vty and json are specified,
+ * Json format output supersedes standard vty output.
+ *
+ * @param ted Link State Data Base. Must not be NULL
+ * @param vty Pointer to vty output, could be NULL
+ * @param json Pointer to json output, could be NULL
+ * @param verbose Set to true for more detail
+ */
+extern void ls_show_vertices(struct ls_ted *ted, struct vty *vty,
+ struct json_object *json, bool verbose);
+
+/**
+ * Show Link State Edge information. If both vty and json are specified,
+ * Json format output supersedes standard vty output.
+ *
+ * @param edge Link State Edge to show. Must not be NULL
+ * @param vty Pointer to vty output, could be NULL
+ * @param json Pointer to json output, could be NULL
+ * @param verbose Set to true for more detail
+ */
+extern void ls_show_edge(struct ls_edge *edge, struct vty *vty,
+ struct json_object *json, bool verbose);
+
+/**
+ * Show all Link State Edges information. If both vty and json are specified,
+ * Json format output supersedes standard vty output.
+ *
+ * @param ted Link State Data Base. Must not be NULL
+ * @param vty Pointer to vty output, could be NULL
+ * @param json Pointer to json output, could be NULL
+ * @param verbose Set to true for more detail
+ */
+extern void ls_show_edges(struct ls_ted *ted, struct vty *vty,
+ struct json_object *json, bool verbose);
+
+/**
+ * Show Link State Subnets information. If both vty and json are specified,
+ * Json format output supersedes standard vty output.
+ *
+ * @param subnet Link State Subnet to show. Must not be NULL
+ * @param vty Pointer to vty output, could be NULL
+ * @param json Pointer to json output, could be NULL
+ * @param verbose Set to true for more detail
+ */
+extern void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty,
+ struct json_object *json, bool verbose);
+
+/**
+ * Show all Link State Subnet information. If both vty and json are specified,
+ * Json format output supersedes standard vty output.
+ *
+ * @param ted Link State Data Base. Must not be NULL
+ * @param vty Pointer to vty output, could be NULL
+ * @param json Pointer to json output, could be NULL
+ * @param verbose Set to true for more detail
+ */
+extern void ls_show_subnets(struct ls_ted *ted, struct vty *vty,
+ struct json_object *json, bool verbose);
+
+/**
+ * Show Link State Data Base information. If both vty and json are specified,
+ * Json format output supersedes standard vty output.
+ *
+ * @param ted Link State Data Base to show. Must not be NULL
+ * @param vty Pointer to vty output, could be NULL
+ * @param json Pointer to json output, could be NULL
+ * @param verbose Set to true for more detail
+ */
+extern void ls_show_ted(struct ls_ted *ted, struct vty *vty,
+ struct json_object *json, bool verbose);
+
/**
* Dump all Link State Data Base elements for debugging purposes
*
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 17ef95c687..8439398149 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -730,80 +730,99 @@ int nexthop_str2backups(const char *str, int *num_backups,
* nexthop2str()
*/
printfrr_ext_autoreg_p("NH", printfrr_nh)
-static ssize_t printfrr_nh(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
const struct nexthop *nexthop = ptr;
- struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 };
bool do_ifi = false;
- const char *s, *v_is = "", *v_via = "", *v_viaif = "via ";
- ssize_t ret = 3;
+ const char *v_is = "", *v_via = "", *v_viaif = "via ";
+ ssize_t ret = 0;
- /* NULL-check */
- if (nexthop == NULL) {
- if (fmt[2] == 'v' && fmt[3] == 'v')
- ret++;
-
- strlcpy(buf, "NULL", bsz);
-
- return ret;
- }
-
- switch (fmt[2]) {
+ switch (*ea->fmt) {
case 'v':
- if (fmt[3] == 'v') {
+ ea->fmt++;
+ if (*ea->fmt == 'v') {
v_is = "is ";
v_via = "via ";
v_viaif = "";
- ret++;
+ ea->fmt++;
}
+ if (!nexthop)
+ return bputs(buf, "(null)");
+
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- bprintfrr(&fb, "%s%pI4", v_via, &nexthop->gate.ipv4);
+ ret += bprintfrr(buf, "%s%pI4", v_via,
+ &nexthop->gate.ipv4);
do_ifi = true;
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- bprintfrr(&fb, "%s%pI6", v_via, &nexthop->gate.ipv6);
+ ret += bprintfrr(buf, "%s%pI6", v_via,
+ &nexthop->gate.ipv6);
do_ifi = true;
break;
case NEXTHOP_TYPE_IFINDEX:
- bprintfrr(&fb, "%sdirectly connected, %s", v_is,
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
+ ret += bprintfrr(buf, "%sdirectly connected, %s", v_is,
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
+ ret += bputs(buf, "unreachable");
+
switch (nexthop->bh_type) {
case BLACKHOLE_REJECT:
- s = " (ICMP unreachable)";
+ ret += bputs(buf, " (ICMP unreachable)");
break;
case BLACKHOLE_ADMINPROHIB:
- s = " (ICMP admin-prohibited)";
+ ret += bputs(buf, " (ICMP admin-prohibited)");
break;
case BLACKHOLE_NULL:
- s = " (blackhole)";
+ ret += bputs(buf, " (blackhole)");
break;
default:
- s = "";
break;
}
- bprintfrr(&fb, "unreachable%s", s);
break;
default:
break;
}
if (do_ifi && nexthop->ifindex)
- bprintfrr(&fb, ", %s%s", v_viaif, ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
+ ret += bprintfrr(buf, ", %s%s", v_viaif,
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
- *fb.pos = '\0';
return ret;
case 's':
- nexthop2str(nexthop, buf, bsz);
- return 3;
+ ea->fmt++;
+
+ if (!nexthop)
+ return bputs(buf, "(null)");
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ ret += bprintfrr(buf, "if %u", nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ ret += bprintfrr(buf, "%pI4 if %u", &nexthop->gate.ipv4,
+ nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ ret += bprintfrr(buf, "%pI6 if %u", &nexthop->gate.ipv6,
+ nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ ret += bputs(buf, "blackhole");
+ break;
+ default:
+ ret += bputs(buf, "unknown");
+ break;
+ }
+ return ret;
}
- return 0;
+ return -1;
}
diff --git a/lib/northbound.h b/lib/northbound.h
index 21aad64a09..417ecc81ea 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -474,6 +474,23 @@ struct nb_callbacks {
int (*rpc)(struct nb_cb_rpc_args *args);
/*
+ * Optional callback to compare the data nodes when printing
+ * the CLI commands associated with them.
+ *
+ * dnode1
+ * The first data node to compare.
+ *
+ * dnode2
+ * The second data node to compare.
+ *
+ * Returns:
+ * <0 when the CLI command for the dnode1 should be printed first
+ * >0 when the CLI command for the dnode2 should be printed first
+ * 0 when there is no difference
+ */
+ int (*cli_cmp)(struct lyd_node *dnode1, struct lyd_node *dnode2);
+
+ /*
* Optional callback to show the CLI command associated to the given
* YANG data node.
*
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index a2c8bc8633..f88c2161da 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -529,25 +529,6 @@ static int nb_cli_candidate_load_transaction(struct vty *vty,
return CMD_SUCCESS;
}
-/*
- * ly_iter_next_is_up: detects when iterating up on the yang model.
- *
- * This function detects whether next node in the iteration is upwards,
- * then return the node otherwise return NULL.
- */
-static struct lyd_node *ly_iter_next_up(const struct lyd_node *elem)
-{
- /* Are we going downwards? Is this still not a leaf? */
- if (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)))
- return NULL;
-
- /* Are there still leaves in this branch? */
- if (elem->next != NULL)
- return NULL;
-
- return elem->parent;
-}
-
/* Prepare the configuration for display. */
void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults)
{
@@ -569,53 +550,80 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults)
ly_native_ctx);
}
-void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
- bool with_defaults)
+static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
+ bool with_defaults)
{
- struct lyd_node *next, *child, *parent;
-
- LY_TREE_DFS_BEGIN (root, next, child) {
- struct nb_node *nb_node;
+ struct nb_node *nb_node, *sort_node = NULL;
+ struct listnode *listnode;
+ struct lyd_node *child;
+ struct list *sort_list;
+ void *data;
+ LY_TREE_FOR (root->child, child) {
nb_node = child->schema->priv;
- if (!nb_node || !nb_node->cbs.cli_show)
- goto next;
- /* Skip default values. */
- if (!with_defaults && yang_dnode_is_default_recursive(child))
- goto next;
-
- (*nb_node->cbs.cli_show)(vty, child, with_defaults);
- next:
/*
- * When transiting upwards in the yang model we should
- * give the previous container/list node a chance to
- * print its close vty output (e.g. "!" or "end-family"
- * etc...).
+ * We finished processing current list,
+ * it's time to print the config.
*/
- parent = ly_iter_next_up(child);
- if (parent != NULL) {
- nb_node = parent->schema->priv;
- if (nb_node && nb_node->cbs.cli_show_end)
- (*nb_node->cbs.cli_show_end)(vty, parent);
+ if (sort_node && nb_node != sort_node) {
+ for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data))
+ nb_cli_show_dnode_cmds(vty, data,
+ with_defaults);
+
+ list_delete(&sort_list);
+ sort_node = NULL;
}
/*
- * There is a possible path in this macro that ends up
- * dereferencing child->parent->parent. We just null checked
- * child->parent by checking (ly_iter_next_up(child) != NULL)
- * above.
- *
- * I am not sure whether it is possible for the other
- * conditions within this macro guarding the problem
- * dereference to be satisfied when child->parent == NULL.
+ * If the config needs to be sorted,
+ * then add the dnode to the sorting
+ * list for later processing.
*/
-#ifndef __clang_analyzer__
- LY_TREE_DFS_END(root, next, child);
-#endif
+ if (nb_node && nb_node->cbs.cli_cmp) {
+ if (!sort_node) {
+ sort_node = nb_node;
+ sort_list = list_new();
+ sort_list->cmp = (int (*)(void *, void *))
+ nb_node->cbs.cli_cmp;
+ }
+
+ listnode_add_sort(sort_list, child);
+ continue;
+ }
+
+ nb_cli_show_dnode_cmds(vty, child, with_defaults);
+ }
+
+ if (sort_node) {
+ for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data))
+ nb_cli_show_dnode_cmds(vty, data, with_defaults);
+
+ list_delete(&sort_list);
+ sort_node = NULL;
}
}
+void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
+ bool with_defaults)
+{
+ struct nb_node *nb_node;
+
+ if (!with_defaults && yang_dnode_is_default_recursive(root))
+ return;
+
+ nb_node = root->schema->priv;
+
+ if (nb_node && nb_node->cbs.cli_show)
+ (*nb_node->cbs.cli_show)(vty, root, with_defaults);
+
+ if (!(root->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)))
+ show_dnode_children_cmds(vty, root, with_defaults);
+
+ if (nb_node && nb_node->cbs.cli_show_end)
+ (*nb_node->cbs.cli_show_end)(vty, root);
+}
+
static void nb_cli_show_config_cmds(struct vty *vty, struct nb_config *config,
bool with_defaults)
{
diff --git a/lib/prefix.c b/lib/prefix.c
index afc4d3d5c2..7dbb5f07f0 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -1198,15 +1198,6 @@ int netmask_str2prefix_str(const char *net_str, const char *mask_str,
return 1;
}
-/* Utility function for making IPv6 address string. */
-const char *inet6_ntoa(struct in6_addr addr)
-{
- static char buf[INET6_ADDRSTRLEN];
-
- inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN);
- return buf;
-}
-
/* converts to internal representation of mac address
* returns 1 on success, 0 otherwise
* format accepted: AA:BB:CC:DD:EE:FF
@@ -1361,92 +1352,92 @@ char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len)
}
printfrr_ext_autoreg_p("EA", printfrr_ea)
-static ssize_t printfrr_ea(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
const struct ethaddr *mac = ptr;
+ char cbuf[ETHER_ADDR_STRLEN];
- if (mac)
- prefix_mac2str(mac, buf, bsz);
- else
- strlcpy(buf, "NULL", bsz);
+ if (!mac)
+ return bputs(buf, "(null)");
- return 2;
+ /* need real length even if buffer is too short */
+ prefix_mac2str(mac, cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
}
printfrr_ext_autoreg_p("IA", printfrr_ia)
-static ssize_t printfrr_ia(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_ia(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
const struct ipaddr *ipa = ptr;
+ char cbuf[INET6_ADDRSTRLEN];
- if (ipa)
- ipaddr2str(ipa, buf, bsz);
- else
- strlcpy(buf, "NULL", bsz);
+ if (!ipa)
+ return bputs(buf, "(null)");
- return 2;
+ ipaddr2str(ipa, cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
}
printfrr_ext_autoreg_p("I4", printfrr_i4)
-static ssize_t printfrr_i4(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_i4(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
- if (ptr)
- inet_ntop(AF_INET, ptr, buf, bsz);
- else
- strlcpy(buf, "NULL", bsz);
+ char cbuf[INET_ADDRSTRLEN];
- return 2;
+ if (!ptr)
+ return bputs(buf, "(null)");
+
+ inet_ntop(AF_INET, ptr, cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
}
printfrr_ext_autoreg_p("I6", printfrr_i6)
-static ssize_t printfrr_i6(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_i6(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
- if (ptr)
- inet_ntop(AF_INET6, ptr, buf, bsz);
- else
- strlcpy(buf, "NULL", bsz);
+ char cbuf[INET6_ADDRSTRLEN];
- return 2;
+ if (!ptr)
+ return bputs(buf, "(null)");
+
+ inet_ntop(AF_INET6, ptr, cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
}
printfrr_ext_autoreg_p("FX", printfrr_pfx)
-static ssize_t printfrr_pfx(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
- if (ptr)
- prefix2str(ptr, buf, bsz);
- else
- strlcpy(buf, "NULL", bsz);
+ char cbuf[PREFIX_STRLEN];
+
+ if (!ptr)
+ return bputs(buf, "(null)");
- return 2;
+ prefix2str(ptr, cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
}
printfrr_ext_autoreg_p("SG4", printfrr_psg)
-static ssize_t printfrr_psg(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
const struct prefix_sg *sg = ptr;
- struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 };
+ ssize_t ret = 0;
- if (sg) {
- if (sg->src.s_addr == INADDR_ANY)
- bprintfrr(&fb, "(*,");
- else
- bprintfrr(&fb, "(%pI4,", &sg->src);
-
- if (sg->grp.s_addr == INADDR_ANY)
- bprintfrr(&fb, "*)");
- else
- bprintfrr(&fb, "%pI4)", &sg->grp);
+ if (!sg)
+ return bputs(buf, "(null)");
- fb.pos[0] = '\0';
+ if (sg->src.s_addr == INADDR_ANY)
+ ret += bputs(buf, "(*,");
+ else
+ ret += bprintfrr(buf, "(%pI4,", &sg->src);
- } else {
- strlcpy(buf, "NULL", bsz);
- }
+ if (sg->grp.s_addr == INADDR_ANY)
+ ret += bputs(buf, "*)");
+ else
+ ret += bprintfrr(buf, "%pI4)", &sg->grp);
- return 3;
+ return ret;
}
diff --git a/lib/prefix.h b/lib/prefix.h
index b2f3b0592f..d7ee1b8e4c 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -504,8 +504,6 @@ extern void apply_mask_ipv6(struct prefix_ipv6 *);
extern int ip6_masklen(struct in6_addr);
extern void masklen2ip6(const int, struct in6_addr *);
-extern const char *inet6_ntoa(struct in6_addr);
-
extern int is_zero_mac(const struct ethaddr *mac);
extern bool is_mcast_mac(const struct ethaddr *mac);
extern bool is_bcast_mac(const struct ethaddr *mac);
diff --git a/lib/printf/glue.c b/lib/printf/glue.c
index 29ca26ad5d..1147901236 100644
--- a/lib/printf/glue.c
+++ b/lib/printf/glue.c
@@ -210,15 +210,16 @@ void printfrr_ext_reg(const struct printfrr_ext *ext)
exts[i] = ext;
}
-ssize_t printfrr_extp(char *buf, size_t sz, const char *fmt, int prec,
+ssize_t printfrr_extp(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
+ const char *fmt = ea->fmt;
const struct printfrr_ext *ext;
size_t i;
for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
- return 0;
+ return -1;
if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
continue;
ext = exts[i];
@@ -226,20 +227,22 @@ ssize_t printfrr_extp(char *buf, size_t sz, const char *fmt, int prec,
continue;
if (strncmp(ext->match, fmt, strlen(ext->match)))
continue;
- return ext->print_ptr(buf, sz, fmt, prec, ptr);
+ ea->fmt += strlen(ext->match);
+ return ext->print_ptr(buf, ea, ptr);
}
- return 0;
+ return -1;
}
-ssize_t printfrr_exti(char *buf, size_t sz, const char *fmt, int prec,
+ssize_t printfrr_exti(struct fbuf *buf, struct printfrr_eargs *ea,
uintmax_t num)
{
+ const char *fmt = ea->fmt;
const struct printfrr_ext *ext;
size_t i;
for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
- return 0;
+ return -1;
if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
continue;
ext = exts[i];
@@ -247,7 +250,48 @@ ssize_t printfrr_exti(char *buf, size_t sz, const char *fmt, int prec,
continue;
if (strncmp(ext->match, fmt, strlen(ext->match)))
continue;
- return ext->print_int(buf, sz, fmt, prec, num);
+ ea->fmt += strlen(ext->match);
+ return ext->print_int(buf, ea, num);
}
- return 0;
+ return -1;
+}
+
+printfrr_ext_autoreg_p("FB", printfrr_fb)
+static ssize_t printfrr_fb(struct fbuf *out, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ const struct fbuf *in = ptr;
+ ptrdiff_t copy_len;
+
+ if (!in)
+ return bputs(out, "NULL");
+
+ if (out) {
+ copy_len = MIN(in->pos - in->buf,
+ out->buf + out->len - out->pos);
+ if (copy_len > 0) {
+ memcpy(out->pos, in->buf, copy_len);
+ out->pos += copy_len;
+ }
+ }
+
+ return in->pos - in->buf;
+}
+
+printfrr_ext_autoreg_p("VA", printfrr_va)
+static ssize_t printfrr_va(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ const struct va_format *vaf = ptr;
+ va_list ap;
+
+ if (!vaf || !vaf->fmt || !vaf->va)
+ return bputs(buf, "NULL");
+
+ /* make sure we don't alter the data passed in - especially since
+ * bprintfrr (and thus this) might be called on the same format twice,
+ * when allocating a larger buffer in asnprintfrr()
+ */
+ va_copy(ap, *vaf->va);
+ return vbprintfrr(buf, vaf->fmt, ap);
}
diff --git a/lib/printf/printflocal.h b/lib/printf/printflocal.h
index 335e09872e..bac80e801c 100644
--- a/lib/printf/printflocal.h
+++ b/lib/printf/printflocal.h
@@ -100,6 +100,8 @@ int _frr_find_arguments(const char *, va_list, union arg **) DSO_LOCAL;
int _frr_find_warguments(const wchar_t *, va_list, union arg **) DSO_LOCAL;
#endif
-/* returns number of bytes consumed for extended specifier */
-ssize_t printfrr_extp(char *, size_t, const char *, int, const void *) DSO_LOCAL;
-ssize_t printfrr_exti(char *, size_t, const char *, int, uintmax_t) DSO_LOCAL;
+/* returns number of bytes needed for full output, or -1 */
+ssize_t printfrr_extp(struct fbuf *, struct printfrr_eargs *ea, const void *)
+ DSO_LOCAL;
+ssize_t printfrr_exti(struct fbuf *, struct printfrr_eargs *ea, uintmax_t)
+ DSO_LOCAL;
diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c
index 8c7a8a58c4..49fa2b718f 100644
--- a/lib/printf/vfprintf.c
+++ b/lib/printf/vfprintf.c
@@ -147,7 +147,7 @@ __wcsconv(wchar_t *wcsarg, int prec)
* Non-MT-safe version
*/
ssize_t
-vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
+vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap)
{
const char *fmt; /* format string */
int ch; /* character from fmt */
@@ -177,6 +177,9 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
int nextarg; /* 1-based argument index */
va_list orgap; /* original argument pointer */
char *convbuf; /* wide to multibyte conversion result */
+ char *extstart = NULL; /* where printfrr_ext* started printing */
+ struct fbuf cb_copy, *cb;
+ struct fmt_outpos *opos;
static const char xdigs_lower[16] = "0123456789abcdef";
static const char xdigs_upper[16] = "0123456789ABCDEF";
@@ -268,6 +271,16 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
argtable = NULL;
nextarg = 1;
va_copy(orgap, ap);
+
+ if (cb_in) {
+ /* prevent printfrr exts from polluting cb->outpos */
+ cb_copy = *cb_in;
+ cb_copy.outpos = NULL;
+ cb_copy.outpos_n = cb_copy.outpos_i = 0;
+ cb = &cb_copy;
+ } else
+ cb = NULL;
+
io_init(&io, cb);
ret = 0;
@@ -292,11 +305,16 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
flags = 0;
dprec = 0;
- width = 0;
+ width = -1;
prec = -1;
sign = '\0';
ox[1] = '\0';
+ if (cb_in && cb_in->outpos_i < cb_in->outpos_n)
+ opos = &cb_in->outpos[cb_in->outpos_i];
+ else
+ opos = NULL;
+
rflag: ch = *fmt++;
reswitch: switch (ch) {
case ' ':
@@ -438,15 +456,24 @@ reswitch: switch (ch) {
ulval = SARG();
if (printfrr_ext_char(fmt[0])) {
- n2 = printfrr_exti(buf, sizeof(buf), fmt, prec,
+ struct printfrr_eargs ea = {
+ .fmt = fmt,
+ .precision = prec,
+ .width = width,
+ .alt_repr = !!(flags & ALT),
+ .leftadj = !!(flags & LADJUST),
+ };
+
+ if (cb)
+ extstart = cb->pos;
+
+ size = printfrr_exti(cb, &ea,
(flags & INTMAX_SIZE) ? ujval
: (uintmax_t)ulval);
- if (n2 > 0) {
- fmt += n2;
- cp = buf;
- size = strlen(cp);
- sign = '\0';
- break;
+ if (size >= 0) {
+ fmt = ea.fmt;
+ width = ea.width;
+ goto ext_printed;
}
}
if (flags & INTMAX_SIZE) {
@@ -503,35 +530,6 @@ reswitch: switch (ch) {
size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
sign = '\0';
break;
-#ifdef DANGEROUS_PERCENT_N
- /* FRR does not use %n in printf formats. This is just left
- * here in case someone tries to use %n and starts debugging
- * why the f* it doesn't work
- */
- case 'n':
- /*
- * Assignment-like behavior is specified if the
- * value overflows or is otherwise unrepresentable.
- * C99 says to use `signed char' for %hhn conversions.
- */
- if (flags & LLONGINT)
- *GETARG(long long *) = ret;
- else if (flags & SIZET)
- *GETARG(ssize_t *) = (ssize_t)ret;
- else if (flags & PTRDIFFT)
- *GETARG(ptrdiff_t *) = ret;
- else if (flags & INTMAXT)
- *GETARG(intmax_t *) = ret;
- else if (flags & LONGINT)
- *GETARG(long *) = ret;
- else if (flags & SHORTINT)
- *GETARG(short *) = ret;
- else if (flags & CHARINT)
- *GETARG(signed char *) = ret;
- else
- *GETARG(int *) = ret;
- continue; /* no output */
-#endif
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
@@ -551,14 +549,24 @@ reswitch: switch (ch) {
* -- ANSI X3J11
*/
ptrval = GETARG(void *);
- if (printfrr_ext_char(fmt[0]) &&
- (n2 = printfrr_extp(buf, sizeof(buf),
- fmt, prec, ptrval)) > 0) {
- fmt += n2;
- cp = buf;
- size = strlen(cp);
- sign = '\0';
- break;
+ if (printfrr_ext_char(fmt[0])) {
+ struct printfrr_eargs ea = {
+ .fmt = fmt,
+ .precision = prec,
+ .width = width,
+ .alt_repr = !!(flags & ALT),
+ .leftadj = !!(flags & LADJUST),
+ };
+
+ if (cb)
+ extstart = cb->pos;
+
+ size = printfrr_extp(cb, &ea, ptrval);
+ if (size >= 0) {
+ fmt = ea.fmt;
+ width = ea.width;
+ goto ext_printed;
+ }
}
ujval = (uintmax_t)(uintptr_t)ptrval;
base = 16;
@@ -662,6 +670,7 @@ number: if ((dprec = prec) >= 0)
cp = buf;
size = 1;
sign = '\0';
+ opos = NULL;
break;
}
@@ -679,6 +688,9 @@ number: if ((dprec = prec) >= 0)
* Compute actual size, so we know how much to pad.
* size excludes decimal prec; realsz includes it.
*/
+ if (width < 0)
+ width = 0;
+
realsz = dprec > size ? dprec : size;
if (sign)
realsz++;
@@ -686,7 +698,7 @@ number: if ((dprec = prec) >= 0)
realsz += 2;
prsize = width > realsz ? width : realsz;
- if ((unsigned)ret + prsize > INT_MAX) {
+ if ((unsigned int)ret + prsize > INT_MAX) {
ret = EOF;
errno = EOVERFLOW;
goto error;
@@ -696,6 +708,9 @@ number: if ((dprec = prec) >= 0)
if ((flags & (LADJUST|ZEROPAD)) == 0)
PAD(width - realsz, blanks);
+ if (opos)
+ opos->off_start = cb->pos - cb->buf;
+
/* prefix */
if (sign)
PRINT(&sign, 1);
@@ -713,6 +728,74 @@ number: if ((dprec = prec) >= 0)
/* leading zeroes from decimal precision */
PAD(dprec - size, zeroes);
PRINT(cp, size);
+
+ if (opos) {
+ opos->off_end = cb->pos - cb->buf;
+ cb_in->outpos_i++;
+ }
+
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += prsize;
+
+ FLUSH(); /* copy out the I/O vectors */
+ continue;
+
+ext_printed:
+ /* when we arrive here, a printfrr extension has written to cb
+ * (if non-NULL), but we still need to handle padding. The
+ * original cb->pos is in extstart; the return value from the
+ * ext is in size.
+ *
+ * Keep analogous to code above please.
+ */
+
+ if (width < 0)
+ width = 0;
+
+ realsz = size;
+ prsize = width > realsz ? width : realsz;
+ if ((unsigned int)ret + prsize > INT_MAX) {
+ ret = EOF;
+ errno = EOVERFLOW;
+ goto error;
+ }
+
+ /* right-adjusting blank padding - need to move the chars
+ * that the extension has already written. Should be very
+ * rare.
+ */
+ if (cb && width > size && (flags & (LADJUST|ZEROPAD)) == 0) {
+ size_t nwritten = cb->pos - extstart;
+ size_t navail = cb->buf + cb->len - extstart;
+ size_t npad = width - realsz;
+ size_t nmove;
+
+ if (navail < npad)
+ navail = 0;
+ else
+ navail -= npad;
+ nmove = MIN(nwritten, navail);
+
+ memmove(extstart + npad, extstart, nmove);
+
+ cb->pos = extstart;
+ PAD(npad, blanks);
+ cb->pos += nmove;
+ extstart += npad;
+ }
+
+ io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
+
+ if (opos && extstart <= cb->pos) {
+ opos->off_start = extstart - cb->buf;
+ opos->off_end = cb->pos - cb->buf;
+ cb_in->outpos_i++;
+ }
+
/* left-adjusting padding (always blank) */
if (flags & LADJUST)
PAD(width - realsz, blanks);
@@ -730,6 +813,8 @@ error:
free(convbuf);
if ((argtable != NULL) && (argtable != statargtable))
free (argtable);
+ if (cb_in)
+ cb_in->pos = cb->pos;
return (ret);
/* NOTREACHED */
}
diff --git a/lib/printfrr.h b/lib/printfrr.h
index 418e839d97..4338ac3a2f 100644
--- a/lib/printfrr.h
+++ b/lib/printfrr.h
@@ -28,10 +28,17 @@
extern "C" {
#endif
+struct fmt_outpos {
+ unsigned int off_start, off_end;
+};
+
struct fbuf {
char *buf;
char *pos;
size_t len;
+
+ struct fmt_outpos *outpos;
+ size_t outpos_n, outpos_i;
};
#define at(a, b) PRINTFRR(a, b)
@@ -105,6 +112,8 @@ char *asnprintfrr(struct memtype *mt, char *out, size_t sz,
*/
#define printfrr_ext_char(ch) ((ch) >= 'A' && (ch) <= 'Z')
+struct printfrr_eargs;
+
struct printfrr_ext {
/* embedded string to minimize cache line pollution */
char match[8];
@@ -112,23 +121,80 @@ struct printfrr_ext {
/* both can be given, if not the code continues searching
* (you can do %pX and %dX in 2 different entries)
*
- * return value: number of bytes consumed from the format string, so
- * you can consume extra flags (e.g. register for "%pX", consume
- * "%pXfoo" or "%pXbar" for flags.) Convention is to make those flags
- * lowercase letters or numbers.
+ * return value: number of bytes that would be printed if the buffer
+ * was large enough. be careful about not under-reporting this;
+ * otherwise asnprintf() & co. will get broken. Returning -1 means
+ * something went wrong & default %p/%d handling should be executed.
*
- * bsz is a compile-time constant in printf; it's gonna be relatively
- * small. This isn't designed to print Shakespeare from a pointer.
+ * to consume extra input flags after %pXY, increment *fmt. It points
+ * at the first character after %pXY at entry. Convention is to make
+ * those flags lowercase letters or numbers.
+ */
+ ssize_t (*print_ptr)(struct fbuf *buf, struct printfrr_eargs *info,
+ const void *);
+ ssize_t (*print_int)(struct fbuf *buf, struct printfrr_eargs *info,
+ uintmax_t);
+};
+
+/* additional information passed to extended formatters */
+
+struct printfrr_eargs {
+ /* position in the format string. Points to directly after the
+ * extension specifier. Increment when consuming extra "flag
+ * characters".
+ */
+ const char *fmt;
+
+ /* %.1234x / %.*x
+ * not POSIX compatible when used with %p, will cause warnings from
+ * GCC & clang. Usable with %d. Not used by the printfrr() itself
+ * for extension specifiers, so essentially available as a "free"
+ * parameter. -1 if not specified. Value in the format string
+ * cannot be negative, but negative values can be passed with %.*x
+ */
+ int precision;
+
+ /* %1234x / %*x
+ * regular width specification. Internally handled by printfrr(), set
+ * to 0 if consumed by the extension in order to suppress standard
+ * width/padding behavior. 0 if not specified.
*
- * prec is the precision specifier (the 999 in "%.999p") -1 means
- * none given (value in the format string cannot be negative)
+ * NB: always positive, even if a negative value is passed in with
+ * %*x. (The sign is used for the - flag.)
+ */
+ int width;
+
+ /* %#x
+ * "alternate representation" flag, not POSIX compatible when used
+ * with %p or %d, will cause warnings from GCC & clang. Not used by
+ * printfrr() itself for extension specifiers.
*/
- ssize_t (*print_ptr)(char *buf, size_t bsz, const char *fmt, int prec,
- const void *);
- ssize_t (*print_int)(char *buf, size_t bsz, const char *fmt, int prec,
- uintmax_t);
+ bool alt_repr;
+
+ /* %-x
+ * left-pad flag. Internally handled by printfrr() if width is
+ * nonzero. Only use if the extension sets width to 0.
+ */
+ bool leftadj;
};
+/* for any extension that needs a buffer length */
+
+static inline ssize_t printfrr_ext_len(struct printfrr_eargs *ea)
+{
+ ssize_t rv;
+
+ if (ea->precision >= 0)
+ rv = ea->precision;
+ else if (ea->width >= 0) {
+ rv = ea->width;
+ ea->width = -1;
+ } else
+ rv = -1;
+
+ return rv;
+}
+
/* no locking - must be called when single threaded (e.g. at startup.)
* this restriction hopefully won't be a huge bother considering normal usage
* scenarios...
@@ -136,7 +202,7 @@ struct printfrr_ext {
void printfrr_ext_reg(const struct printfrr_ext *);
#define printfrr_ext_autoreg_p(matchs, print_fn) \
- static ssize_t print_fn(char *, size_t, const char *, int, \
+ static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \
const void *); \
static const struct printfrr_ext _printext_##print_fn = { \
.match = matchs, \
@@ -149,7 +215,8 @@ void printfrr_ext_reg(const struct printfrr_ext *);
/* end */
#define printfrr_ext_autoreg_i(matchs, print_fn) \
- static ssize_t print_fn(char *, size_t, const char *, int, uintmax_t); \
+ static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \
+ uintmax_t); \
static const struct printfrr_ext _printext_##print_fn = { \
.match = matchs, \
.print_int = print_fn, \
@@ -160,7 +227,11 @@ void printfrr_ext_reg(const struct printfrr_ext *);
} \
/* end */
-/* fbuf helper functions */
+/* fbuf helper functions - note all 3 of these return the length that would
+ * be written regardless of how much space was available in the buffer, as
+ * needed for implementing printfrr extensions. (They also accept NULL buf
+ * for that.)
+ */
static inline ssize_t bputs(struct fbuf *buf, const char *str)
{
@@ -184,6 +255,64 @@ static inline ssize_t bputch(struct fbuf *buf, char ch)
return 1;
}
+static inline ssize_t bputhex(struct fbuf *buf, uint8_t val)
+{
+ static const char hexch[] = "0123456789abcdef";
+
+ if (buf && buf->pos < buf->buf + buf->len)
+ *buf->pos++ = hexch[(val >> 4) & 0xf];
+ if (buf && buf->pos < buf->buf + buf->len)
+ *buf->pos++ = hexch[val & 0xf];
+ return 2;
+}
+
+/* %pVA extension, equivalent to Linux kernel %pV */
+
+struct va_format {
+ const char *fmt;
+ va_list *va;
+};
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pFB" (struct fbuf *)
+#pragma FRR printfrr_ext "%pVA" (struct va_format *)
+
+#pragma FRR printfrr_ext "%pHX" (signed char *)
+#pragma FRR printfrr_ext "%pHX" (unsigned char *)
+#pragma FRR printfrr_ext "%pHX" (void *)
+#pragma FRR printfrr_ext "%pHS" (signed char *)
+#pragma FRR printfrr_ext "%pHS" (unsigned char *)
+#pragma FRR printfrr_ext "%pHS" (void *)
+
+#pragma FRR printfrr_ext "%pSE" (char *)
+#pragma FRR printfrr_ext "%pSQ" (char *)
+#endif
+
+/* when using non-ISO-C compatible extension specifiers... */
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#define FMT_NSTD_BEGIN
+#define FMT_NSTD_END
+#else /* !_FRR_ATTRIBUTE_PRINTFRR */
+#define FMT_NSTD_BEGIN \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wformat\"") \
+ /* end */
+#define FMT_NSTD_END \
+ _Pragma("GCC diagnostic pop") \
+ /* end */
+#endif
+
+#define FMT_NSTD(expr) \
+ ({ \
+ typeof(expr) _v; \
+ FMT_NSTD_BEGIN \
+ _v = expr; \
+ FMT_NSTD_END \
+ _v; \
+ }) \
+ /* end */
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/routemap.c b/lib/routemap.c
index b836b55aad..33c65ac333 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -87,112 +87,126 @@ struct route_map_match_set_hooks rmap_match_set_hook;
/* match interface */
void route_map_match_interface_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_interface = func;
}
/* no match interface */
void route_map_no_match_interface_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_interface = func;
}
/* match ip address */
void route_map_match_ip_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ip_address = func;
}
/* no match ip address */
void route_map_no_match_ip_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ip_address = func;
}
/* match ip address prefix list */
void route_map_match_ip_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ip_address_prefix_list = func;
}
/* no match ip address prefix list */
void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ip_address_prefix_list = func;
}
/* match ip next hop */
void route_map_match_ip_next_hop_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ip_next_hop = func;
}
/* no match ip next hop */
void route_map_no_match_ip_next_hop_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ip_next_hop = func;
}
/* match ip next hop prefix list */
void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
}
/* no match ip next hop prefix list */
void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
}
/* match ip next-hop type */
void route_map_match_ip_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ip_next_hop_type = func;
}
/* no match ip next-hop type */
void route_map_no_match_ip_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ip_next_hop_type = func;
}
/* match ipv6 address */
void route_map_match_ipv6_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ipv6_address = func;
}
/* no match ipv6 address */
void route_map_no_match_ipv6_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ipv6_address = func;
}
@@ -200,178 +214,183 @@ void route_map_no_match_ipv6_address_hook(int (*func)(
/* match ipv6 address prefix list */
void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ipv6_address_prefix_list = func;
}
/* no match ipv6 address prefix list */
void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
}
/* match ipv6 next-hop type */
void route_map_match_ipv6_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_ipv6_next_hop_type = func;
}
/* no match ipv6 next-hop type */
void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_ipv6_next_hop_type = func;
}
/* match metric */
void route_map_match_metric_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_metric = func;
}
/* no match metric */
void route_map_no_match_metric_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_metric = func;
}
/* match tag */
-void route_map_match_tag_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_match_tag_hook(int (*func)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type))
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.match_tag = func;
}
/* no match tag */
void route_map_no_match_tag_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type))
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_match_tag = func;
}
/* set sr-te color */
-void route_map_set_srte_color_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_set_srte_color_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg))
+ const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.set_srte_color = func;
}
/* no set sr-te color */
-void route_map_no_set_srte_color_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_no_set_srte_color_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg))
+ const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_set_srte_color = func;
}
/* set ip nexthop */
-void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg))
+ const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.set_ip_nexthop = func;
}
/* no set ip nexthop */
-void route_map_no_set_ip_nexthop_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_no_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg))
+ const char *arg,
+ char *errmsg,
+ size_t errmsg_len))
{
rmap_match_set_hook.no_set_ip_nexthop = func;
}
/* set ipv6 nexthop local */
void route_map_set_ipv6_nexthop_local_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg))
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.set_ipv6_nexthop_local = func;
}
/* no set ipv6 nexthop local */
void route_map_no_set_ipv6_nexthop_local_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg))
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
}
/* set metric */
-void route_map_set_metric_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_set_metric_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg))
+ const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.set_metric = func;
}
/* no set metric */
-void route_map_no_set_metric_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_no_set_metric_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg))
+ const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_set_metric = func;
}
/* set tag */
-void route_map_set_tag_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg))
+void route_map_set_tag_hook(int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.set_tag = func;
}
/* no set tag */
-void route_map_no_set_tag_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg))
+ const char *arg,
+ char *errmsg, size_t errmsg_len))
{
rmap_match_set_hook.no_set_tag = func;
}
-int generic_match_add(struct vty *vty, struct route_map_index *index,
+int generic_match_add(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type)
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len)
{
enum rmap_compile_rets ret;
ret = route_map_add_match(index, command, arg, type);
switch (ret) {
case RMAP_RULE_MISSING:
- if (vty)
- vty_out(vty, "%% [%s] Can't find rule.\n",
- frr_protonameinst);
- else
- zlog_warn("Can't find rule: %s", command);
+ snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
+ frr_protonameinst);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_ERROR:
- if (vty)
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- else
- zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
+ snprintf(errmsg, errmsg_len,
+ "%% [%s] Argument form is unsupported or malformed.",
+ frr_protonameinst);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_SUCCESS:
/*
@@ -383,9 +402,10 @@ int generic_match_add(struct vty *vty, struct route_map_index *index,
return CMD_SUCCESS;
}
-int generic_match_delete(struct vty *vty, struct route_map_index *index,
+int generic_match_delete(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type)
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len)
{
enum rmap_compile_rets ret;
int retval = CMD_SUCCESS;
@@ -409,20 +429,14 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
ret = route_map_delete_match(index, command, dep_name, type);
switch (ret) {
case RMAP_RULE_MISSING:
- if (vty)
- vty_out(vty, "%% [%s] Can't find rule.\n",
- frr_protonameinst);
- else
- zlog_warn("Can't find rule: %s", command);
+ snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
+ frr_protonameinst);
retval = CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_ERROR:
- if (vty)
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- else
- zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
+ snprintf(errmsg, errmsg_len,
+ "%% [%s] Argument form is unsupported or malformed.",
+ frr_protonameinst);
retval = CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
@@ -438,26 +452,22 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
return retval;
}
-int generic_set_add(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+int generic_set_add(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len)
{
enum rmap_compile_rets ret;
ret = route_map_add_set(index, command, arg);
switch (ret) {
case RMAP_RULE_MISSING:
- if (vty)
- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
- else
- zlog_warn("Can't find rule: %s", command);
+ snprintf(errmsg, errmsg_len,
+ "%% [%s] Can't find rule.", frr_protonameinst);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_ERROR:
- if (vty)
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- else
- zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
+ snprintf(errmsg, errmsg_len,
+ "%% [%s] Argument form is unsupported or malformed.",
+ frr_protonameinst);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_SUCCESS:
break;
@@ -466,26 +476,22 @@ int generic_set_add(struct vty *vty, struct route_map_index *index,
return CMD_SUCCESS;
}
-int generic_set_delete(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+int generic_set_delete(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len)
{
enum rmap_compile_rets ret;
ret = route_map_delete_set(index, command, arg);
switch (ret) {
case RMAP_RULE_MISSING:
- if (vty)
- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
- else
- zlog_warn("Can't find rule: %s", command);
+ snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
+ frr_protonameinst);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_ERROR:
- if (vty)
- vty_out(vty,
- "%% [%s] Argument form is unsupported or malformed.\n",
- frr_protonameinst);
- else
- zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
+ snprintf(errmsg, errmsg_len,
+ "%% [%s] Argument form is unsupported or malformed.",
+ frr_protonameinst);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_SUCCESS:
break;
@@ -2627,47 +2633,6 @@ static unsigned int route_map_dep_data_hash_make_key(const void *p)
return string_hash_make(dep_data->rname);
}
-DEFUN (set_srte_color,
- set_srte_color_cmd,
- "set sr-te color [(1-4294967295)]",
- SET_STR
- SRTE_STR
- SRTE_COLOR_STR
- "Color of the SR-TE Policies to match with\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- int idx = 0;
- char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
- ? argv[idx]->arg
- : NULL;
-
- if (rmap_match_set_hook.set_srte_color)
- return rmap_match_set_hook.set_srte_color(vty, index,
- "sr-te color", arg);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_set_srte_color,
- no_set_srte_color_cmd,
- "no set sr-te color [(1-4294967295)]",
- NO_STR
- SET_STR
- SRTE_STR
- SRTE_COLOR_STR
- "Color of the SR-TE Policies to match with\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- int idx = 0;
- char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
- ? argv[idx]->arg
- : NULL;
-
- if (rmap_match_set_hook.no_set_srte_color)
- return rmap_match_set_hook.no_set_srte_color(
- vty, index, "sr-te color", arg);
- return CMD_SUCCESS;
-}
-
static void *route_map_dep_hash_alloc(void *p)
{
char *dep_name = (char *)p;
@@ -3279,8 +3244,5 @@ void route_map_init(void)
install_element(RMAP_NODE, &routemap_optimization_cmd);
install_element(RMAP_NODE, &no_routemap_optimization_cmd);
- install_element(RMAP_NODE, &set_srte_color_cmd);
- install_element(RMAP_NODE, &no_set_srte_color_cmd);
-
install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
}
diff --git a/lib/routemap.h b/lib/routemap.h
index bad3ca6d3d..6385193bbf 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -229,6 +229,144 @@ struct route_map {
};
DECLARE_QOBJ_TYPE(route_map);
+/* Route-map match conditions */
+#define IS_MATCH_INTERFACE(C) \
+ (strmatch(C, "frr-route-map:interface"))
+#define IS_MATCH_IPv4_ADDRESS_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv4-address-list"))
+#define IS_MATCH_IPv6_ADDRESS_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv6-address-list"))
+#define IS_MATCH_IPv4_NEXTHOP_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv4-next-hop-list"))
+#define IS_MATCH_IPv4_PREFIX_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv4-prefix-list"))
+#define IS_MATCH_IPv6_PREFIX_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv6-prefix-list"))
+#define IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv4-next-hop-prefix-list"))
+#define IS_MATCH_IPv4_NEXTHOP_TYPE(C) \
+ (strmatch(C, "frr-route-map:ipv4-next-hop-type"))
+#define IS_MATCH_IPv6_NEXTHOP_TYPE(C) \
+ (strmatch(C, "frr-route-map:ipv6-next-hop-type"))
+#define IS_MATCH_METRIC(C) \
+ (strmatch(C, "frr-route-map:match-metric"))
+#define IS_MATCH_TAG(C) (strmatch(C, "frr-route-map:match-tag"))
+/* Zebra route-map match conditions */
+#define IS_MATCH_IPv4_PREFIX_LEN(C) \
+ (strmatch(C, "frr-zebra-route-map:ipv4-prefix-length"))
+#define IS_MATCH_IPv6_PREFIX_LEN(C) \
+ (strmatch(C, "frr-zebra-route-map:ipv6-prefix-length"))
+#define IS_MATCH_IPv4_NH_PREFIX_LEN(C) \
+ (strmatch(C, "frr-zebra-route-map:ipv4-next-hop-prefix-length"))
+#define IS_MATCH_SRC_PROTO(C) \
+ (strmatch(C, "frr-zebra-route-map:source-protocol"))
+#define IS_MATCH_SRC_INSTANCE(C) \
+ (strmatch(C, "frr-zebra-route-map:source-instance"))
+/* BGP route-map match conditions */
+#define IS_MATCH_LOCAL_PREF(C) \
+ (strmatch(C, "frr-bgp-route-map:match-local-preference"))
+#define IS_MATCH_ORIGIN(C) \
+ (strmatch(C, "frr-bgp-route-map:match-origin"))
+#define IS_MATCH_RPKI(C) (strmatch(C, "frr-bgp-route-map:rpki"))
+#define IS_MATCH_PROBABILITY(C) \
+ (strmatch(C, "frr-bgp-route-map:probability"))
+#define IS_MATCH_SRC_VRF(C) \
+ (strmatch(C, "frr-bgp-route-map:source-vrf"))
+#define IS_MATCH_PEER(C) (strmatch(C, "frr-bgp-route-map:peer"))
+#define IS_MATCH_AS_LIST(C) \
+ (strmatch(C, "frr-bgp-route-map:as-path-list"))
+#define IS_MATCH_MAC_LIST(C) \
+ (strmatch(C, "frr-bgp-route-map:mac-address-list"))
+#define IS_MATCH_EVPN_ROUTE_TYPE(C) \
+ (strmatch(C, "frr-bgp-route-map:evpn-route-type"))
+#define IS_MATCH_EVPN_DEFAULT_ROUTE(C) \
+ (strmatch(C, "frr-bgp-route-map:evpn-default-route"))
+#define IS_MATCH_EVPN_VNI(C) \
+ (strmatch(C, "frr-bgp-route-map:evpn-vni"))
+#define IS_MATCH_EVPN_DEFAULT_ROUTE(C) \
+ (strmatch(C, "frr-bgp-route-map:evpn-default-route"))
+#define IS_MATCH_EVPN_RD(C) \
+ (strmatch(C, "frr-bgp-route-map:evpn-rd"))
+#define IS_MATCH_ROUTE_SRC(C) \
+ (strmatch(C, "frr-bgp-route-map:ip-route-source"))
+#define IS_MATCH_ROUTE_SRC_PL(C) \
+ (strmatch(C, "frr-bgp-route-map:ip-route-source-prefix-list"))
+#define IS_MATCH_COMMUNITY(C) \
+ (strmatch(C, "frr-bgp-route-map:match-community"))
+#define IS_MATCH_LCOMMUNITY(C) \
+ (strmatch(C, "frr-bgp-route-map:match-large-community"))
+#define IS_MATCH_EXTCOMMUNITY(C) \
+ (strmatch(C, "frr-bgp-route-map:match-extcommunity"))
+#define IS_MATCH_IPV4_NH(C) \
+ (strmatch(C, "frr-bgp-route-map:ipv4-nexthop"))
+#define IS_MATCH_IPV6_NH(C) \
+ (strmatch(C, "frr-bgp-route-map:ipv6-nexthop"))
+
+/* Route-map set actions */
+#define IS_SET_IPv4_NH(A) \
+ (strmatch(A, "frr-route-map:ipv4-next-hop"))
+#define IS_SET_IPv6_NH(A) \
+ (strmatch(A, "frr-route-map:ipv6-next-hop"))
+#define IS_SET_METRIC(A) \
+ (strmatch(A, "frr-route-map:set-metric"))
+#define IS_SET_TAG(A) (strmatch(A, "frr-route-map:set-tag"))
+#define IS_SET_SR_TE_COLOR(A) \
+ (strmatch(A, "frr-route-map:set-sr-te-color"))
+/* Zebra route-map set actions */
+#define IS_SET_SRC(A) \
+ (strmatch(A, "frr-zebra-route-map:src-address"))
+/* OSPF route-map set actions */
+#define IS_SET_METRIC_TYPE(A) \
+ (strmatch(A, "frr-ospf-route-map:metric-type"))
+#define IS_SET_FORWARDING_ADDR(A) \
+ (strmatch(A, "frr-ospf6-route-map:forwarding-address"))
+/* BGP route-map_set actions */
+#define IS_SET_WEIGHT(A) \
+ (strmatch(A, "frr-bgp-route-map:weight"))
+#define IS_SET_TABLE(A) (strmatch(A, "frr-bgp-route-map:table"))
+#define IS_SET_LOCAL_PREF(A) \
+ (strmatch(A, "frr-bgp-route-map:set-local-preference"))
+#define IS_SET_LABEL_INDEX(A) \
+ (strmatch(A, "frr-bgp-route-map:label-index"))
+#define IS_SET_DISTANCE(A) \
+ (strmatch(A, "frr-bgp-route-map:distance"))
+#define IS_SET_ORIGIN(A) \
+ (strmatch(A, "frr-bgp-route-map:set-origin"))
+#define IS_SET_ATOMIC_AGGREGATE(A) \
+ (strmatch(A, "frr-bgp-route-map:atomic-aggregate"))
+#define IS_SET_ORIGINATOR_ID(A) \
+ (strmatch(A, "frr-bgp-route-map:originator-id"))
+#define IS_SET_COMM_LIST_DEL(A) \
+ (strmatch(A, "frr-bgp-route-map:comm-list-delete"))
+#define IS_SET_LCOMM_LIST_DEL(A) \
+ (strmatch(A, "frr-bgp-route-map:large-comm-list-delete"))
+#define IS_SET_LCOMMUNITY(A) \
+ (strmatch(A, "frr-bgp-route-map:set-large-community"))
+#define IS_SET_COMMUNITY(A) \
+ (strmatch(A, "frr-bgp-route-map:set-community"))
+#define IS_SET_EXTCOMMUNITY_RT(A) \
+ (strmatch(A, "frr-bgp-route-map:set-extcommunity-rt"))
+#define IS_SET_EXTCOMMUNITY_SOO(A) \
+ (strmatch(A, "frr-bgp-route-map:set-extcommunity-soo"))
+#define IS_SET_AGGREGATOR(A) \
+ (strmatch(A, "frr-bgp-route-map:aggregator"))
+#define IS_SET_AS_PREPEND(A) \
+ (strmatch(A, "frr-bgp-route-map:as-path-prepend"))
+#define IS_SET_AS_EXCLUDE(A) \
+ (strmatch(A, "frr-bgp-route-map:as-path-exclude"))
+#define IS_SET_IPV6_NH_GLOBAL(A) \
+ (strmatch(A, "frr-bgp-route-map:ipv6-nexthop-global"))
+#define IS_SET_IPV6_VPN_NH(A) \
+ (strmatch(A, "frr-bgp-route-map:ipv6-vpn-address"))
+#define IS_SET_IPV6_PEER_ADDR(A) \
+ (strmatch(A, "frr-bgp-route-map:ipv6-peer-address"))
+#define IS_SET_IPV6_PREFER_GLOBAL(A) \
+ (strmatch(A, "frr-bgp-route-map:ipv6-prefer-global"))
+#define IS_SET_IPV4_VPN_NH(A) \
+ (strmatch(A, "frr-bgp-route-map:ipv4-vpn-address"))
+#define IS_SET_BGP_IPV4_NH(A) \
+ (strmatch(A, "frr-bgp-route-map:set-ipv4-nexthop"))
+
/* Prototypes. */
extern void route_map_init(void);
@@ -310,150 +448,186 @@ extern void
route_map_notify_pentry_dependencies(const char *affected_name,
struct prefix_list_entry *pentry,
route_map_event_t event);
-extern int generic_match_add(struct vty *vty, struct route_map_index *index,
+extern int generic_match_add(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
-
-extern int generic_match_delete(struct vty *vty, struct route_map_index *index,
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
+extern int generic_match_delete(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
-extern int generic_set_add(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
-extern int generic_set_delete(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
+
+extern int generic_set_add(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
+extern int generic_set_delete(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* match interface */
extern void route_map_match_interface_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match interface */
extern void route_map_no_match_interface_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ip address */
extern void route_map_match_ip_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ip address */
extern void route_map_no_match_ip_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ip address prefix list */
extern void route_map_match_ip_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ip address prefix list */
extern void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ip next hop */
extern void route_map_match_ip_next_hop_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ip next hop */
extern void route_map_no_match_ip_next_hop_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ip next hop prefix list */
extern void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ip next hop prefix list */
extern void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ip next hop type */
extern void route_map_match_ip_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ip next hop type */
extern void route_map_no_match_ip_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ipv6 address */
extern void route_map_match_ipv6_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ipv6 address */
extern void route_map_no_match_ipv6_address_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ipv6 address prefix list */
extern void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ipv6 address prefix list */
extern void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match ipv6 next-hop type */
extern void route_map_match_ipv6_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match ipv6 next-hop type */
extern void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match metric */
extern void route_map_match_metric_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match metric */
extern void route_map_no_match_metric_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* match tag */
extern void route_map_match_tag_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* no match tag */
extern void route_map_no_match_tag_hook(int (*func)(
- struct vty *vty, struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type));
+ struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type,
+ char *errmsg, size_t errmsg_len));
/* set sr-te color */
extern void route_map_set_srte_color_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg));
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len));
/* no set sr-te color */
extern void route_map_no_set_srte_color_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg));
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len));
/* set ip nexthop */
extern void route_map_set_ip_nexthop_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg));
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len));
/* no set ip nexthop */
extern void route_map_no_set_ip_nexthop_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg));
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len));
/* set ipv6 nexthop local */
extern void route_map_set_ipv6_nexthop_local_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg));
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len));
/* no set ipv6 nexthop local */
extern void route_map_no_set_ipv6_nexthop_local_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg));
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len));
/* set metric */
-extern void route_map_set_metric_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+extern void route_map_set_metric_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg));
+ const char *arg,
+ char *errmsg,
+ size_t errmsg_len));
/* no set metric */
extern void route_map_no_set_metric_hook(
- int (*func)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg));
+ int (*func)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len));
/* set tag */
-extern void route_map_set_tag_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+extern void route_map_set_tag_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg));
+ const char *arg,
+ char *errmsg,
+ size_t errmsg_len));
/* no set tag */
-extern void route_map_no_set_tag_hook(int (*func)(struct vty *vty,
- struct route_map_index *index,
+extern void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
const char *command,
- const char *arg));
+ const char *arg,
+ char *errmsg,
+ size_t errmsg_len));
extern void *route_map_rule_tag_compile(const char *arg);
extern void route_map_rule_tag_free(void *rule);
@@ -467,181 +641,200 @@ extern void route_map_counter_decrement(struct route_map *map);
/* Route map hooks data structure. */
struct route_map_match_set_hooks {
/* match interface */
- int (*match_interface)(struct vty *vty, struct route_map_index *index,
+ int (*match_interface)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match interface */
- int (*no_match_interface)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_interface)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* match ip address */
- int (*match_ip_address)(struct vty *vty, struct route_map_index *index,
+ int (*match_ip_address)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match ip address */
- int (*no_match_ip_address)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_ip_address)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* match ip address prefix list */
- int (*match_ip_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
+ int (*match_ip_address_prefix_list)(struct route_map_index *index,
const char *command,
const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match ip address prefix list */
- int (*no_match_ip_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_ip_address_prefix_list)(struct route_map_index *index,
const char *command,
const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* match ip next hop */
- int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index,
+ int (*match_ip_next_hop)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match ip next hop */
- int (*no_match_ip_next_hop)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_ip_next_hop)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* match ip next hop prefix list */
- int (*match_ip_next_hop_prefix_list)(struct vty *vty,
- struct route_map_index *index,
+ int (*match_ip_next_hop_prefix_list)(struct route_map_index *index,
const char *command,
const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match ip next hop prefix list */
- int (*no_match_ip_next_hop_prefix_list)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_ip_next_hop_prefix_list)(struct route_map_index *index,
const char *command,
const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg,
+ size_t errmsg_len);
/* match ip next-hop type */
- int (*match_ip_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
+ int (*match_ip_next_hop_type)(struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type,
+ char *errmsg,
+ size_t errmsg_len);
/* no match ip next-hop type */
- int (*no_match_ip_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
- const char *command,
- const char *arg,
- route_map_event_t type);
+ int (*no_match_ip_next_hop_type)(struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type,
+ char *errmsg,
+ size_t errmsg_len);
/* match ipv6 address */
- int (*match_ipv6_address)(struct vty *vty,
- struct route_map_index *index,
+ int (*match_ipv6_address)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match ipv6 address */
- int (*no_match_ipv6_address)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_ipv6_address)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* match ipv6 address prefix list */
- int (*match_ipv6_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
+ int (*match_ipv6_address_prefix_list)(struct route_map_index *index,
const char *command,
const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match ipv6 address prefix list */
- int (*no_match_ipv6_address_prefix_list)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_ipv6_address_prefix_list)(struct route_map_index *index,
const char *command,
const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg,
+ size_t errmsg_len);
/* match ipv6 next-hop type */
- int (*match_ipv6_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
+ int (*match_ipv6_next_hop_type)(struct route_map_index *index,
const char *command,
const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match ipv6 next-hop type */
- int (*no_match_ipv6_next_hop_type)(struct vty *vty,
- struct route_map_index *index,
+ int (*no_match_ipv6_next_hop_type)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* match metric */
- int (*match_metric)(struct vty *vty, struct route_map_index *index,
+ int (*match_metric)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match metric */
- int (*no_match_metric)(struct vty *vty, struct route_map_index *index,
+ int (*no_match_metric)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* match tag */
- int (*match_tag)(struct vty *vty, struct route_map_index *index,
+ int (*match_tag)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* no match tag */
- int (*no_match_tag)(struct vty *vty, struct route_map_index *index,
+ int (*no_match_tag)(struct route_map_index *index,
const char *command, const char *arg,
- route_map_event_t type);
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
/* set sr-te color */
- int (*set_srte_color)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*set_srte_color)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* no set sr-te color */
- int (*no_set_srte_color)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*no_set_srte_color)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* set ip nexthop */
- int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*set_ip_nexthop)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* no set ip nexthop */
- int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*no_set_ip_nexthop)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* set ipv6 nexthop local */
- int (*set_ipv6_nexthop_local)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg);
+ int (*set_ipv6_nexthop_local)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* no set ipv6 nexthop local */
- int (*no_set_ipv6_nexthop_local)(struct vty *vty,
- struct route_map_index *index,
- const char *command, const char *arg);
+ int (*no_set_ipv6_nexthop_local)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* set metric */
- int (*set_metric)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*set_metric)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* no set metric */
- int (*no_set_metric)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*no_set_metric)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* set tag */
- int (*set_tag)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*set_tag)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
/* no set tag */
- int (*no_set_tag)(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg);
+ int (*no_set_tag)(struct route_map_index *index,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
};
extern struct route_map_match_set_hooks rmap_match_set_hook;
@@ -666,15 +859,13 @@ extern struct route_map_index *route_map_index_get(struct route_map *map,
extern void route_map_index_delete(struct route_map_index *index, int notify);
/* routemap_northbound.c */
-typedef int (*routemap_match_hook_fun)(struct vty *vty,
- struct route_map_index *rmi,
+typedef int (*routemap_match_hook_fun)(struct route_map_index *rmi,
const char *command, const char *arg,
- route_map_event_t event);
-
-typedef int (*routemap_set_hook_fun)(struct vty *vty,
- struct route_map_index *rmi,
- const char *command, const char *arg);
-
+ route_map_event_t event,
+ char *errmsg, size_t errmsg_len);
+typedef int (*routemap_set_hook_fun)(struct route_map_index *rmi,
+ const char *command, const char *arg,
+ char *errmsg, size_t errmsg_len);
struct routemap_hook_context {
struct route_map_index *rhc_rmi;
const char *rhc_rule;
@@ -694,6 +885,8 @@ void routemap_hook_context_free(struct routemap_hook_context *rhc);
extern const struct frr_yang_module_info frr_route_map_info;
/* routemap_cli.c */
+extern int route_map_instance_cmp(struct lyd_node *dnode1,
+ struct lyd_node *dnode2);
extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void route_map_instance_show_end(struct vty *vty,
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 339d025124..9a53c11a4c 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -46,9 +46,6 @@ DEFPY_YANG_NOSH(
ROUTE_MAP_OP_CMD_STR
ROUTE_MAP_SEQUENCE_CMD_STR)
{
- struct route_map_index *rmi;
- struct route_map *rm;
- int action_type;
char xpath_action[XPATH_MAXLEN + 64];
char xpath_index[XPATH_MAXLEN + 32];
char xpath[XPATH_MAXLEN];
@@ -66,17 +63,9 @@ DEFPY_YANG_NOSH(
nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action);
rv = nb_cli_apply_changes(vty, NULL);
- if (rv == CMD_SUCCESS) {
+ if (rv == CMD_SUCCESS)
VTY_PUSH_XPATH(RMAP_NODE, xpath_index);
- /* Add support for non-migrated route map users. */
- nb_cli_pending_commit_check(vty);
- rm = route_map_get(name);
- action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY;
- rmi = route_map_index_get(rm, action_type, sequence);
- VTY_PUSH_CONTEXT(RMAP_NODE, rmi);
- }
-
return rv;
}
@@ -108,71 +97,29 @@ DEFPY_YANG(
snprintf(xpath, sizeof(xpath),
"/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']",
name, sequence);
+
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
+int route_map_instance_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+{
+ uint16_t seq1 = yang_dnode_get_uint16(dnode1, "./sequence");
+ uint16_t seq2 = yang_dnode_get_uint16(dnode2, "./sequence");
+
+ return seq1 - seq2;
+}
+
void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- const struct route_map_rule *rmr;
- const struct route_map_index *rmi;
const char *name = yang_dnode_get_string(dnode, "../name");
const char *action = yang_dnode_get_string(dnode, "./action");
const char *sequence = yang_dnode_get_string(dnode, "./sequence");
vty_out(vty, "route-map %s %s %s\n", name, action, sequence);
- rmi = nb_running_get_entry(dnode, NULL, false);
- if (rmi == NULL) {
- /*
- * We can't have outdated rules if route map hasn't
- * been created yet.
- */
- return;
- }
-
-#define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue
-
- /* Print route map `match` for old CLI users. */
- for (rmr = rmi->match_list.head; rmr; rmr = rmr->next) {
- /* Skip all matches implemented by northbound. */
- SKIP_RULE("interface");
- SKIP_RULE("ip address");
- SKIP_RULE("ip address prefix-list");
- SKIP_RULE("ip next-hop");
- SKIP_RULE("ip next-hop prefix-list");
- SKIP_RULE("ip next-hop type");
- SKIP_RULE("ipv6 address");
- SKIP_RULE("ipv6 address prefix-list");
- SKIP_RULE("ipv6 next-hop type");
- SKIP_RULE("metric");
- SKIP_RULE("tag");
- /* Zebra specific match conditions. */
- SKIP_RULE("ip address prefix-len");
- SKIP_RULE("ipv6 address prefix-len");
- SKIP_RULE("ip next-hop prefix-len");
- SKIP_RULE("source-protocol");
- SKIP_RULE("source-instance");
-
- vty_out(vty, " match %s %s\n", rmr->cmd->str,
- rmr->rule_str ? rmr->rule_str : "");
- }
-
- /* Print route map `set` for old CLI users. */
- for (rmr = rmi->set_list.head; rmr; rmr = rmr->next) {
- /* Skip all sets implemented by northbound. */
- SKIP_RULE("metric");
- SKIP_RULE("tag");
- /* Zebra specific set actions. */
- SKIP_RULE("src");
-
- vty_out(vty, " set %s %s\n", rmr->cmd->str,
- rmr->rule_str ? rmr->rule_str : "");
- }
-
-#undef SKIP_RULE
}
void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
@@ -187,11 +134,13 @@ DEFPY_YANG(
"Match first hop interface of route\n"
INTERFACE_STR)
{
- const char *xpath = "./match-condition[condition='interface']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:interface']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/interface", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname);
return nb_cli_apply_changes(vty, NULL);
@@ -205,7 +154,8 @@ DEFPY_YANG(
"Match first hop interface of route\n"
INTERFACE_STR)
{
- const char *xpath = "./match-condition[condition='interface']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:interface']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -222,11 +172,13 @@ DEFPY_YANG(
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv4-address-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-address-list']";
char xpath_value[XPATH_MAXLEN + 32];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
@@ -243,7 +195,8 @@ DEFPY_YANG(
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv4-address-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-address-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -260,11 +213,13 @@ DEFPY_YANG(
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-prefix-list']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
@@ -280,7 +235,8 @@ DEFPY_YANG(
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-prefix-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -297,11 +253,13 @@ DEFPY_YANG(
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-next-hop-list']";
char xpath_value[XPATH_MAXLEN + 32];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
@@ -318,7 +276,8 @@ DEFPY_YANG(
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-next-hop-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -336,11 +295,12 @@ DEFPY_YANG(
"IP prefix-list name\n")
{
const char *xpath =
- "./match-condition[condition='ipv4-next-hop-prefix-list']";
+ "./match-condition[condition='frr-route-map:ipv4-next-hop-prefix-list']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
@@ -358,7 +318,7 @@ DEFPY_YANG(
"IP prefix-list name\n")
{
const char *xpath =
- "./match-condition[condition='ipv4-next-hop-prefix-list']";
+ "./match-condition[condition='frr-route-map:ipv4-next-hop-prefix-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -374,12 +334,13 @@ DEFPY_YANG(
"Match entries by type\n"
"Blackhole\n")
{
- const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-next-hop-type']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type",
- xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/ipv4-next-hop-type", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
return nb_cli_apply_changes(vty, NULL);
@@ -393,7 +354,8 @@ DEFPY_YANG(
"Match entries by type\n"
"Blackhole\n")
{
- const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv4-next-hop-type']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -408,11 +370,13 @@ DEFPY_YANG(
"Match IPv6 address of route\n"
"IPv6 access-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv6-address-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv6-address-list']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
@@ -427,7 +391,8 @@ DEFPY_YANG(
"Match IPv6 address of route\n"
"IPv6 access-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv6-address-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv6-address-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -443,11 +408,13 @@ DEFPY_YANG(
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv6-prefix-list']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/list-name", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
@@ -464,7 +431,8 @@ DEFPY_YANG(
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv6-prefix-list']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -479,12 +447,13 @@ DEFPY_YANG(
"Match entries by type\n"
"Blackhole\n")
{
- const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv6-next-hop-type']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type",
- xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/ipv6-next-hop-type", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
return nb_cli_apply_changes(vty, NULL);
@@ -498,7 +467,8 @@ DEFPY_YANG(
"Match entries by type\n"
"Blackhole\n")
{
- const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:ipv6-next-hop-type']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -512,11 +482,13 @@ DEFPY_YANG(
"Match metric of route\n"
"Metric value\n")
{
- const char *xpath = "./match-condition[condition='metric']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:match-metric']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/metric", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str);
return nb_cli_apply_changes(vty, NULL);
@@ -530,7 +502,8 @@ DEFPY_YANG(
"Match metric of route\n"
"Metric value\n")
{
- const char *xpath = "./match-condition[condition='metric']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:match-metric']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -544,11 +517,13 @@ DEFPY_YANG(
"Match tag of route\n"
"Tag value\n")
{
- const char *xpath = "./match-condition[condition='tag']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:match-tag']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/tag", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
return nb_cli_apply_changes(vty, NULL);
@@ -562,7 +537,8 @@ DEFPY_YANG(
"Match tag of route\n"
"Tag value\n")
{
- const char *xpath = "./match-condition[condition='tag']";
+ const char *xpath =
+ "./match-condition[condition='frr-route-map:match-tag']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -572,78 +548,259 @@ DEFPY_YANG(
void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- int condition = yang_dnode_get_enum(dnode, "./condition");
+ const char *condition = yang_dnode_get_string(dnode, "./condition");
+ struct lyd_node *ln;
+ const char *acl;
- switch (condition) {
- case 0: /* interface */
+ if (IS_MATCH_INTERFACE(condition)) {
vty_out(vty, " match interface %s\n",
- yang_dnode_get_string(dnode, "./interface"));
- break;
- case 1: /* ipv4-address-list */
- case 3: /* ipv4-next-hop-list */
- switch (condition) {
- case 1:
- vty_out(vty, " match ip address %s\n",
- yang_dnode_get_string(dnode, "./list-name"));
- break;
- case 3:
- vty_out(vty, " match ip next-hop %s\n",
- yang_dnode_get_string(dnode, "./list-name"));
- break;
- }
- break;
- case 2: /* ipv4-prefix-list */
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/interface"));
+ } else if (IS_MATCH_IPv4_ADDRESS_LIST(condition)
+ || IS_MATCH_IPv4_NEXTHOP_LIST(condition)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(dnode,
+ "./rmap-match-condition/list-name"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ if (IS_MATCH_IPv4_ADDRESS_LIST(condition))
+ vty_out(vty, " match ip address %s\n", acl);
+ else
+ vty_out(vty, " match ip next-hop %s\n", acl);
+ } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) {
vty_out(vty, " match ip address prefix-list %s\n",
- yang_dnode_get_string(dnode, "./list-name"));
- break;
- case 4: /* ipv4-next-hop-prefix-list */
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
+ } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) {
vty_out(vty, " match ip next-hop prefix-list %s\n",
- yang_dnode_get_string(dnode, "./list-name"));
- break;
- case 5: /* ipv4-next-hop-type */
- vty_out(vty, " match ip next-hop type %s\n",
- yang_dnode_get_string(dnode, "./ipv4-next-hop-type"));
- break;
- case 6: /* ipv6-address-list */
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
+ } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) {
vty_out(vty, " match ipv6 address %s\n",
- yang_dnode_get_string(dnode, "./list-name"));
- break;
- case 7: /* ipv6-prefix-list */
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
+ } else if (IS_MATCH_IPv6_PREFIX_LIST(condition)) {
vty_out(vty, " match ipv6 address prefix-list %s\n",
- yang_dnode_get_string(dnode, "./list-name"));
- break;
- case 8: /* ipv6-next-hop-type */
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
+ } else if (IS_MATCH_IPv4_NEXTHOP_TYPE(condition)) {
+ vty_out(vty, " match ip next-hop type %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/ipv4-next-hop-type"));
+ } else if (IS_MATCH_IPv6_NEXTHOP_TYPE(condition)) {
vty_out(vty, " match ipv6 next-hop type %s\n",
- yang_dnode_get_string(dnode, "./ipv6-next-hop-type"));
- break;
- case 9: /* metric */
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/ipv6-next-hop-type"));
+ } else if (IS_MATCH_METRIC(condition)) {
vty_out(vty, " match metric %s\n",
- yang_dnode_get_string(dnode, "./metric"));
- break;
- case 10: /* tag */
+ yang_dnode_get_string(dnode,
+ "./rmap-match-condition/metric"));
+ } else if (IS_MATCH_TAG(condition)) {
vty_out(vty, " match tag %s\n",
- yang_dnode_get_string(dnode, "./tag"));
- break;
- case 100: /* ipv4-prefix-length */
+ yang_dnode_get_string(dnode,
+ "./rmap-match-condition/tag"));
+ } else if (IS_MATCH_IPv4_PREFIX_LEN(condition)) {
vty_out(vty, " match ip address prefix-len %s\n",
- yang_dnode_get_string(dnode,"./frr-zebra:ipv4-prefix-length"));
- break;
- case 101: /* ipv6-prefix-length */
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length"));
+ } else if (IS_MATCH_IPv6_PREFIX_LEN(condition)) {
vty_out(vty, " match ipv6 address prefix-len %s\n",
- yang_dnode_get_string(dnode, "./frr-zebra:ipv6-prefix-length"));
- break;
- case 102: /* ipv4-next-hop-prefix-length */
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length"));
+ } else if (IS_MATCH_IPv4_NH_PREFIX_LEN(condition)) {
vty_out(vty, " match ip next-hop prefix-len %s\n",
- yang_dnode_get_string(dnode, "./frr-zebra:ipv4-prefix-length"));
- break;
- case 103: /* source-protocol */
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length"));
+ } else if (IS_MATCH_SRC_PROTO(condition)) {
vty_out(vty, " match source-protocol %s\n",
- yang_dnode_get_string(dnode, "./frr-zebra:source-protocol"));
- break;
- case 104: /* source-instance */
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-zebra-route-map:source-protocol"));
+ } else if (IS_MATCH_SRC_INSTANCE(condition)) {
vty_out(vty, " match source-instance %s\n",
- yang_dnode_get_string(dnode, "./frr-zebra:source-instance"));
- break;
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-zebra-route-map:source-instance"));
+ } else if (IS_MATCH_LOCAL_PREF(condition)) {
+ vty_out(vty, " match local-preference %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:local-preference"));
+ } else if (IS_MATCH_ORIGIN(condition)) {
+ vty_out(vty, " match origin %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:origin"));
+ } else if (IS_MATCH_RPKI(condition)) {
+ vty_out(vty, " match rpki %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:rpki"));
+ } else if (IS_MATCH_PROBABILITY(condition)) {
+ vty_out(vty, " match probability %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:probability"));
+ } else if (IS_MATCH_SRC_VRF(condition)) {
+ vty_out(vty, " match source-vrf %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:source-vrf"));
+ } else if (IS_MATCH_PEER(condition)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:peer-ipv4-address"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+ else if (
+ (ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:peer-ipv6-address"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+ else if (
+ (ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:peer-interface"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+ else if (yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:peer-local")
+ != NULL)
+ acl = "local";
+
+ vty_out(vty, " match peer %s\n", acl);
+ } else if (IS_MATCH_AS_LIST(condition)) {
+ vty_out(vty, " match as-path %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:list-name"));
+ } else if (IS_MATCH_EVPN_ROUTE_TYPE(condition)) {
+ vty_out(vty, " match evpn route-type %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:evpn-route-type"));
+ } else if (IS_MATCH_EVPN_DEFAULT_ROUTE(condition)) {
+ vty_out(vty, " match evpn default-route\n");
+ } else if (IS_MATCH_EVPN_VNI(condition)) {
+ vty_out(vty, " match evpn vni %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:evpn-vni"));
+ } else if (IS_MATCH_EVPN_DEFAULT_ROUTE(condition)) {
+ vty_out(vty, " match evpn default-route %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:evpn-default-route"));
+ } else if (IS_MATCH_EVPN_RD(condition)) {
+ vty_out(vty, " match evpn rd %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:route-distinguisher"));
+ } else if (IS_MATCH_MAC_LIST(condition)) {
+ vty_out(vty, " match mac address %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:list-name"));
+ } else if (IS_MATCH_ROUTE_SRC(condition)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:list-name"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ vty_out(vty, " match ip route-source %s\n", acl);
+ } else if (IS_MATCH_ROUTE_SRC_PL(condition)) {
+ vty_out(vty, " match ip route-source prefix-list %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:list-name"));
+ } else if (IS_MATCH_ROUTE_SRC(condition)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:list-name"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ vty_out(vty, " match ip route-source %s\n", acl);
+ } else if (IS_MATCH_COMMUNITY(condition)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"))
+ != NULL) {
+ acl = yang_dnode_get_string(ln, NULL);
+
+ if (true
+ == yang_dnode_get_bool(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match"))
+ vty_out(vty,
+ " match community %s exact-match\n",
+ acl);
+ else
+ vty_out(vty, " match community %s\n", acl);
+ }
+
+ assert(acl);
+ } else if (IS_MATCH_LCOMMUNITY(condition)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"))
+ != NULL) {
+ acl = yang_dnode_get_string(ln, NULL);
+
+ if (true
+ == yang_dnode_get_bool(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match"))
+ vty_out(vty,
+ " match large-community %s exact-match\n",
+ acl);
+ else
+ vty_out(vty, " match large-community %s\n",
+ acl);
+ }
+
+ assert(acl);
+ } else if (IS_MATCH_EXTCOMMUNITY(condition)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ vty_out(vty, " match extcommunity %s\n", acl);
+ } else if (IS_MATCH_IPV4_NH(condition)) {
+ vty_out(vty, " match ip next-hop %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:ipv4-address"));
+ } else if (IS_MATCH_IPV6_NH(condition)) {
+ vty_out(vty, " match ipv6 next-hop %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:ipv6-address"));
}
}
@@ -655,11 +812,13 @@ DEFPY_YANG(
"Next hop address\n"
"IP address of next hop\n")
{
- const char *xpath = "./set-action[action='ipv4-next-hop']";
+ const char *xpath =
+ "./set-action[action='frr-route-map:ipv4-next-hop']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/ipv4-address", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
return nb_cli_apply_changes(vty, NULL);
@@ -674,7 +833,8 @@ DEFPY_YANG(
"Next hop address\n"
"IP address of next hop\n")
{
- const char *xpath = "./set-action[action='ipv4-next-hop']";
+ const char *xpath =
+ "./set-action[action='frr-route-map:ipv4-next-hop']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -690,11 +850,13 @@ DEFPY_YANG(
"IPv6 local address\n"
"IPv6 address of next hop\n")
{
- const char *xpath = "./set-action[action='ipv6-next-hop']";
+ const char *xpath =
+ "./set-action[action='frr-route-map:ipv6-next-hop']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/ipv6-address", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
return nb_cli_apply_changes(vty, NULL);
@@ -710,7 +872,8 @@ DEFPY_YANG(
"IPv6 local address\n"
"IPv6 address of next hop\n")
{
- const char *xpath = "./set-action[action='ipv6-next-hop']";
+ const char *xpath =
+ "./set-action[action='frr-route-map:ipv6-next-hop']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -727,33 +890,34 @@ DEFPY_YANG(
"Add round trip time\n"
"Subtract round trip time\n")
{
- const char *xpath = "./set-action[action='metric']";
+ const char *xpath = "./set-action[action='frr-route-map:set-metric']";
char xpath_value[XPATH_MAXLEN];
char value[64];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
if (rtt) {
snprintf(xpath_value, sizeof(xpath_value),
- "%s/use-round-trip-time", xpath);
+ "%s/rmap-set-action/use-round-trip-time", xpath);
snprintf(value, sizeof(value), "true");
} else if (artt) {
snprintf(xpath_value, sizeof(xpath_value),
- "%s/add-round-trip-time", xpath);
+ "%s/rmap-set-action/add-round-trip-time", xpath);
snprintf(value, sizeof(value), "true");
} else if (srtt) {
snprintf(xpath_value, sizeof(xpath_value),
- "%s/subtract-round-trip-time", xpath);
+ "%s/rmap-set-action/subtract-round-trip-time", xpath);
snprintf(value, sizeof(value), "true");
} else if (metric_str && metric_str[0] == '+') {
- snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric",
- xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/add-metric", xpath);
snprintf(value, sizeof(value), "%s", ++metric_str);
} else if (metric_str && metric_str[0] == '-') {
- snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric",
- xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/subtract-metric", xpath);
snprintf(value, sizeof(value), "%s", ++metric_str);
} else {
- snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/value", xpath);
snprintf(value, sizeof(value), "%s", metric_str);
}
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value);
@@ -769,7 +933,7 @@ DEFPY_YANG(
"Metric value for destination routing protocol\n"
"Metric value\n")
{
- const char *xpath = "./set-action[action='metric']";
+ const char *xpath = "./set-action[action='frr-route-map:set-metric']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
@@ -782,11 +946,12 @@ DEFPY_YANG(
"Tag value for routing protocol\n"
"Tag value\n")
{
- const char *xpath = "./set-action[action='tag']";
+ const char *xpath = "./set-action[action='frr-route-map:set-tag']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/tag",
+ xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
return nb_cli_apply_changes(vty, NULL);
@@ -800,58 +965,289 @@ DEFPY_YANG(
"Tag value for routing protocol\n"
"Tag value\n")
{
- const char *xpath = "./set-action[action='tag']";
+ const char *xpath = "./set-action[action='frr-route-map:set-tag']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (set_srte_color,
+ set_srte_color_cmd,
+ "set sr-te color (1-4294967295)",
+ SET_STR
+ SRTE_STR
+ SRTE_COLOR_STR
+ "Color of the SR-TE Policies to match with\n")
+{
+ const char *xpath =
+ "./set-action[action='frr-route-map:set-sr-te-color']";
+ char xpath_value[XPATH_MAXLEN];
+ int idx = 0;
+
+ char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
+ ? argv[idx]->arg
+ : NULL;
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/policy", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, arg);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (no_set_srte_color,
+ no_set_srte_color_cmd,
+ "no set sr-te color [(1-4294967295)]",
+ NO_STR
+ SET_STR
+ SRTE_STR
+ SRTE_COLOR_STR
+ "Color of the SR-TE Policies to match with\n")
+{
+ const char *xpath =
+ "./set-action[action='frr-route-map:set-sr-te-color']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
+
void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- int action = yang_dnode_get_enum(dnode, "./action");
+ const char *action = yang_dnode_get_string(dnode, "./action");
+ struct lyd_node *ln;
+ const char *acl;
- switch (action) {
- case 0: /* ipv4-next-hop */
+ if (IS_SET_IPv4_NH(action)) {
vty_out(vty, " set ip next-hop %s\n",
- yang_dnode_get_string(dnode, "./ipv4-address"));
- break;
- case 1: /* ipv6-next-hop */
+ yang_dnode_get_string(
+ dnode, "./rmap-set-action/ipv4-address"));
+ } else if (IS_SET_IPv6_NH(action)) {
vty_out(vty, " set ipv6 next-hop local %s\n",
- yang_dnode_get_string(dnode, "./ipv6-address"));
- break;
- case 2: /* metric */
- if (yang_dnode_get(dnode, "./use-round-trip-time")) {
+ yang_dnode_get_string(
+ dnode, "./rmap-set-action/ipv6-address"));
+ } else if (IS_SET_METRIC(action)) {
+ if (yang_dnode_get(dnode,
+ "./rmap-set-action/use-round-trip-time")) {
vty_out(vty, " set metric rtt\n");
- } else if (yang_dnode_get(dnode, "./add-round-trip-time")) {
+ } else if (yang_dnode_get(
+ dnode,
+ "./rmap-set-action/add-round-trip-time")) {
vty_out(vty, " set metric +rtt\n");
- } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) {
+ } else if (
+ yang_dnode_get(
+ dnode,
+ "./rmap-set-action/subtract-round-trip-time")) {
vty_out(vty, " set metric -rtt\n");
- } else if (yang_dnode_get(dnode, "./add-metric")) {
+ } else if (yang_dnode_get(dnode,
+ "./rmap-set-action/add-metric")) {
vty_out(vty, " set metric +%s\n",
- yang_dnode_get_string(dnode, "./add-metric"));
- } else if (yang_dnode_get(dnode, "./subtract-metric")) {
+ yang_dnode_get_string(
+ dnode, "./rmap-set-action/add-metric"));
+ } else if (yang_dnode_get(
+ dnode,
+ "./rmap-set-action/subtract-metric")) {
vty_out(vty, " set metric -%s\n",
- yang_dnode_get_string(dnode,
- "./subtract-metric"));
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/subtract-metric"));
} else {
vty_out(vty, " set metric %s\n",
- yang_dnode_get_string(dnode, "./value"));
+ yang_dnode_get_string(
+ dnode, "./rmap-set-action/value"));
}
- break;
- case 3: /* tag */
+ } else if (IS_SET_TAG(action)) {
vty_out(vty, " set tag %s\n",
- yang_dnode_get_string(dnode, "./tag"));
- break;
- case 100: /* source */
- if (yang_dnode_exists(dnode, "./frr-zebra:source-v4"))
+ yang_dnode_get_string(dnode, "./rmap-set-action/tag"));
+ } else if (IS_SET_SR_TE_COLOR(action)) {
+ vty_out(vty, " set sr-te color %s\n",
+ yang_dnode_get_string(dnode,
+ "./rmap-set-action/policy"));
+ } else if (IS_SET_SRC(action)) {
+ if (yang_dnode_exists(
+ dnode,
+ "./rmap-set-action/frr-zebra-route-map:ipv4-src-address"))
vty_out(vty, " set src %s\n",
- yang_dnode_get_string(dnode, "./frr-zebra:source-v4"));
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-zebra-route-map:ipv4-src-address"));
else
vty_out(vty, " set src %s\n",
- yang_dnode_get_string(dnode, "./frr-zebra:source-v6"));
- break;
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-zebra-route-map:ipv6-src-address"));
+ } else if (IS_SET_METRIC_TYPE(action)) {
+ vty_out(vty, " set metric-type %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-ospf-route-map:metric-type"));
+ } else if (IS_SET_FORWARDING_ADDR(action)) {
+ vty_out(vty, " set forwarding-address %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-ospf6-route-map:ipv6-address"));
+ } else if (IS_SET_WEIGHT(action)) {
+ vty_out(vty, " set weight %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:weight"));
+ } else if (IS_SET_TABLE(action)) {
+ vty_out(vty, " set table %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:table"));
+ } else if (IS_SET_LOCAL_PREF(action)) {
+ vty_out(vty, " set local-preference %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:local-pref"));
+ } else if (IS_SET_LABEL_INDEX(action)) {
+ vty_out(vty, " set label-index %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:label-index"));
+ } else if (IS_SET_DISTANCE(action)) {
+ vty_out(vty, " set distance %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:distance"));
+ } else if (IS_SET_ORIGIN(action)) {
+ vty_out(vty, " set origin %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:origin"));
+ } else if (IS_SET_ATOMIC_AGGREGATE(action)) {
+ vty_out(vty, " set atomic-aggregate\n");
+ } else if (IS_SET_ORIGINATOR_ID(action)) {
+ vty_out(vty, " set originator-id %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:originator-id"));
+ } else if (IS_SET_COMM_LIST_DEL(action)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:comm-list-name"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ vty_out(vty, " set comm-list %s delete\n", acl);
+ } else if (IS_SET_LCOMM_LIST_DEL(action)) {
+ acl = NULL;
+ if ((ln = yang_dnode_get(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:comm-list-name"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ vty_out(vty, " set large-comm-list %s delete\n", acl);
+ } else if (IS_SET_LCOMMUNITY(action)) {
+ if (yang_dnode_exists(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:large-community-string"))
+ vty_out(vty, " set large-community %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:large-community-string"));
+ else {
+ if (true
+ == yang_dnode_get_bool(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:large-community-none"))
+ vty_out(vty, " set large-community none\n");
+ }
+ } else if (IS_SET_COMMUNITY(action)) {
+ if (yang_dnode_exists(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:community-string"))
+ vty_out(vty, " set community %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:community-string"));
+ else {
+ if (true
+ == yang_dnode_get_bool(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:community-none"))
+ vty_out(vty, " set community none\n");
+ }
+ } else if (IS_SET_EXTCOMMUNITY_RT(action)) {
+ vty_out(vty, " set extcommunity rt %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:extcommunity-rt"));
+ } else if (IS_SET_EXTCOMMUNITY_SOO(action)) {
+ vty_out(vty, " set extcommunity soo %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:extcommunity-soo"));
+ } else if (IS_SET_AGGREGATOR(action)) {
+ vty_out(vty, " set aggregator as %s %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn"),
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address"));
+ } else if (IS_SET_AS_EXCLUDE(action)) {
+ vty_out(vty, " set as-path exclude %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:exclude-as-path"));
+ } else if (IS_SET_AS_PREPEND(action)) {
+ if (yang_dnode_exists(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:prepend-as-path"))
+ vty_out(vty, " set as-path prepend %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:prepend-as-path"));
+ else {
+ vty_out(vty, " set as-path prepend last-as %u\n",
+ yang_dnode_get_uint8(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:last-as"));
+ }
+ } else if (IS_SET_IPV6_NH_GLOBAL(action)) {
+ vty_out(vty, " set ipv6 next-hop global %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:ipv6-address"));
+ } else if (IS_SET_IPV6_VPN_NH(action)) {
+ vty_out(vty, " set ipv6 vpn next-hop %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:ipv6-address"));
+ } else if (IS_SET_IPV6_PEER_ADDR(action)) {
+ if (true
+ == yang_dnode_get_bool(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:preference"))
+ vty_out(vty, " set ipv6 next-hop peer-address\n");
+ } else if (IS_SET_IPV6_PREFER_GLOBAL(action)) {
+ if (true
+ == yang_dnode_get_bool(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:preference"))
+ vty_out(vty, " set ipv6 next-hop prefer-global\n");
+ } else if (IS_SET_IPV4_VPN_NH(action)) {
+ vty_out(vty, " set ipv4 vpn next-hop %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:ipv4-address"));
+ } else if (IS_SET_BGP_IPV4_NH(action)) {
+ vty_out(vty, " set ip next-hop %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:ipv4-nexthop"));
}
}
@@ -1114,4 +1510,7 @@ void route_map_cli_init(void)
install_element(RMAP_NODE, &set_tag_cmd);
install_element(RMAP_NODE, &no_set_tag_cmd);
+
+ install_element(RMAP_NODE, &set_srte_color_cmd);
+ install_element(RMAP_NODE, &no_set_srte_color_cmd);
}
diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c
index 597a6b1ecf..410eb51f5e 100644
--- a/lib/routemap_northbound.c
+++ b/lib/routemap_northbound.c
@@ -45,8 +45,9 @@ int lib_route_map_entry_match_destroy(struct nb_cb_destroy_args *args)
if (rhc->rhc_mhook == NULL)
return NB_OK;
- rv = rhc->rhc_mhook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL,
- rhc->rhc_event);
+ rv = rhc->rhc_mhook(rhc->rhc_rmi, rhc->rhc_rule, NULL,
+ rhc->rhc_event,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS)
return NB_ERR_INCONSISTENCY;
@@ -65,7 +66,8 @@ int lib_route_map_entry_set_destroy(struct nb_cb_destroy_args *args)
if (rhc->rhc_shook == NULL)
return NB_OK;
- rv = rhc->rhc_shook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL);
+ rv = rhc->rhc_shook(rhc->rhc_rmi, rhc->rhc_rule, NULL,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS)
return NB_ERR_INCONSISTENCY;
@@ -498,9 +500,10 @@ static int lib_route_map_entry_match_condition_interface_modify(
rhc->rhc_rule = "interface";
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
- rv = rmap_match_set_hook.match_interface(NULL, rhc->rhc_rmi,
+ rv = rmap_match_set_hook.match_interface(rhc->rhc_rmi,
"interface", ifname,
- RMAP_EVENT_MATCH_ADDED);
+ RMAP_EVENT_MATCH_ADDED,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -523,7 +526,7 @@ static int lib_route_map_entry_match_condition_list_name_modify(
{
struct routemap_hook_context *rhc;
const char *acl;
- int condition;
+ const char *condition;
int rv;
if (args->event != NB_EV_APPLY)
@@ -532,19 +535,19 @@ static int lib_route_map_entry_match_condition_list_name_modify(
/* Check for hook installation, otherwise we can just stop. */
acl = yang_dnode_get_string(args->dnode, NULL);
rhc = nb_running_get_entry(args->dnode, NULL, true);
- condition = yang_dnode_get_enum(args->dnode, "../condition");
- switch (condition) {
- case 1: /* ipv4-address-list */
+ condition = yang_dnode_get_string(args->dnode, "../../condition");
+
+ if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) {
if (rmap_match_set_hook.match_ip_address == NULL)
return NB_OK;
rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
rhc->rhc_rule = "ip address";
rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
rv = rmap_match_set_hook.match_ip_address(
- NULL, rhc->rhc_rmi, "ip address", acl,
- RMAP_EVENT_FILTER_ADDED);
- break;
- case 2: /* ipv4-prefix-list */
+ rhc->rhc_rmi, "ip address", acl,
+ RMAP_EVENT_FILTER_ADDED,
+ args->errmsg, args->errmsg_len);
+ } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) {
if (rmap_match_set_hook.match_ip_address_prefix_list == NULL)
return NB_OK;
rhc->rhc_mhook =
@@ -552,20 +555,20 @@ static int lib_route_map_entry_match_condition_list_name_modify(
rhc->rhc_rule = "ip address prefix-list";
rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
rv = rmap_match_set_hook.match_ip_address_prefix_list(
- NULL, rhc->rhc_rmi, "ip address prefix-list", acl,
- RMAP_EVENT_PLIST_ADDED);
- break;
- case 3: /* ipv4-next-hop-list */
+ rhc->rhc_rmi, "ip address prefix-list", acl,
+ RMAP_EVENT_PLIST_ADDED,
+ args->errmsg, args->errmsg_len);
+ } else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition)) {
if (rmap_match_set_hook.match_ip_next_hop == NULL)
return NB_OK;
rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
rhc->rhc_rule = "ip next-hop";
rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
rv = rmap_match_set_hook.match_ip_next_hop(
- NULL, rhc->rhc_rmi, "ip next-hop", acl,
- RMAP_EVENT_FILTER_ADDED);
- break;
- case 4: /* ipv4-next-hop-prefix-list */
+ rhc->rhc_rmi, "ip next-hop", acl,
+ RMAP_EVENT_FILTER_ADDED,
+ args->errmsg, args->errmsg_len);
+ } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) {
if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL)
return NB_OK;
rhc->rhc_mhook =
@@ -573,20 +576,20 @@ static int lib_route_map_entry_match_condition_list_name_modify(
rhc->rhc_rule = "ip next-hop prefix-list";
rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
rv = rmap_match_set_hook.match_ip_next_hop_prefix_list(
- NULL, rhc->rhc_rmi, "ip next-hop prefix-list", acl,
- RMAP_EVENT_PLIST_ADDED);
- break;
- case 6: /* ipv6-address-list */
+ rhc->rhc_rmi, "ip next-hop prefix-list", acl,
+ RMAP_EVENT_PLIST_ADDED,
+ args->errmsg, args->errmsg_len);
+ } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) {
if (rmap_match_set_hook.match_ipv6_address == NULL)
return NB_OK;
rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address;
rhc->rhc_rule = "ipv6 address";
rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
rv = rmap_match_set_hook.match_ipv6_address(
- NULL, rhc->rhc_rmi, "ipv6 address", acl,
- RMAP_EVENT_FILTER_ADDED);
- break;
- case 7: /* ipv6-prefix-list */
+ rhc->rhc_rmi, "ipv6 address", acl,
+ RMAP_EVENT_FILTER_ADDED,
+ args->errmsg, args->errmsg_len);
+ } else if (IS_MATCH_IPv6_PREFIX_LIST(condition)) {
if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL)
return NB_OK;
rhc->rhc_mhook =
@@ -594,13 +597,12 @@ static int lib_route_map_entry_match_condition_list_name_modify(
rhc->rhc_rule = "ipv6 address prefix-list";
rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
rv = rmap_match_set_hook.match_ipv6_address_prefix_list(
- NULL, rhc->rhc_rmi, "ipv6 address prefix-list", acl,
- RMAP_EVENT_PLIST_ADDED);
- break;
- default:
+ rhc->rhc_rmi, "ipv6 address prefix-list", acl,
+ RMAP_EVENT_PLIST_ADDED,
+ args->errmsg, args->errmsg_len);
+ } else
rv = CMD_ERR_NO_MATCH;
- break;
- }
+
if (rv != CMD_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -642,8 +644,9 @@ static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify(
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
rv = rmap_match_set_hook.match_ip_next_hop_type(
- NULL, rhc->rhc_rmi, "ip next-hop type", type,
- RMAP_EVENT_MATCH_ADDED);
+ rhc->rhc_rmi, "ip next-hop type", type,
+ RMAP_EVENT_MATCH_ADDED,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -685,8 +688,9 @@ static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify(
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
rv = rmap_match_set_hook.match_ipv6_next_hop_type(
- NULL, rhc->rhc_rmi, "ipv6 next-hop type", type,
- RMAP_EVENT_MATCH_ADDED);
+ rhc->rhc_rmi, "ipv6 next-hop type", type,
+ RMAP_EVENT_MATCH_ADDED,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -727,8 +731,9 @@ static int lib_route_map_entry_match_condition_metric_modify(
rhc->rhc_rule = "metric";
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
- rv = rmap_match_set_hook.match_metric(NULL, rhc->rhc_rmi, "metric",
- type, RMAP_EVENT_MATCH_ADDED);
+ rv = rmap_match_set_hook.match_metric(rhc->rhc_rmi, "metric",
+ type, RMAP_EVENT_MATCH_ADDED,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -769,8 +774,9 @@ lib_route_map_entry_match_condition_tag_modify(struct nb_cb_modify_args *args)
rhc->rhc_rule = "tag";
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
- rv = rmap_match_set_hook.match_tag(NULL, rhc->rhc_rmi, "tag", tag,
- RMAP_EVENT_MATCH_ADDED);
+ rv = rmap_match_set_hook.match_tag(rhc->rhc_rmi, "tag", tag,
+ RMAP_EVENT_MATCH_ADDED,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -850,8 +856,9 @@ static int lib_route_map_entry_set_action_ipv4_address_modify(
rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop;
rhc->rhc_rule = "ip next-hop";
- rv = rmap_match_set_hook.set_ip_nexthop(NULL, rhc->rhc_rmi,
- "ip next-hop", address);
+ rv = rmap_match_set_hook.set_ip_nexthop(rhc->rhc_rmi, "ip next-hop",
+ address,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_shook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -909,7 +916,8 @@ static int lib_route_map_entry_set_action_ipv6_address_modify(
rhc->rhc_rule = "ipv6 next-hop local";
rv = rmap_match_set_hook.set_ipv6_nexthop_local(
- NULL, rhc->rhc_rmi, "ipv6 next-hop local", address);
+ rhc->rhc_rmi, "ipv6 next-hop local", address,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_shook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -928,7 +936,8 @@ static int lib_route_map_entry_set_action_ipv6_address_destroy(
* XPath: /frr-route-map:lib/route-map/entry/set-action/value
*/
static int set_action_modify(enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource, const char *value)
+ union nb_resource *resource, const char *value,
+ char *errmsg, size_t errmsg_len)
{
struct routemap_hook_context *rhc;
int rv;
@@ -952,8 +961,10 @@ static int set_action_modify(enum nb_event event, const struct lyd_node *dnode,
rhc->rhc_shook = rmap_match_set_hook.no_set_metric;
rhc->rhc_rule = "metric";
- rv = rmap_match_set_hook.set_metric(NULL, rhc->rhc_rmi, "metric",
- value);
+ rv = rmap_match_set_hook.set_metric(rhc->rhc_rmi, "metric",
+ value,
+ errmsg, errmsg_len
+ );
if (rv != CMD_SUCCESS) {
rhc->rhc_shook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -968,7 +979,7 @@ lib_route_map_entry_set_action_value_modify(struct nb_cb_modify_args *args)
const char *metric = yang_dnode_get_string(args->dnode, NULL);
return set_action_modify(args->event, args->dnode, args->resource,
- metric);
+ metric, args->errmsg, args->errmsg_len);
}
static int
@@ -995,7 +1006,8 @@ lib_route_map_entry_set_action_add_metric_modify(struct nb_cb_modify_args *args)
snprintf(metric_str, sizeof(metric_str), "+%s",
yang_dnode_get_string(args->dnode, NULL));
return set_action_modify(args->event, args->dnode, args->resource,
- metric_str);
+ metric_str,
+ args->errmsg, args->errmsg_len);
}
static int lib_route_map_entry_set_action_add_metric_destroy(
@@ -1022,7 +1034,8 @@ static int lib_route_map_entry_set_action_subtract_metric_modify(
snprintf(metric_str, sizeof(metric_str), "-%s",
yang_dnode_get_string(args->dnode, NULL));
return set_action_modify(args->event, args->dnode, args->resource,
- metric_str);
+ metric_str,
+ args->errmsg, args->errmsg_len);
}
static int lib_route_map_entry_set_action_subtract_metric_destroy(
@@ -1038,7 +1051,8 @@ static int lib_route_map_entry_set_action_use_round_trip_time_modify(
struct nb_cb_modify_args *args)
{
return set_action_modify(args->event, args->dnode, args->resource,
- "rtt");
+ "rtt",
+ args->errmsg, args->errmsg_len);
}
static int lib_route_map_entry_set_action_use_round_trip_time_destroy(
@@ -1054,7 +1068,8 @@ static int lib_route_map_entry_set_action_add_round_trip_time_modify(
struct nb_cb_modify_args *args)
{
return set_action_modify(args->event, args->dnode, args->resource,
- "+rtt");
+ "+rtt",
+ args->errmsg, args->errmsg_len);
}
static int lib_route_map_entry_set_action_add_round_trip_time_destroy(
@@ -1070,7 +1085,7 @@ static int lib_route_map_entry_set_action_subtract_round_trip_time_modify(
struct nb_cb_modify_args *args)
{
return set_action_modify(args->event, args->dnode, args->resource,
- "-rtt");
+ "-rtt", args->errmsg, args->errmsg_len);
}
static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy(
@@ -1109,7 +1124,8 @@ lib_route_map_entry_set_action_tag_modify(struct nb_cb_modify_args *args)
rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
rhc->rhc_rule = "tag";
- rv = rmap_match_set_hook.set_tag(NULL, rhc->rhc_rmi, "tag", tag);
+ rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "tag", tag,
+ args->errmsg, args->errmsg_len);
if (rv != CMD_SUCCESS) {
rhc->rhc_shook = NULL;
return NB_ERR_INCONSISTENCY;
@@ -1124,6 +1140,52 @@ lib_route_map_entry_set_action_tag_destroy(struct nb_cb_destroy_args *args)
return lib_route_map_entry_set_destroy(args);
}
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/policy
+ */
+static int
+lib_route_map_entry_set_action_policy_modify(struct nb_cb_modify_args *args)
+{
+ struct routemap_hook_context *rhc;
+ const char *policy;
+ int rv;
+
+ /*
+ * NOTE: validate if 'action' is 'tag', currently it is not
+ * necessary because this is the only implemented action. Other
+ * actions might have different validations.
+ */
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Check for hook function. */
+ if (rmap_match_set_hook.set_srte_color == NULL)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(args->dnode, NULL, true);
+ policy = yang_dnode_get_string(args->dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
+ rhc->rhc_rule = "sr-te color";
+
+ rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "sr-te color", policy,
+ args->errmsg, args->errmsg_len);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_policy_destroy(struct nb_cb_destroy_args *args)
+{
+ return lib_route_map_entry_set_destroy(args);
+}
+
/* clang-format off */
const struct frr_yang_module_info frr_route_map_info = {
.name = "frr-route-map",
@@ -1140,6 +1202,7 @@ const struct frr_yang_module_info frr_route_map_info = {
.cbs = {
.create = lib_route_map_entry_create,
.destroy = lib_route_map_entry_destroy,
+ .cli_cmp = route_map_instance_cmp,
.cli_show = route_map_instance_show,
.cli_show_end = route_map_instance_show_end,
}
@@ -1189,42 +1252,42 @@ const struct frr_yang_module_info frr_route_map_info = {
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/interface",
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/interface",
.cbs = {
.modify = lib_route_map_entry_match_condition_interface_modify,
.destroy = lib_route_map_entry_match_condition_interface_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name",
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/list-name",
.cbs = {
.modify = lib_route_map_entry_match_condition_list_name_modify,
.destroy = lib_route_map_entry_match_condition_list_name_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type",
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv4-next-hop-type",
.cbs = {
.modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify,
.destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type",
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv6-next-hop-type",
.cbs = {
.modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify,
.destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/metric",
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/metric",
.cbs = {
.modify = lib_route_map_entry_match_condition_metric_modify,
.destroy = lib_route_map_entry_match_condition_metric_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/tag",
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/tag",
.cbs = {
.modify = lib_route_map_entry_match_condition_tag_modify,
.destroy = lib_route_map_entry_match_condition_tag_destroy,
@@ -1239,69 +1302,77 @@ const struct frr_yang_module_info frr_route_map_info = {
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv4-address",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv4-address",
.cbs = {
.modify = lib_route_map_entry_set_action_ipv4_address_modify,
.destroy = lib_route_map_entry_set_action_ipv4_address_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv6-address",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv6-address",
.cbs = {
.modify = lib_route_map_entry_set_action_ipv6_address_modify,
.destroy = lib_route_map_entry_set_action_ipv6_address_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/value",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/value",
.cbs = {
.modify = lib_route_map_entry_set_action_value_modify,
.destroy = lib_route_map_entry_set_action_value_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-metric",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-metric",
.cbs = {
.modify = lib_route_map_entry_set_action_add_metric_modify,
.destroy = lib_route_map_entry_set_action_add_metric_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-metric",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-metric",
.cbs = {
.modify = lib_route_map_entry_set_action_subtract_metric_modify,
.destroy = lib_route_map_entry_set_action_subtract_metric_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/use-round-trip-time",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/use-round-trip-time",
.cbs = {
.modify = lib_route_map_entry_set_action_use_round_trip_time_modify,
.destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-round-trip-time",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-round-trip-time",
.cbs = {
.modify = lib_route_map_entry_set_action_add_round_trip_time_modify,
.destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-round-trip-time",
.cbs = {
.modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify,
.destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy,
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/set-action/tag",
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/tag",
.cbs = {
.modify = lib_route_map_entry_set_action_tag_modify,
.destroy = lib_route_map_entry_set_action_tag_destroy,
}
},
{
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/policy",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_policy_modify,
+ .destroy = lib_route_map_entry_set_action_policy_destroy,
+ }
+ },
+
+ {
.xpath = NULL,
},
}
diff --git a/lib/sockunion.c b/lib/sockunion.c
index d65235b41c..e6340a1743 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -664,54 +664,76 @@ void sockunion_init(union sockunion *su)
}
printfrr_ext_autoreg_p("SU", printfrr_psu)
-static ssize_t printfrr_psu(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_psu(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
const union sockunion *su = ptr;
- struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 };
- bool include_port = false;
+ bool include_port = false, include_scope = false;
bool endflags = false;
- ssize_t consumed = 2;
-
- if (su) {
- while (!endflags) {
- switch (fmt[consumed++]) {
- case 'p':
- include_port = true;
- break;
- default:
- consumed--;
- endflags = true;
- break;
- }
- };
-
- switch (sockunion_family(su)) {
- case AF_UNSPEC:
- bprintfrr(&fb, "(unspec)");
- break;
- case AF_INET:
- inet_ntop(AF_INET, &su->sin.sin_addr, buf, bsz);
- fb.pos += strlen(fb.buf);
- if (include_port)
- bprintfrr(&fb, ":%d", su->sin.sin_port);
+ ssize_t ret = 0;
+ char cbuf[INET6_ADDRSTRLEN];
+
+ if (!su)
+ return bputs(buf, "(null)");
+
+ while (!endflags) {
+ switch (*ea->fmt) {
+ case 'p':
+ ea->fmt++;
+ include_port = true;
break;
- case AF_INET6:
- inet_ntop(AF_INET6, &su->sin6.sin6_addr, buf, bsz);
- fb.pos += strlen(fb.buf);
- if (include_port)
- bprintfrr(&fb, ":%d", su->sin6.sin6_port);
+ case 's':
+ ea->fmt++;
+ include_scope = true;
break;
default:
- bprintfrr(&fb, "(af %d)", sockunion_family(su));
+ endflags = true;
+ break;
}
+ }
- fb.pos[0] = '\0';
- } else {
- strlcpy(buf, "NULL", bsz);
+ switch (sockunion_family(su)) {
+ case AF_UNSPEC:
+ ret += bputs(buf, "(unspec)");
+ break;
+ case AF_INET:
+ inet_ntop(AF_INET, &su->sin.sin_addr, cbuf, sizeof(cbuf));
+ ret += bputs(buf, cbuf);
+ if (include_port)
+ ret += bprintfrr(buf, ":%d", ntohs(su->sin.sin_port));
+ break;
+ case AF_INET6:
+ if (include_port)
+ ret += bputch(buf, '[');
+ inet_ntop(AF_INET6, &su->sin6.sin6_addr, cbuf, sizeof(cbuf));
+ ret += bputs(buf, cbuf);
+ if (include_scope && su->sin6.sin6_scope_id)
+ ret += bprintfrr(buf, "%%%u",
+ (unsigned int)su->sin6.sin6_scope_id);
+ if (include_port)
+ ret += bprintfrr(buf, "]:%d",
+ ntohs(su->sin6.sin6_port));
+ break;
+ case AF_UNIX: {
+ int len;
+#ifdef __linux__
+ if (su->sun.sun_path[0] == '\0' && su->sun.sun_path[1]) {
+ len = strnlen(su->sun.sun_path + 1,
+ sizeof(su->sun.sun_path) - 1);
+ ret += bprintfrr(buf, "@%*pSE", len,
+ su->sun.sun_path + 1);
+ break;
+ }
+#endif
+ len = strnlen(su->sun.sun_path, sizeof(su->sun.sun_path));
+ ret += bprintfrr(buf, "%*pSE", len, su->sun.sun_path);
+ break;
+ }
+ default:
+ ret += bprintfrr(buf, "(af %d)", sockunion_family(su));
}
- return consumed;
+ return ret;
}
int sockunion_is_null(const union sockunion *su)
@@ -730,3 +752,49 @@ int sockunion_is_null(const union sockunion *su)
return 0;
}
}
+
+printfrr_ext_autoreg_i("PF", printfrr_pf)
+static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea,
+ uintmax_t val)
+{
+ switch (val) {
+ case AF_INET:
+ return bputs(buf, "AF_INET");
+ case AF_INET6:
+ return bputs(buf, "AF_INET6");
+ case AF_UNIX:
+ return bputs(buf, "AF_UNIX");
+#ifdef AF_PACKET
+ case AF_PACKET:
+ return bputs(buf, "AF_PACKET");
+#endif
+#ifdef AF_NETLINK
+ case AF_NETLINK:
+ return bputs(buf, "AF_NETLINK");
+#endif
+ }
+ return bprintfrr(buf, "AF_(%ju)", val);
+}
+
+printfrr_ext_autoreg_i("SO", printfrr_so)
+static ssize_t printfrr_so(struct fbuf *buf, struct printfrr_eargs *ea,
+ uintmax_t val)
+{
+ switch (val) {
+ case SOCK_STREAM:
+ return bputs(buf, "SOCK_STREAM");
+ case SOCK_DGRAM:
+ return bputs(buf, "SOCK_DGRAM");
+ case SOCK_SEQPACKET:
+ return bputs(buf, "SOCK_SEQPACKET");
+#ifdef SOCK_RAW
+ case SOCK_RAW:
+ return bputs(buf, "SOCK_RAW");
+#endif
+#ifdef SOCK_PACKET
+ case SOCK_PACKET:
+ return bputs(buf, "SOCK_PACKET");
+#endif
+ }
+ return bprintfrr(buf, "SOCK_(%ju)", val);
+}
diff --git a/lib/sockunion.h b/lib/sockunion.h
index 5e80ba1090..2cc80bb70f 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -24,6 +24,7 @@
#include "privs.h"
#include "if.h"
+#include <sys/un.h>
#ifdef __OpenBSD__
#include <netmpls/mpls.h>
#endif
@@ -36,6 +37,7 @@ union sockunion {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
+ struct sockaddr_un sun;
#ifdef __OpenBSD__
struct sockaddr_mpls smpls;
struct sockaddr_rtlabel rtlabel;
@@ -106,6 +108,16 @@ extern int sockunion_is_null(const union sockunion *su);
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pSU" (union sockunion *)
+#pragma FRR printfrr_ext "%pSU" (struct sockaddr *)
+#pragma FRR printfrr_ext "%pSU" (struct sockaddr_storage *)
+#pragma FRR printfrr_ext "%pSU" (struct sockaddr_in *)
+#pragma FRR printfrr_ext "%pSU" (struct sockaddr_in6 *)
+#pragma FRR printfrr_ext "%pSU" (struct sockaddr_un *)
+
+/* AF_INET/PF_INET & co., using "PF" to avoid confusion with AFI/SAFI */
+#pragma FRR printfrr_ext "%dPF" (int)
+/* SOCK_STREAM & co. */
+#pragma FRR printfrr_ext "%dSO" (int)
#endif
#ifdef __cplusplus
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index a115507192..d2e0682e95 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -307,20 +307,20 @@ const char *srcdest_rnode2str(const struct route_node *rn, char *str, int size)
}
printfrr_ext_autoreg_p("RN", printfrr_rn)
-static ssize_t printfrr_rn(char *buf, size_t bsz, const char *fmt,
- int prec, const void *ptr)
+static ssize_t printfrr_rn(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
{
const struct route_node *rn = ptr;
const struct prefix *dst_p, *src_p;
+ char cbuf[PREFIX_STRLEN * 2 + 6];
- if (rn) {
- srcdest_rnode_prefixes(rn, &dst_p, &src_p);
- srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, buf, bsz);
- } else {
- strlcpy(buf, "NULL", bsz);
- }
+ if (!rn)
+ return bputs(buf, "(null)");
- return 2;
+ srcdest_rnode_prefixes(rn, &dst_p, &src_p);
+ srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p,
+ cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
}
struct route_table *srcdest_srcnode_table(struct route_node *rn)
diff --git a/lib/strformat.c b/lib/strformat.c
new file mode 100644
index 0000000000..431e573a0c
--- /dev/null
+++ b/lib/strformat.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2019 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "compiler.h"
+
+#include <string.h>
+#include <ctype.h>
+
+#include "printfrr.h"
+
+printfrr_ext_autoreg_p("HX", printfrr_hexdump)
+static ssize_t printfrr_hexdump(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ ssize_t ret = 0;
+ ssize_t input_len = printfrr_ext_len(ea);
+ char sep = ' ';
+ const uint8_t *pos, *end;
+
+ if (ea->fmt[0] == 'c') {
+ ea->fmt++;
+ sep = ':';
+ } else if (ea->fmt[0] == 'n') {
+ ea->fmt++;
+ sep = '\0';
+ }
+
+ if (input_len < 0)
+ return 0;
+
+ for (pos = ptr, end = pos + input_len; pos < end; pos++) {
+ if (sep && pos != ptr)
+ ret += bputch(buf, sep);
+ ret += bputhex(buf, *pos);
+ }
+
+ return ret;
+}
+
+/* string analog for hexdumps / the "this." in ("74 68 69 73 0a |this.|") */
+
+printfrr_ext_autoreg_p("HS", printfrr_hexdstr)
+static ssize_t printfrr_hexdstr(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ ssize_t ret = 0;
+ ssize_t input_len = printfrr_ext_len(ea);
+ const uint8_t *pos, *end;
+
+ if (input_len < 0)
+ return 0;
+
+ for (pos = ptr, end = pos + input_len; pos < end; pos++) {
+ if (*pos >= 0x20 && *pos < 0x7f)
+ ret += bputch(buf, *pos);
+ else
+ ret += bputch(buf, '.');
+ }
+
+ return ret;
+}
+
+enum escape_flags {
+ ESC_N_R_T = (1 << 0), /* use \n \r \t instead of \x0a ...*/
+ ESC_SPACE = (1 << 1), /* \ */
+ ESC_BACKSLASH = (1 << 2), /* \\ */
+ ESC_DBLQUOTE = (1 << 3), /* \" */
+ ESC_SGLQUOTE = (1 << 4), /* \' */
+ ESC_BACKTICK = (1 << 5), /* \` */
+ ESC_DOLLAR = (1 << 6), /* \$ */
+ ESC_CLBRACKET = (1 << 7), /* \] for RFC5424 syslog */
+ ESC_OTHER = (1 << 8), /* remaining non-alpha */
+
+ ESC_ALL = ESC_N_R_T | ESC_SPACE | ESC_BACKSLASH | ESC_DBLQUOTE
+ | ESC_SGLQUOTE | ESC_DOLLAR | ESC_OTHER,
+ ESC_QUOTSTRING = ESC_N_R_T | ESC_BACKSLASH | ESC_DBLQUOTE,
+ /* if needed: ESC_SHELL = ... */
+};
+
+static ssize_t bquote(struct fbuf *buf, const uint8_t *pos, size_t len,
+ unsigned int flags)
+{
+ ssize_t ret = 0;
+ const uint8_t *end = pos + len;
+
+ for (; pos < end; pos++) {
+ /* here's to hoping this might be a bit faster... */
+ if (__builtin_expect(!!isalnum(*pos), 1)) {
+ ret += bputch(buf, *pos);
+ continue;
+ }
+
+ switch (*pos) {
+ case '%':
+ case '+':
+ case ',':
+ case '-':
+ case '.':
+ case '/':
+ case ':':
+ case '@':
+ case '_':
+ ret += bputch(buf, *pos);
+ continue;
+
+ case '\r':
+ if (!(flags & ESC_N_R_T))
+ break;
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, 'r');
+ continue;
+ case '\n':
+ if (!(flags & ESC_N_R_T))
+ break;
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, 'n');
+ continue;
+ case '\t':
+ if (!(flags & ESC_N_R_T))
+ break;
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, 't');
+ continue;
+
+ case ' ':
+ if (flags & ESC_SPACE)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+
+ case '\\':
+ if (flags & ESC_BACKSLASH)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+
+ case '"':
+ if (flags & ESC_DBLQUOTE)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+
+ case '\'':
+ if (flags & ESC_SGLQUOTE)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+
+ case '`':
+ if (flags & ESC_BACKTICK)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+
+ case '$':
+ if (flags & ESC_DOLLAR)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+
+ case ']':
+ if (flags & ESC_CLBRACKET)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+
+ /* remaining: !#&'()*;<=>?[^{|}~ */
+
+ default:
+ if (*pos >= 0x20 && *pos < 0x7f) {
+ if (flags & ESC_OTHER)
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, *pos);
+ continue;
+ }
+ }
+ ret += bputch(buf, '\\');
+ ret += bputch(buf, 'x');
+ ret += bputhex(buf, *pos);
+ }
+
+ return ret;
+}
+
+printfrr_ext_autoreg_p("SE", printfrr_escape)
+static ssize_t printfrr_escape(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *vptr)
+{
+ ssize_t len = printfrr_ext_len(ea);
+ const uint8_t *ptr = vptr;
+ bool null_is_empty = false;
+
+ if (ea->fmt[0] == 'n') {
+ null_is_empty = true;
+ ea->fmt++;
+ }
+
+ if (!ptr) {
+ if (null_is_empty)
+ return 0;
+ return bputs(buf, "(null)");
+ }
+
+ if (len < 0)
+ len = strlen((const char *)ptr);
+
+ return bquote(buf, ptr, len, ESC_ALL);
+}
+
+printfrr_ext_autoreg_p("SQ", printfrr_quote)
+static ssize_t printfrr_quote(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *vptr)
+{
+ ssize_t len = printfrr_ext_len(ea);
+ const uint8_t *ptr = vptr;
+ ssize_t ret = 0;
+ bool null_is_empty = false;
+ bool do_quotes = false;
+ unsigned int flags = ESC_QUOTSTRING;
+
+ while (ea->fmt[0]) {
+ switch (ea->fmt[0]) {
+ case 'n':
+ null_is_empty = true;
+ ea->fmt++;
+ continue;
+ case 'q':
+ do_quotes = true;
+ ea->fmt++;
+ continue;
+ case 's':
+ flags |= ESC_CLBRACKET;
+ flags &= ~ESC_N_R_T;
+ ea->fmt++;
+ continue;
+ }
+ break;
+ }
+
+ if (!ptr) {
+ if (null_is_empty)
+ return bputs(buf, do_quotes ? "\"\"" : "");
+ return bputs(buf, "(null)");
+ }
+
+ if (len < 0)
+ len = strlen((const char *)ptr);
+
+ if (do_quotes)
+ ret += bputch(buf, '"');
+ ret += bquote(buf, ptr, len, flags);
+ if (do_quotes)
+ ret += bputch(buf, '"');
+ return ret;
+}
diff --git a/lib/subdir.am b/lib/subdir.am
index bfd367b134..0853d4bb2b 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -90,6 +90,7 @@ lib_libfrr_la_SOURCES = \
lib/spf_backoff.c \
lib/srcdest_table.c \
lib/stream.c \
+ lib/strformat.c \
lib/strlcat.c \
lib/strlcpy.c \
lib/systemd.c \
diff --git a/lib/vrf.c b/lib/vrf.c
index dff041cbc7..7888d435f5 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -1110,7 +1110,7 @@ static int lib_vrf_create(struct nb_cb_create_args *args)
vrfp = vrf_get(VRF_UNKNOWN, vrfname);
- vrf_set_user_cfged(vrfp);
+ SET_FLAG(vrfp->status, VRF_CONFIGURED);
nb_running_set_entry(args->dnode, vrfp);
return NB_OK;
@@ -1136,7 +1136,7 @@ static int lib_vrf_destroy(struct nb_cb_destroy_args *args)
vrfp = nb_running_unset_entry(args->dnode);
/* Clear configured flag and invoke delete. */
- vrf_reset_user_cfged(vrfp);
+ UNSET_FLAG(vrfp->status, VRF_CONFIGURED);
vrf_delete(vrfp);
break;
}
diff --git a/lib/vrf.h b/lib/vrf.h
index 6cdb52244d..c79dd99b9a 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -159,18 +159,6 @@ static inline int vrf_is_user_cfged(struct vrf *vrf)
return vrf && CHECK_FLAG(vrf->status, VRF_CONFIGURED);
}
-/* Mark that VRF has user configuration */
-static inline void vrf_set_user_cfged(struct vrf *vrf)
-{
- SET_FLAG(vrf->status, VRF_CONFIGURED);
-}
-
-/* Mark that VRF no longer has any user configuration */
-static inline void vrf_reset_user_cfged(struct vrf *vrf)
-{
- UNSET_FLAG(vrf->status, VRF_CONFIGURED);
-}
-
static inline uint32_t vrf_interface_count(struct vrf *vrf)
{
uint32_t count = 0;
diff --git a/lib/vty.c b/lib/vty.c
index d44cc904c5..96cfef1c0a 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -159,6 +159,8 @@ int vty_out(struct vty *vty, const char *format, ...)
char buf[1024];
char *p = NULL;
char *filtered;
+ /* format string may contain %m, keep errno intact for printfrr */
+ int saved_errno = errno;
if (vty->frame_pos) {
vty->frame_pos = 0;
@@ -166,6 +168,7 @@ int vty_out(struct vty *vty, const char *format, ...)
}
va_start(args, format);
+ errno = saved_errno;
p = vasnprintfrr(MTYPE_VTY_OUT_BUF, buf, sizeof(buf), format, args);
va_end(args);
diff --git a/lib/zclient.h b/lib/zclient.h
index 5b2298c42d..bd952ea1e6 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -1134,7 +1134,7 @@ int zapi_opaque_reg_decode(struct stream *msg,
*/
enum zapi_opaque_registry {
/* Request link-state database dump, at restart for example */
- LINK_STATE_REQUEST = 1,
+ LINK_STATE_SYNC = 1,
/* Update containing link-state db info */
LINK_STATE_UPDATE = 2,
/* Request LDP-SYNC state from LDP */