]> git.proxmox.com Git - mirror_frr.git/blob - lib/link_state.c
Merge pull request #8008 from chiragshah6/yang_nb5
[mirror_frr.git] / lib / link_state.c
1 /*
2 * Link State Database - link_state.c
3 *
4 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
5 *
6 * Copyright (C) 2020 Orange http://www.orange.com
7 *
8 * This file is part of Free Range Routing (FRR).
9 *
10 * FRR is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * FRR is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "if.h"
26 #include "linklist.h"
27 #include "log.h"
28 #include "command.h"
29 #include "termtable.h"
30 #include "memory.h"
31 #include "prefix.h"
32 #include "table.h"
33 #include "vty.h"
34 #include "zclient.h"
35 #include "stream.h"
36 #include "link_state.h"
37
38 /* Link State Memory allocation */
39 DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database")
40
41 /**
42 * Link State Node management functions
43 */
44 struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid,
45 struct in6_addr rid6)
46 {
47 struct ls_node *new;
48
49 if (adv.origin == NONE)
50 return NULL;
51
52 new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node));
53 new->adv = adv;
54 if (!IPV4_NET0(rid.s_addr)) {
55 new->router_id = rid;
56 SET_FLAG(new->flags, LS_NODE_ROUTER_ID);
57 } else {
58 if (adv.origin == OSPFv2 || adv.origin == STATIC
59 || adv.origin == DIRECT) {
60 new->router_id = adv.id.ip.addr;
61 SET_FLAG(new->flags, LS_NODE_ROUTER_ID);
62 }
63 }
64 if (!IN6_IS_ADDR_UNSPECIFIED(&rid6)) {
65 new->router6_id = rid6;
66 SET_FLAG(new->flags, LS_NODE_ROUTER_ID6);
67 }
68 return new;
69 }
70
71 void ls_node_del(struct ls_node *node)
72 {
73 XFREE(MTYPE_LS_DB, node);
74 node = NULL;
75 }
76
77 int ls_node_same(struct ls_node *n1, struct ls_node *n2)
78 {
79 if ((n1 && !n2) || (!n1 && n2))
80 return 0;
81
82 if (n1 == n2)
83 return 1;
84
85 if (n1->flags != n2->flags)
86 return 0;
87
88 if (n1->adv.origin != n2->adv.origin)
89 return 0;
90
91 if (!memcmp(&n1->adv.id, &n2->adv.id, sizeof(struct ls_node_id)))
92 return 0;
93
94 /* Do we need to test individually each field, instead performing a
95 * global memcmp? There is a risk that an old value that is bit masked
96 * i.e. corresponding flag = 0, will result into a false negative
97 */
98 if (!memcmp(n1, n2, sizeof(struct ls_node)))
99 return 0;
100 else
101 return 1;
102 }
103
104 /**
105 * Link State Attributes management functions
106 */
107 struct ls_attributes *ls_attributes_new(struct ls_node_id adv,
108 struct in_addr local,
109 struct in6_addr local6,
110 uint32_t local_id)
111 {
112 struct ls_attributes *new;
113
114 if (adv.origin == NONE)
115 return NULL;
116
117 new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes));
118 new->adv = adv;
119 if (!IPV4_NET0(local.s_addr)) {
120 new->standard.local = local;
121 SET_FLAG(new->flags, LS_ATTR_LOCAL_ADDR);
122 }
123 if (!IN6_IS_ADDR_UNSPECIFIED(&local6)) {
124 new->standard.local6 = local6;
125 SET_FLAG(new->flags, LS_ATTR_LOCAL_ADDR6);
126 }
127 if (local_id != 0) {
128 new->standard.local_id = local_id;
129 SET_FLAG(new->flags, LS_ATTR_LOCAL_ID);
130 }
131
132 /* Check that almost one identifier is set */
133 if (!CHECK_FLAG(new->flags, LS_ATTR_LOCAL_ADDR | LS_ATTR_LOCAL_ADDR6
134 | LS_ATTR_LOCAL_ID)) {
135 XFREE(MTYPE_LS_DB, new);
136 return NULL;
137 }
138
139 return new;
140 }
141
142 void ls_attributes_del(struct ls_attributes *attr)
143 {
144 if (!attr)
145 return;
146
147 if (attr->srlgs)
148 XFREE(MTYPE_LS_DB, attr->srlgs);
149
150 XFREE(MTYPE_LS_DB, attr);
151 attr = NULL;
152 }
153
154 int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2)
155 {
156 if ((l1 && !l2) || (!l1 && l2))
157 return 0;
158
159 if (l1 == l2)
160 return 1;
161
162 if (l1->flags != l2->flags)
163 return 0;
164
165 if (l1->adv.origin != l2->adv.origin)
166 return 0;
167
168 if (!memcmp(&l1->adv.id, &l2->adv.id, sizeof(struct ls_node_id)))
169 return 0;
170
171 /* Do we need to test individually each field, instead performing a
172 * global memcmp? There is a risk that an old value that is bit masked
173 * i.e. corresponding flag = 0, will result into a false negative
174 */
175 if (!memcmp(l1, l2, sizeof(struct ls_attributes)))
176 return 0;
177 else
178 return 1;
179 }
180
181 /**
182 * Link State Vertices management functions
183 */
184 struct ls_vertex *ls_vertex_new(struct ls_node *node)
185 {
186 struct ls_vertex *new;
187
188 if (node == NULL)
189 return NULL;
190
191 new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_vertex));
192 new->node = node;
193 new->incoming_edges = list_new();
194 new->outgoing_edges = list_new();
195 new->prefixes = list_new();
196
197 return new;
198 }
199
200 void ls_vertex_del(struct ls_vertex *vertex)
201 {
202 if (vertex == NULL)
203 return;
204
205 list_delete_all_node(vertex->incoming_edges);
206 list_delete_all_node(vertex->outgoing_edges);
207 list_delete_all_node(vertex->prefixes);
208 XFREE(MTYPE_LS_DB, vertex);
209 vertex = NULL;
210 }
211
212 struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node)
213 {
214 struct ls_vertex *new;
215
216 if ((ted == NULL) || (node == NULL))
217 return NULL;
218
219 new = ls_vertex_new(node);
220 if (!new)
221 return NULL;
222
223 /* set Key as the IPv4/Ipv6 Router ID or ISO System ID */
224 switch (node->adv.origin) {
225 case OSPFv2:
226 case STATIC:
227 case DIRECT:
228 memcpy(&new->key, &node->adv.id.ip.addr, IPV4_MAX_BYTELEN);
229 break;
230 case ISIS_L1:
231 case ISIS_L2:
232 memcpy(&new->key, &node->adv.id.iso.sys_id, ISO_SYS_ID_LEN);
233 break;
234 default:
235 new->key = 0;
236 break;
237 }
238
239 /* Remove Vertex if key is not set */
240 if (new->key == 0) {
241 ls_vertex_del(new);
242 return NULL;
243 }
244
245 /* Add Vertex to TED */
246 vertices_add(&ted->vertices, new);
247
248 return new;
249 }
250
251 struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node)
252 {
253 struct ls_vertex *old;
254
255 if (node == NULL)
256 return NULL;
257
258 old = ls_find_vertex_by_id(ted, node->adv);
259 if (old) {
260 if (!ls_node_same(old->node, node)) {
261 ls_node_del(old->node);
262 old->node = node;
263 }
264 return old;
265 }
266
267 return ls_vertex_add(ted, node);
268 }
269
270 void ls_vertex_remove(struct ls_ted *ted, struct ls_vertex *vertex)
271 {
272 vertices_del(&ted->vertices, vertex);
273 ls_vertex_del(vertex);
274 }
275
276 struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key)
277 {
278 struct ls_vertex node = {};
279
280 if (key == 0)
281 return NULL;
282
283 node.key = key;
284 return vertices_find(&ted->vertices, &node);
285 }
286
287 struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted,
288 struct ls_node_id nid)
289 {
290 struct ls_vertex node = {};
291
292 switch (nid.origin) {
293 case OSPFv2:
294 case STATIC:
295 case DIRECT:
296 memcpy(&node.key, &nid.id.ip.addr, IPV4_MAX_BYTELEN);
297 break;
298 case ISIS_L1:
299 case ISIS_L2:
300 memcpy(&node.key, &nid.id.iso.sys_id, ISO_SYS_ID_LEN);
301 break;
302 default:
303 return NULL;
304 }
305
306 return vertices_find(&ted->vertices, &node);
307 }
308
309 int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2)
310 {
311 if ((v1 && !v2) || (!v1 && v2))
312 return 0;
313
314 if (!v1 && !v2)
315 return 1;
316
317 if (v1->key != v2->key)
318 return 0;
319
320 if (v1->node == v2->node)
321 return 1;
322
323 return ls_node_same(v1->node, v2->node);
324 }
325
326 /**
327 * Link State Edges management functions
328 */
329
330 /**
331 * This function allows to connect the Edge to the vertices present in the TED.
332 * A temporary vertex that corresponds to the source of this Edge i.e. the
333 * advertised router, is created if not found in the Data Base. If a Edge that
334 * corresponds to the reverse path is found, the Edge is attached to the
335 * destination vertex as destination and reverse Edge is attached to the source
336 * vertex as source.
337 *
338 * @param ted Link State Data Base
339 * @param edge Link State Edge to be attached
340 */
341 static void ls_edge_connect_to(struct ls_ted *ted, struct ls_edge *edge)
342 {
343 struct ls_vertex *vertex = NULL;
344 struct ls_node *node;
345 struct ls_edge *dst;
346 const struct in_addr inaddr_any = {.s_addr = INADDR_ANY};
347
348 /* First, search if there is a Vertex that correspond to the Node ID */
349 vertex = ls_find_vertex_by_id(ted, edge->attributes->adv);
350 if (vertex == NULL) {
351 /* Create a new temporary Node & Vertex if not found */
352 node = ls_node_new(edge->attributes->adv, inaddr_any,
353 in6addr_any);
354 vertex = ls_vertex_add(ted, node);
355 }
356 /* and attach the edge as source to the vertex */
357 listnode_add(vertex->outgoing_edges, edge);
358 edge->source = vertex;
359
360 /* Then search if there is a reverse Edge */
361 dst = ls_find_edge_by_destination(ted, edge->attributes);
362 /* attach the destination edge to the vertex */
363 if (dst) {
364 listnode_add(vertex->incoming_edges, dst);
365 dst->destination = vertex;
366 /* and destination vertex to this edge */
367 vertex = dst->source;
368 listnode_add(vertex->incoming_edges, edge);
369 edge->destination = vertex;
370 }
371 }
372
373 struct ls_edge *ls_edge_add(struct ls_ted *ted,
374 struct ls_attributes *attributes)
375 {
376 struct ls_edge *new;
377
378 if (attributes == NULL)
379 return NULL;
380
381 new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge));
382 new->attributes = attributes;
383 /* Key is the IPv4 local address */
384 if (!IPV4_NET0(attributes->standard.local.s_addr))
385 new->key = ((uint64_t)attributes->standard.local.s_addr)
386 & 0xffffffff;
387 /* or the IPv6 local address if IPv4 is not defined */
388 else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6))
389 new->key = (uint64_t)(attributes->standard.local6.s6_addr32[0]
390 & 0xffffffff)
391 | ((uint64_t)attributes->standard.local6.s6_addr32[1]
392 << 32);
393 /* of local identifier if no IP addresses are defined */
394 else if (attributes->standard.local_id != 0)
395 new->key = (uint64_t)(
396 (attributes->standard.local_id & 0xffffffff)
397 | ((uint64_t)attributes->standard.remote_id << 32));
398
399 /* Remove Edge if key is not known */
400 if (new->key == 0) {
401 XFREE(MTYPE_LS_DB, new);
402 return NULL;
403 }
404
405 edges_add(&ted->edges, new);
406
407 /* Finally, connect edge to vertices */
408 ls_edge_connect_to(ted, new);
409
410 return new;
411 }
412
413 struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted, const uint64_t key)
414 {
415 struct ls_edge edge = {};
416
417 if (key == 0)
418 return NULL;
419
420 edge.key = key;
421 return edges_find(&ted->edges, &edge);
422 }
423
424 struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted,
425 struct ls_attributes *attributes)
426 {
427 struct ls_edge edge = {};
428
429 if (attributes == NULL)
430 return NULL;
431
432 /* Key is the IPv4 local address */
433 if (!IPV4_NET0(attributes->standard.local.s_addr))
434 edge.key = ((uint64_t)attributes->standard.local.s_addr)
435 & 0xffffffff;
436 /* or the IPv6 local address if IPv4 is not defined */
437 else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6))
438 edge.key = (uint64_t)(attributes->standard.local6.s6_addr32[0]
439 & 0xffffffff)
440 | ((uint64_t)attributes->standard.local6.s6_addr32[1]
441 << 32);
442 /* of local identifier if no IP addresses are defined */
443 else if (attributes->standard.local_id != 0)
444 edge.key = (uint64_t)(
445 (attributes->standard.local_id & 0xffffffff)
446 | ((uint64_t)attributes->standard.remote_id << 32));
447
448 if (edge.key == 0)
449 return NULL;
450
451 return edges_find(&ted->edges, &edge);
452 }
453
454 struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted,
455 struct ls_attributes *attributes)
456 {
457 struct ls_edge edge = {};
458
459 if (attributes == NULL)
460 return NULL;
461
462 /* Key is the IPv4 local address */
463 if (!IPV4_NET0(attributes->standard.remote.s_addr))
464 edge.key = ((uint64_t)attributes->standard.remote.s_addr)
465 & 0xffffffff;
466 /* or the IPv6 local address if IPv4 is not defined */
467 else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.remote6))
468 edge.key =
469 (uint64_t)(attributes->standard.remote6.s6_addr32[0]
470 & 0xffffffff)
471 | ((uint64_t)attributes->standard.remote6.s6_addr32[1]
472 << 32);
473 /* of local identifier if no IP addresses are defined */
474 else if (attributes->standard.remote_id != 0)
475 edge.key = (uint64_t)(
476 (attributes->standard.remote_id & 0xffffffff)
477 | ((uint64_t)attributes->standard.local_id << 32));
478
479 if (edge.key == 0)
480 return NULL;
481
482 return edges_find(&ted->edges, &edge);
483 }
484
485 struct ls_edge *ls_edge_update(struct ls_ted *ted,
486 struct ls_attributes *attributes)
487 {
488 struct ls_edge *old;
489
490 if (attributes == NULL)
491 return NULL;
492
493 /* First, search for an existing Edge */
494 old = ls_find_edge_by_source(ted, attributes);
495 if (old) {
496 /* Check if attributes are similar */
497 if (!ls_attributes_same(old->attributes, attributes)) {
498 ls_attributes_del(old->attributes);
499 old->attributes = attributes;
500 }
501 return old;
502 }
503
504 /* If not found, add new Edge from the attributes */
505 return ls_edge_add(ted, attributes);
506 }
507
508 void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge)
509 {
510 /* Fist disconnect Edge */
511 ls_disconnect_edge(edge);
512 /* Then remove it from the Data Base */
513 edges_del(&ted->edges, edge);
514 XFREE(MTYPE_LS_DB, edge);
515 }
516
517 /**
518 * Link State Subnet Management functions.
519 */
520 struct ls_subnet *ls_subnet_add(struct ls_ted *ted,
521 struct ls_prefix *ls_pref)
522 {
523 struct ls_subnet *new;
524 struct ls_vertex *vertex;
525 struct ls_node *node;
526 const struct in_addr inaddr_any = {.s_addr = INADDR_ANY};
527
528 if (ls_pref == NULL)
529 return NULL;
530
531 new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_subnet));
532 new->ls_pref = ls_pref;
533 new->key = ls_pref->pref;
534
535 /* Find Vertex */
536 vertex = ls_find_vertex_by_id(ted, ls_pref->adv);
537 if (vertex == NULL) {
538 /* Create a new temporary Node & Vertex if not found */
539 node = ls_node_new(ls_pref->adv, inaddr_any, in6addr_any);
540 vertex = ls_vertex_add(ted, node);
541 }
542 /* And attach the subnet to the corresponding Vertex */
543 new->vertex = vertex;
544 listnode_add(vertex->prefixes, new);
545
546 subnets_add(&ted->subnets, new);
547
548 return new;
549 }
550
551 void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet)
552 {
553 subnets_del(&ted->subnets, subnet);
554 XFREE(MTYPE_LS_DB, subnet);
555 }
556
557 struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix)
558 {
559 struct ls_subnet subnet = {};
560
561 subnet.key = prefix;
562 return subnets_find(&ted->subnets, &subnet);
563 }
564
565 /**
566 * Link State TED management functions
567 */
568 struct ls_ted *ls_ted_new(const uint32_t key, const char *name,
569 uint32_t as_number)
570 {
571 struct ls_ted *new;
572
573 new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_ted));
574 if (new == NULL)
575 return new;
576
577 /* Set basic information for this ted */
578 new->key = key;
579 new->as_number = as_number;
580 strlcpy(new->name, name, MAX_NAME_LENGTH);
581
582 /* Initialize the various RB tree */
583 vertices_init(&new->vertices);
584 edges_init(&new->edges);
585 subnets_init(&new->subnets);
586
587 return new;
588 }
589
590 void ls_ted_del(struct ls_ted *ted)
591 {
592 if (ted == NULL)
593 return;
594
595 /* Release RB Tree */
596 vertices_fini(&ted->vertices);
597 edges_fini(&ted->edges);
598 subnets_fini(&ted->subnets);
599
600 XFREE(MTYPE_LS_DB, ted);
601 ted = NULL;
602 }
603
604 void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source)
605 {
606 if (vertex == NULL || edge == NULL)
607 return;
608
609 if (source) {
610 listnode_add(vertex->outgoing_edges, edge);
611 edge->source = vertex;
612 } else {
613 listnode_add(vertex->incoming_edges, edge);
614 edge->destination = vertex;
615 }
616 }
617
618 void ls_disconnect(struct ls_vertex *vertex, struct ls_edge *edge, bool source)
619 {
620
621 if (vertex == NULL || edge == NULL)
622 return;
623
624 if (source) {
625 listnode_delete(vertex->outgoing_edges, edge);
626 edge->source = NULL;
627 } else {
628 listnode_delete(vertex->incoming_edges, edge);
629 edge->destination = NULL;
630 }
631 }
632
633 void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst,
634 struct ls_edge *edge)
635 {
636 if (edge == NULL)
637 return;
638
639 edge->source = src;
640 edge->destination = dst;
641
642 if (src != NULL)
643 listnode_add(src->outgoing_edges, edge);
644
645 if (dst != NULL)
646 listnode_add(dst->incoming_edges, edge);
647
648 }
649
650 void ls_disconnect_edge(struct ls_edge *edge)
651 {
652 if (edge == NULL)
653 return;
654
655 ls_disconnect(edge->source, edge, true);
656 ls_disconnect(edge->destination, edge, false);
657 }
658
659 /**
660 * Link State Message management functions
661 */
662
663 static struct ls_node *ls_parse_node(struct stream *s)
664 {
665 struct ls_node *node;
666 size_t len;
667
668 node = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node));
669 if (node == NULL)
670 return NULL;
671
672 STREAM_GET(&node->adv, s, sizeof(struct ls_node_id));
673 STREAM_GETW(s, node->flags);
674 if (CHECK_FLAG(node->flags, LS_NODE_NAME)) {
675 STREAM_GETC(s, len);
676 STREAM_GET(node->name, s, len);
677 }
678 if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID))
679 node->router_id.s_addr = stream_get_ipv4(s);
680 if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID6))
681 STREAM_GET(&node->router6_id, s, IPV6_MAX_BYTELEN);
682 if (CHECK_FLAG(node->flags, LS_NODE_FLAG))
683 STREAM_GETC(s, node->node_flag);
684 if (CHECK_FLAG(node->flags, LS_NODE_TYPE))
685 STREAM_GETC(s, node->type);
686 if (CHECK_FLAG(node->flags, LS_NODE_AS_NUMBER))
687 STREAM_GETL(s, node->as_number);
688 if (CHECK_FLAG(node->flags, LS_NODE_SR)) {
689 STREAM_GETL(s, node->srgb.lower_bound);
690 STREAM_GETL(s, node->srgb.range_size);
691 STREAM_GETC(s, node->srgb.flag);
692 STREAM_GET(node->algo, s, 2);
693 }
694 if (CHECK_FLAG(node->flags, LS_NODE_SRLB)) {
695 STREAM_GETL(s, node->srlb.lower_bound);
696 STREAM_GETL(s, node->srlb.range_size);
697 }
698 if (CHECK_FLAG(node->flags, LS_NODE_MSD))
699 STREAM_GETC(s, node->msd);
700
701 return node;
702
703 stream_failure:
704 zlog_err("LS(%s): Could not parse Link State Node. Abort!", __func__);
705 XFREE(MTYPE_LS_DB, node);
706 return NULL;
707 }
708
709 static struct ls_attributes *ls_parse_attributes(struct stream *s)
710 {
711 struct ls_attributes *attr;
712 size_t len;
713
714 attr = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes));
715 if (attr == NULL)
716 return NULL;
717 attr->srlgs = NULL;
718
719 STREAM_GET(&attr->adv, s, sizeof(struct ls_node_id));
720 STREAM_GETL(s, attr->flags);
721 if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) {
722 STREAM_GETC(s, len);
723 STREAM_GET(attr->name, s, len);
724 }
725 if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC))
726 STREAM_GETL(s, attr->standard.metric);
727 if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
728 STREAM_GETL(s, attr->standard.te_metric);
729 if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
730 STREAM_GETL(s, attr->standard.admin_group);
731 if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR))
732 attr->standard.local.s_addr = stream_get_ipv4(s);
733 if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR))
734 attr->standard.remote.s_addr = stream_get_ipv4(s);
735 if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6))
736 STREAM_GET(&attr->standard.local6, s, IPV6_MAX_BYTELEN);
737 if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6))
738 STREAM_GET(&attr->standard.remote6, s, IPV6_MAX_BYTELEN);
739 if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID))
740 STREAM_GETL(s, attr->standard.local_id);
741 if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID))
742 STREAM_GETL(s, attr->standard.remote_id);
743 if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW))
744 STREAM_GETF(s, attr->standard.max_bw);
745 if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW))
746 STREAM_GETF(s, attr->standard.max_rsv_bw);
747 if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW))
748 for (len = 0; len < MAX_CLASS_TYPE; len++)
749 STREAM_GETF(s, attr->standard.unrsv_bw[len]);
750 if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS))
751 STREAM_GETL(s, attr->standard.remote_as);
752 if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR))
753 attr->standard.remote_addr.s_addr = stream_get_ipv4(s);
754 if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6))
755 STREAM_GET(&attr->standard.remote_addr6, s, IPV6_MAX_BYTELEN);
756 if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY))
757 STREAM_GETL(s, attr->extended.delay);
758 if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) {
759 STREAM_GETL(s, attr->extended.min_delay);
760 STREAM_GETL(s, attr->extended.max_delay);
761 }
762 if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER))
763 STREAM_GETL(s, attr->extended.jitter);
764 if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS))
765 STREAM_GETL(s, attr->extended.pkt_loss);
766 if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW))
767 STREAM_GETF(s, attr->extended.ava_bw);
768 if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW))
769 STREAM_GETF(s, attr->extended.rsv_bw);
770 if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW))
771 STREAM_GETF(s, attr->extended.used_bw);
772 if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) {
773 STREAM_GETL(s, attr->adj_sid[0].sid);
774 STREAM_GETC(s, attr->adj_sid[0].flags);
775 STREAM_GETC(s, attr->adj_sid[0].weight);
776 if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
777 STREAM_GET(attr->adj_sid[0].neighbor.sysid, s,
778 ISO_SYS_ID_LEN);
779 else if (attr->adv.origin == OSPFv2)
780 attr->adj_sid[0].neighbor.addr.s_addr =
781 stream_get_ipv4(s);
782 }
783 if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) {
784 STREAM_GETL(s, attr->adj_sid[1].sid);
785 STREAM_GETC(s, attr->adj_sid[1].flags);
786 STREAM_GETC(s, attr->adj_sid[1].weight);
787 if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
788 STREAM_GET(attr->adj_sid[1].neighbor.sysid, s,
789 ISO_SYS_ID_LEN);
790 else if (attr->adv.origin == OSPFv2)
791 attr->adj_sid[1].neighbor.addr.s_addr =
792 stream_get_ipv4(s);
793 }
794 if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) {
795 STREAM_GETC(s, len);
796 attr->srlgs = XCALLOC(MTYPE_LS_DB, len*sizeof(uint32_t));
797 attr->srlg_len = len;
798 for (len = 0; len < attr->srlg_len; len++)
799 STREAM_GETL(s, attr->srlgs[len]);
800 }
801
802 return attr;
803
804 stream_failure:
805 zlog_err("LS(%s): Could not parse Link State Attributes. Abort!",
806 __func__);
807 /* Clean memeory allocation */
808 if (attr->srlgs != NULL)
809 XFREE(MTYPE_LS_DB, attr->srlgs);
810 XFREE(MTYPE_LS_DB, attr);
811 return NULL;
812
813 }
814
815 static struct ls_prefix *ls_parse_prefix(struct stream *s)
816 {
817 struct ls_prefix *ls_pref;
818 size_t len;
819
820 ls_pref = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_prefix));
821 if (ls_pref == NULL)
822 return NULL;
823
824 STREAM_GET(&ls_pref->adv, s, sizeof(struct ls_node_id));
825 STREAM_GETW(s, ls_pref->flags);
826 STREAM_GETC(s, ls_pref->pref.family);
827 STREAM_GETW(s, ls_pref->pref.prefixlen);
828 len = prefix_blen(&ls_pref->pref);
829 STREAM_GET(&ls_pref->pref.u.prefix, s, len);
830 if (CHECK_FLAG(ls_pref->flags, LS_PREF_IGP_FLAG))
831 STREAM_GETC(s, ls_pref->igp_flag);
832 if (CHECK_FLAG(ls_pref->flags, LS_PREF_ROUTE_TAG))
833 STREAM_GETL(s, ls_pref->route_tag);
834 if (CHECK_FLAG(ls_pref->flags, LS_PREF_EXTENDED_TAG))
835 STREAM_GETQ(s, ls_pref->extended_tag);
836 if (CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC))
837 STREAM_GETL(s, ls_pref->metric);
838 if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) {
839 STREAM_GETL(s, ls_pref->sr.sid);
840 STREAM_GETC(s, ls_pref->sr.sid_flag);
841 STREAM_GETC(s, ls_pref->sr.algo);
842 }
843
844 return ls_pref;
845
846 stream_failure:
847 zlog_err("LS(%s): Could not parse Link State Prefix. Abort!", __func__);
848 XFREE(MTYPE_LS_DB, ls_pref);
849 return NULL;
850 }
851
852 struct ls_message *ls_parse_msg(struct stream *s)
853 {
854 struct ls_message *msg;
855
856 msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
857 if (msg == NULL)
858 return NULL;
859
860 /* Read LS Message header */
861 STREAM_GETC(s, msg->event);
862 STREAM_GETC(s, msg->type);
863 STREAM_GET(&msg->remote_id, s, sizeof(struct ls_node_id));
864
865 /* Read Message Payload */
866 switch (msg->type) {
867 case LS_MSG_TYPE_NODE:
868 msg->data.node = ls_parse_node(s);
869 break;
870 case LS_MSG_TYPE_ATTRIBUTES:
871 msg->data.attr = ls_parse_attributes(s);
872 break;
873 case LS_MSG_TYPE_PREFIX:
874 msg->data.prefix = ls_parse_prefix(s);
875 break;
876 default:
877 zlog_err("Unsupported Payload");
878 goto stream_failure;
879 }
880
881 if (msg->data.node == NULL || msg->data.attr == NULL
882 || msg->data.prefix == NULL)
883 goto stream_failure;
884
885 return msg;
886
887 stream_failure:
888 zlog_err("LS(%s): Could not parse LS message. Abort!", __func__);
889 XFREE(MTYPE_LS_DB, msg);
890 return NULL;
891 }
892
893 static int ls_format_node(struct stream *s, struct ls_node *node)
894 {
895 size_t len;
896
897 /* Push Advertise node information first */
898 stream_put(s, &node->adv, sizeof(struct ls_node_id));
899
900 /* Push Flags & Origin then Node information if there are present */
901 stream_putw(s, node->flags);
902 if (CHECK_FLAG(node->flags, LS_NODE_NAME)) {
903 len = strlen(node->name);
904 stream_putc(s, len + 1);
905 stream_put(s, node->name, len);
906 stream_putc(s, '\0');
907 }
908 if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID))
909 stream_put_ipv4(s, node->router_id.s_addr);
910 if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID6))
911 stream_put(s, &node->router6_id, IPV6_MAX_BYTELEN);
912 if (CHECK_FLAG(node->flags, LS_NODE_FLAG))
913 stream_putc(s, node->node_flag);
914 if (CHECK_FLAG(node->flags, LS_NODE_TYPE))
915 stream_putc(s, node->type);
916 if (CHECK_FLAG(node->flags, LS_NODE_AS_NUMBER))
917 stream_putl(s, node->as_number);
918 if (CHECK_FLAG(node->flags, LS_NODE_SR)) {
919 stream_putl(s, node->srgb.lower_bound);
920 stream_putl(s, node->srgb.range_size);
921 stream_putc(s, node->srgb.flag);
922 stream_put(s, node->algo, 2);
923 }
924 if (CHECK_FLAG(node->flags, LS_NODE_SRLB)) {
925 stream_putl(s, node->srlb.lower_bound);
926 stream_putl(s, node->srlb.range_size);
927 }
928 if (CHECK_FLAG(node->flags, LS_NODE_MSD))
929 stream_putc(s, node->msd);
930
931 return 0;
932 }
933
934 static int ls_format_attributes(struct stream *s, struct ls_attributes *attr)
935 {
936 size_t len;
937
938 /* Push Advertise node information first */
939 stream_put(s, &attr->adv, sizeof(struct ls_node_id));
940
941 /* Push Flags & Origin then LS attributes if there are present */
942 stream_putl(s, attr->flags);
943 if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) {
944 len = strlen(attr->name);
945 stream_putc(s, len + 1);
946 stream_put(s, attr->name, len);
947 stream_putc(s, '\0');
948 }
949 if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC))
950 stream_putl(s, attr->standard.metric);
951 if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
952 stream_putl(s, attr->standard.te_metric);
953 if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
954 stream_putl(s, attr->standard.admin_group);
955 if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR))
956 stream_put_ipv4(s, attr->standard.local.s_addr);
957 if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR))
958 stream_put_ipv4(s, attr->standard.remote.s_addr);
959 if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6))
960 stream_put(s, &attr->standard.local6, IPV6_MAX_BYTELEN);
961 if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6))
962 stream_put(s, &attr->standard.remote6, IPV6_MAX_BYTELEN);
963 if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID))
964 stream_putl(s, attr->standard.local_id);
965 if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID))
966 stream_putl(s, attr->standard.remote_id);
967 if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW))
968 stream_putf(s, attr->standard.max_bw);
969 if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW))
970 stream_putf(s, attr->standard.max_rsv_bw);
971 if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW))
972 for (len = 0; len < MAX_CLASS_TYPE; len++)
973 stream_putf(s, attr->standard.unrsv_bw[len]);
974 if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS))
975 stream_putl(s, attr->standard.remote_as);
976 if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR))
977 stream_put_ipv4(s, attr->standard.remote_addr.s_addr);
978 if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6))
979 stream_put(s, &attr->standard.remote_addr6, IPV6_MAX_BYTELEN);
980 if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY))
981 stream_putl(s, attr->extended.delay);
982 if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) {
983 stream_putl(s, attr->extended.min_delay);
984 stream_putl(s, attr->extended.max_delay);
985 }
986 if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER))
987 stream_putl(s, attr->extended.jitter);
988 if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS))
989 stream_putl(s, attr->extended.pkt_loss);
990 if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW))
991 stream_putf(s, attr->extended.ava_bw);
992 if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW))
993 stream_putf(s, attr->extended.rsv_bw);
994 if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW))
995 stream_putf(s, attr->extended.used_bw);
996 if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) {
997 stream_putl(s, attr->adj_sid[0].sid);
998 stream_putc(s, attr->adj_sid[0].flags);
999 stream_putc(s, attr->adj_sid[0].weight);
1000 if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
1001 stream_put(s, attr->adj_sid[0].neighbor.sysid,
1002 ISO_SYS_ID_LEN);
1003 else if (attr->adv.origin == OSPFv2)
1004 stream_put_ipv4(s,
1005 attr->adj_sid[0].neighbor.addr.s_addr);
1006 }
1007 if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) {
1008 stream_putl(s, attr->adj_sid[1].sid);
1009 stream_putc(s, attr->adj_sid[1].flags);
1010 stream_putc(s, attr->adj_sid[1].weight);
1011 if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
1012 stream_put(s, attr->adj_sid[1].neighbor.sysid,
1013 ISO_SYS_ID_LEN);
1014 else if (attr->adv.origin == OSPFv2)
1015 stream_put_ipv4(s,
1016 attr->adj_sid[1].neighbor.addr.s_addr);
1017 }
1018 if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) {
1019 stream_putc(s, attr->srlg_len);
1020 for (len = 0; len < attr->srlg_len; len++)
1021 stream_putl(s, attr->srlgs[len]);
1022 }
1023
1024 return 0;
1025 }
1026
1027 static int ls_format_prefix(struct stream *s, struct ls_prefix *ls_pref)
1028 {
1029 size_t len;
1030
1031 /* Push Advertise node information first */
1032 stream_put(s, &ls_pref->adv, sizeof(struct ls_node_id));
1033
1034 /* Push Flags, Origin & Prefix then information if there are present */
1035 stream_putw(s, ls_pref->flags);
1036 stream_putc(s, ls_pref->pref.family);
1037 stream_putw(s, ls_pref->pref.prefixlen);
1038 len = prefix_blen(&ls_pref->pref);
1039 stream_put(s, &ls_pref->pref.u.prefix, len);
1040 if (CHECK_FLAG(ls_pref->flags, LS_PREF_IGP_FLAG))
1041 stream_putc(s, ls_pref->igp_flag);
1042 if (CHECK_FLAG(ls_pref->flags, LS_PREF_ROUTE_TAG))
1043 stream_putl(s, ls_pref->route_tag);
1044 if (CHECK_FLAG(ls_pref->flags, LS_PREF_EXTENDED_TAG))
1045 stream_putq(s, ls_pref->extended_tag);
1046 if (CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC))
1047 stream_putl(s, ls_pref->metric);
1048 if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) {
1049 stream_putl(s, ls_pref->sr.sid);
1050 stream_putc(s, ls_pref->sr.sid_flag);
1051 stream_putc(s, ls_pref->sr.algo);
1052 }
1053
1054 return 0;
1055 }
1056
1057 static int ls_format_msg(struct stream *s, struct ls_message *msg)
1058 {
1059
1060 /* Prepare Link State header */
1061 stream_putc(s, msg->event);
1062 stream_putc(s, msg->type);
1063 stream_put(s, &msg->remote_id, sizeof(struct ls_node_id));
1064
1065 /* Add Message Payload */
1066 switch (msg->type) {
1067 case LS_MSG_TYPE_NODE:
1068 return ls_format_node(s, msg->data.node);
1069 case LS_MSG_TYPE_ATTRIBUTES:
1070 return ls_format_attributes(s, msg->data.attr);
1071 case LS_MSG_TYPE_PREFIX:
1072 return ls_format_prefix(s, msg->data.prefix);
1073 default:
1074 zlog_warn("Unsupported Payload");
1075 break;
1076 }
1077
1078 return -1;
1079 }
1080
1081 int ls_send_msg(struct zclient *zclient, struct ls_message *msg,
1082 struct zapi_opaque_reg_info *dst)
1083 {
1084 struct stream *s;
1085 uint16_t flags = 0;
1086
1087 /* Check buffer size */
1088 if (STREAM_SIZE(zclient->obuf) <
1089 (ZEBRA_HEADER_SIZE + sizeof(uint32_t) + sizeof(msg)))
1090 return -1;
1091
1092 s = zclient->obuf;
1093 stream_reset(s);
1094
1095 zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT);
1096
1097 /* Send sub-type, flags and destination for unicast message */
1098 stream_putl(s, LINK_STATE_UPDATE);
1099 if (dst != NULL) {
1100 SET_FLAG(flags, ZAPI_OPAQUE_FLAG_UNICAST);
1101 stream_putw(s, flags);
1102 /* Send destination client info */
1103 stream_putc(s, dst->proto);
1104 stream_putw(s, dst->instance);
1105 stream_putl(s, dst->session_id);
1106 } else
1107 stream_putw(s, flags);
1108
1109 /* Format Link State message */
1110 if (ls_format_msg(s, msg) < 0) {
1111 stream_reset(s);
1112 return -1;
1113 }
1114
1115 /* Put length into the header at the start of the stream. */
1116 stream_putw_at(s, 0, stream_get_endp(s));
1117
1118 return zclient_send_message(zclient);
1119 }
1120
1121 struct ls_message *ls_vertex2msg(struct ls_message *msg,
1122 struct ls_vertex *vertex)
1123 {
1124 /* Allocate space if needed */
1125 if (msg == NULL)
1126 msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
1127 else
1128 memset(msg, 0, sizeof(*msg));
1129
1130 msg->type = LS_MSG_TYPE_NODE;
1131 msg->data.node = vertex->node;
1132 msg->remote_id.origin = NONE;
1133
1134 return msg;
1135 }
1136
1137 struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge)
1138 {
1139 /* Allocate space if needed */
1140 if (msg == NULL)
1141 msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
1142 else
1143 memset(msg, 0, sizeof(*msg));
1144
1145 msg->type = LS_MSG_TYPE_ATTRIBUTES;
1146 msg->data.attr = edge->attributes;
1147 if (edge->destination != NULL)
1148 msg->remote_id = edge->destination->node->adv;
1149 else
1150 msg->remote_id.origin = NONE;
1151
1152 return msg;
1153 }
1154
1155 struct ls_message *ls_subnet2msg(struct ls_message *msg,
1156 struct ls_subnet *subnet)
1157 {
1158 /* Allocate space if needed */
1159 if (msg == NULL)
1160 msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
1161 else
1162 memset(msg, 0, sizeof(*msg));
1163
1164 msg->type = LS_MSG_TYPE_PREFIX;
1165 msg->data.prefix = subnet->ls_pref;
1166 msg->remote_id.origin = NONE;
1167
1168 return msg;
1169 }
1170
1171 void ls_delete_msg(struct ls_message *msg)
1172 {
1173 if (msg == NULL)
1174 return;
1175
1176 switch (msg->type) {
1177 case LS_MSG_TYPE_NODE:
1178 if (msg->data.node)
1179 XFREE(MTYPE_LS_DB, msg->data.node);
1180 break;
1181 case LS_MSG_TYPE_ATTRIBUTES:
1182 if (msg->data.attr)
1183 XFREE(MTYPE_LS_DB, msg->data.attr);
1184 break;
1185 case LS_MSG_TYPE_PREFIX:
1186 if (msg->data.prefix)
1187 XFREE(MTYPE_LS_DB, msg->data.prefix);
1188 break;
1189 default:
1190 break;
1191 }
1192
1193 XFREE(MTYPE_LS_DB, msg);
1194 }
1195
1196 int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient,
1197 struct zapi_opaque_reg_info *dst)
1198 {
1199 struct ls_vertex *vertex;
1200 struct ls_edge *edge;
1201 struct ls_subnet *subnet;
1202 struct ls_message msg;
1203
1204 /* Prepare message */
1205 msg.event = LS_MSG_EVENT_SYNC;
1206
1207 /* Loop TED, start sending Node, then Attributes and finally Prefix */
1208 frr_each(vertices, &ted->vertices, vertex) {
1209 ls_vertex2msg(&msg, vertex);
1210 ls_send_msg(zclient, &msg, dst);
1211 }
1212 frr_each(edges, &ted->edges, edge) {
1213 ls_edge2msg(&msg, edge);
1214 ls_send_msg(zclient, &msg, dst);
1215 }
1216 frr_each(subnets, &ted->subnets, subnet) {
1217 ls_subnet2msg(&msg, subnet);
1218 ls_send_msg(zclient, &msg, dst);
1219 }
1220 return 0;
1221 }
1222
1223 void ls_dump_ted(struct ls_ted *ted)
1224 {
1225 struct ls_vertex *vertex;
1226 struct ls_edge *edge;
1227 struct ls_subnet *subnet;
1228 struct ls_message msg;
1229
1230 zlog_debug("(%s) Ted init", __func__);
1231 /* Prepare message */
1232 msg.event = LS_MSG_EVENT_SYNC;
1233
1234 /* Loop TED, start printing Node, then Attributes and finally Prefix */
1235 frr_each(vertices, &ted->vertices, vertex) {
1236 ls_vertex2msg(&msg, vertex);
1237 zlog_debug(" Ted node (%s %pI4 %s)",
1238 vertex->node->name[0] ? vertex->node->name
1239 : "no name node",
1240 &vertex->node->router_id,
1241 vertex->node->adv.origin == DIRECT ? "DIRECT"
1242 : "NO DIRECT");
1243 struct listnode *lst_node;
1244 struct ls_edge *vertex_edge;
1245
1246 for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, lst_node,
1247 vertex_edge)) {
1248 zlog_debug(
1249 " inc edge key:%"PRIu64"n attr key:%pI4 loc:(%pI4) rmt:(%pI4)",
1250 vertex_edge->key,
1251 &vertex_edge->attributes->adv.id.ip.addr,
1252 &vertex_edge->attributes->standard.local,
1253 &vertex_edge->attributes->standard.remote);
1254 }
1255 for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, lst_node,
1256 vertex_edge)) {
1257 zlog_debug(
1258 " out edge key:%"PRIu64" attr key:%pI4 loc:(%pI4) rmt:(%pI4)",
1259 vertex_edge->key,
1260 &vertex_edge->attributes->adv.id.ip.addr,
1261 &vertex_edge->attributes->standard.local,
1262 &vertex_edge->attributes->standard.remote);
1263 }
1264 }
1265 frr_each(edges, &ted->edges, edge) {
1266 ls_edge2msg(&msg, edge);
1267 zlog_debug(" Ted edge key:%"PRIu64" src:%s dst:%s",
1268 edge->key,
1269 edge->source ? edge->source->node->name
1270 : "no_source",
1271 edge->destination ? edge->destination->node->name
1272 : "no_dest");
1273 }
1274 frr_each(subnets, &ted->subnets, subnet) {
1275 ls_subnet2msg(&msg, subnet);
1276 zlog_debug(
1277 " Ted subnet key:%pFX vertex:%pI4 pfx:%pFX",
1278 &subnet->key,
1279 &subnet->vertex->node->adv.id.ip.addr,
1280 &subnet->ls_pref->pref);
1281 }
1282 zlog_debug("(%s) Ted end", __func__);
1283 }