summaryrefslogtreecommitdiff
path: root/lib/link_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/link_state.c')
-rw-r--r--lib/link_state.c1425
1 files changed, 1308 insertions, 117 deletions
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__);
}