]>
Commit | Line | Data |
---|---|---|
bbd85e20 OD |
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 | ||
1f8031f7 DL |
25 | #include <zebra.h> |
26 | ||
bbd85e20 OD |
27 | #include "if.h" |
28 | #include "linklist.h" | |
29 | #include "log.h" | |
30 | #include "command.h" | |
31 | #include "termtable.h" | |
32 | #include "memory.h" | |
33 | #include "prefix.h" | |
34 | #include "table.h" | |
35 | #include "vty.h" | |
36 | #include "zclient.h" | |
37 | #include "stream.h" | |
b0c0b433 OD |
38 | #include "sbuf.h" |
39 | #include "printfrr.h" | |
40 | #include <lib/json.h> | |
bbd85e20 OD |
41 | #include "link_state.h" |
42 | ||
43 | /* Link State Memory allocation */ | |
bf8d3d6a | 44 | DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database"); |
bbd85e20 OD |
45 | |
46 | /** | |
47 | * Link State Node management functions | |
48 | */ | |
49 | struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid, | |
50 | struct in6_addr rid6) | |
51 | { | |
52 | struct ls_node *new; | |
53 | ||
b0c0b433 | 54 | if (adv.origin == UNKNOWN) |
bbd85e20 OD |
55 | return NULL; |
56 | ||
57 | new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node)); | |
58 | new->adv = adv; | |
59 | if (!IPV4_NET0(rid.s_addr)) { | |
60 | new->router_id = rid; | |
61 | SET_FLAG(new->flags, LS_NODE_ROUTER_ID); | |
62 | } else { | |
63 | if (adv.origin == OSPFv2 || adv.origin == STATIC | |
64 | || adv.origin == DIRECT) { | |
65 | new->router_id = adv.id.ip.addr; | |
66 | SET_FLAG(new->flags, LS_NODE_ROUTER_ID); | |
67 | } | |
68 | } | |
69 | if (!IN6_IS_ADDR_UNSPECIFIED(&rid6)) { | |
70 | new->router6_id = rid6; | |
71 | SET_FLAG(new->flags, LS_NODE_ROUTER_ID6); | |
72 | } | |
73 | return new; | |
74 | } | |
75 | ||
76 | void ls_node_del(struct ls_node *node) | |
77 | { | |
b0c0b433 OD |
78 | if (!node) |
79 | return; | |
80 | ||
bbd85e20 | 81 | XFREE(MTYPE_LS_DB, node); |
bbd85e20 OD |
82 | } |
83 | ||
84 | int ls_node_same(struct ls_node *n1, struct ls_node *n2) | |
85 | { | |
86 | if ((n1 && !n2) || (!n1 && n2)) | |
87 | return 0; | |
88 | ||
89 | if (n1 == n2) | |
90 | return 1; | |
91 | ||
92 | if (n1->flags != n2->flags) | |
93 | return 0; | |
94 | ||
95 | if (n1->adv.origin != n2->adv.origin) | |
96 | return 0; | |
97 | ||
98 | if (!memcmp(&n1->adv.id, &n2->adv.id, sizeof(struct ls_node_id))) | |
99 | return 0; | |
100 | ||
101 | /* Do we need to test individually each field, instead performing a | |
102 | * global memcmp? There is a risk that an old value that is bit masked | |
103 | * i.e. corresponding flag = 0, will result into a false negative | |
104 | */ | |
105 | if (!memcmp(n1, n2, sizeof(struct ls_node))) | |
106 | return 0; | |
107 | else | |
108 | return 1; | |
109 | } | |
110 | ||
111 | /** | |
112 | * Link State Attributes management functions | |
113 | */ | |
114 | struct ls_attributes *ls_attributes_new(struct ls_node_id adv, | |
115 | struct in_addr local, | |
116 | struct in6_addr local6, | |
117 | uint32_t local_id) | |
118 | { | |
119 | struct ls_attributes *new; | |
120 | ||
b0c0b433 | 121 | if (adv.origin == UNKNOWN) |
bbd85e20 OD |
122 | return NULL; |
123 | ||
124 | new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); | |
125 | new->adv = adv; | |
126 | if (!IPV4_NET0(local.s_addr)) { | |
127 | new->standard.local = local; | |
128 | SET_FLAG(new->flags, LS_ATTR_LOCAL_ADDR); | |
129 | } | |
130 | if (!IN6_IS_ADDR_UNSPECIFIED(&local6)) { | |
131 | new->standard.local6 = local6; | |
132 | SET_FLAG(new->flags, LS_ATTR_LOCAL_ADDR6); | |
133 | } | |
134 | if (local_id != 0) { | |
135 | new->standard.local_id = local_id; | |
136 | SET_FLAG(new->flags, LS_ATTR_LOCAL_ID); | |
137 | } | |
138 | ||
139 | /* Check that almost one identifier is set */ | |
140 | if (!CHECK_FLAG(new->flags, LS_ATTR_LOCAL_ADDR | LS_ATTR_LOCAL_ADDR6 | |
141 | | LS_ATTR_LOCAL_ID)) { | |
142 | XFREE(MTYPE_LS_DB, new); | |
143 | return NULL; | |
144 | } | |
145 | ||
146 | return new; | |
147 | } | |
148 | ||
b0c0b433 | 149 | void ls_attributes_srlg_del(struct ls_attributes *attr) |
bbd85e20 OD |
150 | { |
151 | if (!attr) | |
152 | return; | |
153 | ||
154 | if (attr->srlgs) | |
155 | XFREE(MTYPE_LS_DB, attr->srlgs); | |
156 | ||
b0c0b433 OD |
157 | attr->srlgs = NULL; |
158 | attr->srlg_len = 0; | |
159 | UNSET_FLAG(attr->flags, LS_ATTR_SRLG); | |
160 | } | |
161 | ||
162 | void ls_attributes_del(struct ls_attributes *attr) | |
163 | { | |
164 | if (!attr) | |
165 | return; | |
166 | ||
167 | ls_attributes_srlg_del(attr); | |
168 | ||
bbd85e20 | 169 | XFREE(MTYPE_LS_DB, attr); |
bbd85e20 OD |
170 | } |
171 | ||
172 | int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2) | |
173 | { | |
174 | if ((l1 && !l2) || (!l1 && l2)) | |
175 | return 0; | |
176 | ||
177 | if (l1 == l2) | |
178 | return 1; | |
179 | ||
180 | if (l1->flags != l2->flags) | |
181 | return 0; | |
182 | ||
183 | if (l1->adv.origin != l2->adv.origin) | |
184 | return 0; | |
185 | ||
186 | if (!memcmp(&l1->adv.id, &l2->adv.id, sizeof(struct ls_node_id))) | |
187 | return 0; | |
188 | ||
189 | /* Do we need to test individually each field, instead performing a | |
190 | * global memcmp? There is a risk that an old value that is bit masked | |
191 | * i.e. corresponding flag = 0, will result into a false negative | |
192 | */ | |
193 | if (!memcmp(l1, l2, sizeof(struct ls_attributes))) | |
194 | return 0; | |
195 | else | |
196 | return 1; | |
197 | } | |
198 | ||
199 | /** | |
b0c0b433 | 200 | * Link State prefix management functions |
bbd85e20 | 201 | */ |
b0c0b433 | 202 | struct ls_prefix *ls_prefix_new(struct ls_node_id adv, struct prefix p) |
bbd85e20 | 203 | { |
b0c0b433 | 204 | struct ls_prefix *new; |
bbd85e20 | 205 | |
b0c0b433 | 206 | if (adv.origin == UNKNOWN) |
bbd85e20 OD |
207 | return NULL; |
208 | ||
b0c0b433 OD |
209 | new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); |
210 | new->adv = adv; | |
211 | new->pref = p; | |
bbd85e20 OD |
212 | |
213 | return new; | |
214 | } | |
215 | ||
b0c0b433 | 216 | void ls_prefix_del(struct ls_prefix *pref) |
bbd85e20 | 217 | { |
b0c0b433 | 218 | if (!pref) |
bbd85e20 OD |
219 | return; |
220 | ||
b0c0b433 | 221 | XFREE(MTYPE_LS_DB, pref); |
bbd85e20 OD |
222 | } |
223 | ||
b0c0b433 OD |
224 | int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2) |
225 | { | |
226 | if ((p1 && !p2) || (!p1 && p2)) | |
227 | return 0; | |
228 | ||
229 | if (p1 == p2) | |
230 | return 1; | |
231 | ||
232 | if (p1->flags != p2->flags) | |
233 | return 0; | |
234 | ||
235 | if (p1->adv.origin != p2->adv.origin) | |
236 | return 0; | |
237 | ||
238 | if (!memcmp(&p1->adv.id, &p2->adv.id, sizeof(struct ls_node_id))) | |
239 | return 0; | |
240 | ||
241 | /* Do we need to test individually each field, instead performing a | |
242 | * global memcmp? There is a risk that an old value that is bit masked | |
243 | * i.e. corresponding flag = 0, will result into a false negative | |
244 | */ | |
245 | if (!memcmp(p1, p2, sizeof(struct ls_prefix))) | |
246 | return 0; | |
247 | else | |
248 | return 1; | |
249 | } | |
250 | ||
251 | /** | |
252 | * Link State Vertices management functions | |
253 | */ | |
bbd85e20 OD |
254 | struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node) |
255 | { | |
256 | struct ls_vertex *new; | |
b0c0b433 | 257 | uint64_t key = 0; |
bbd85e20 OD |
258 | |
259 | if ((ted == NULL) || (node == NULL)) | |
260 | return NULL; | |
261 | ||
bbd85e20 OD |
262 | /* set Key as the IPv4/Ipv6 Router ID or ISO System ID */ |
263 | switch (node->adv.origin) { | |
264 | case OSPFv2: | |
265 | case STATIC: | |
266 | case DIRECT: | |
b0c0b433 OD |
267 | key = ((uint64_t)ntohl(node->adv.id.ip.addr.s_addr)) |
268 | & 0xffffffff; | |
bbd85e20 OD |
269 | break; |
270 | case ISIS_L1: | |
271 | case ISIS_L2: | |
b0c0b433 | 272 | memcpy(&key, &node->adv.id.iso.sys_id, ISO_SYS_ID_LEN); |
bbd85e20 OD |
273 | break; |
274 | default: | |
b0c0b433 | 275 | key = 0; |
bbd85e20 OD |
276 | break; |
277 | } | |
278 | ||
b0c0b433 OD |
279 | /* Check that key is valid */ |
280 | if (key == 0) | |
bbd85e20 | 281 | return NULL; |
bbd85e20 | 282 | |
b0c0b433 OD |
283 | /* Create Vertex and add it to the TED */ |
284 | new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_vertex)); | |
285 | if (!new) | |
286 | return NULL; | |
287 | ||
288 | new->key = key; | |
289 | new->node = node; | |
290 | new->status = NEW; | |
291 | new->type = VERTEX; | |
292 | new->incoming_edges = list_new(); | |
293 | new->incoming_edges->cmp = (int (*)(void *, void *))edge_cmp; | |
294 | new->outgoing_edges = list_new(); | |
295 | new->outgoing_edges->cmp = (int (*)(void *, void *))edge_cmp; | |
296 | new->prefixes = list_new(); | |
297 | new->prefixes->cmp = (int (*)(void *, void *))subnet_cmp; | |
bbd85e20 OD |
298 | vertices_add(&ted->vertices, new); |
299 | ||
300 | return new; | |
301 | } | |
302 | ||
b0c0b433 OD |
303 | void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex) |
304 | { | |
305 | struct listnode *node, *nnode; | |
306 | struct ls_edge *edge; | |
307 | struct ls_subnet *subnet; | |
308 | ||
309 | if (!ted || !vertex) | |
310 | return; | |
311 | ||
312 | /* Remove outgoing Edges and list */ | |
313 | for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) | |
314 | ls_edge_del_all(ted, edge); | |
315 | list_delete(&vertex->outgoing_edges); | |
316 | ||
317 | /* Disconnect incoming Edges and remove list */ | |
318 | for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) { | |
319 | ls_disconnect(vertex, edge, false); | |
320 | if (edge->source == NULL) | |
321 | ls_edge_del_all(ted, edge); | |
322 | } | |
323 | list_delete(&vertex->incoming_edges); | |
324 | ||
325 | /* Remove subnet and list */ | |
326 | for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) | |
327 | ls_subnet_del_all(ted, subnet); | |
328 | list_delete(&vertex->prefixes); | |
329 | ||
330 | /* Then remove Vertex from Link State Data Base and free memory */ | |
331 | vertices_del(&ted->vertices, vertex); | |
332 | XFREE(MTYPE_LS_DB, vertex); | |
333 | vertex = NULL; | |
334 | } | |
335 | ||
336 | void ls_vertex_del_all(struct ls_ted *ted, struct ls_vertex *vertex) | |
337 | { | |
338 | if (!ted || !vertex) | |
339 | return; | |
340 | ||
341 | /* First remove associated Link State Node */ | |
342 | ls_node_del(vertex->node); | |
343 | ||
344 | /* Then, Vertex itself */ | |
345 | ls_vertex_del(ted, vertex); | |
346 | } | |
347 | ||
bbd85e20 OD |
348 | struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node) |
349 | { | |
350 | struct ls_vertex *old; | |
351 | ||
352 | if (node == NULL) | |
353 | return NULL; | |
354 | ||
355 | old = ls_find_vertex_by_id(ted, node->adv); | |
356 | if (old) { | |
357 | if (!ls_node_same(old->node, node)) { | |
358 | ls_node_del(old->node); | |
359 | old->node = node; | |
360 | } | |
b0c0b433 | 361 | old->status = UPDATE; |
bbd85e20 OD |
362 | return old; |
363 | } | |
364 | ||
365 | return ls_vertex_add(ted, node); | |
366 | } | |
367 | ||
bbd85e20 OD |
368 | struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key) |
369 | { | |
b0c0b433 | 370 | struct ls_vertex vertex = {}; |
bbd85e20 OD |
371 | |
372 | if (key == 0) | |
373 | return NULL; | |
374 | ||
b0c0b433 OD |
375 | vertex.key = key; |
376 | return vertices_find(&ted->vertices, &vertex); | |
bbd85e20 OD |
377 | } |
378 | ||
379 | struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted, | |
380 | struct ls_node_id nid) | |
381 | { | |
b0c0b433 | 382 | struct ls_vertex vertex = {}; |
bbd85e20 | 383 | |
b0c0b433 | 384 | vertex.key = 0; |
bbd85e20 OD |
385 | switch (nid.origin) { |
386 | case OSPFv2: | |
387 | case STATIC: | |
388 | case DIRECT: | |
b0c0b433 OD |
389 | vertex.key = |
390 | ((uint64_t)ntohl(nid.id.ip.addr.s_addr)) & 0xffffffff; | |
bbd85e20 OD |
391 | break; |
392 | case ISIS_L1: | |
393 | case ISIS_L2: | |
b0c0b433 | 394 | memcpy(&vertex.key, &nid.id.iso.sys_id, ISO_SYS_ID_LEN); |
bbd85e20 OD |
395 | break; |
396 | default: | |
397 | return NULL; | |
398 | } | |
399 | ||
b0c0b433 | 400 | return vertices_find(&ted->vertices, &vertex); |
bbd85e20 OD |
401 | } |
402 | ||
403 | int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2) | |
404 | { | |
405 | if ((v1 && !v2) || (!v1 && v2)) | |
406 | return 0; | |
407 | ||
408 | if (!v1 && !v2) | |
409 | return 1; | |
410 | ||
411 | if (v1->key != v2->key) | |
412 | return 0; | |
413 | ||
414 | if (v1->node == v2->node) | |
415 | return 1; | |
416 | ||
417 | return ls_node_same(v1->node, v2->node); | |
418 | } | |
419 | ||
b0c0b433 OD |
420 | void ls_vertex_clean(struct ls_ted *ted, struct ls_vertex *vertex, |
421 | struct zclient *zclient) | |
422 | { | |
423 | struct listnode *node, *nnode; | |
424 | struct ls_edge *edge; | |
425 | struct ls_subnet *subnet; | |
426 | struct ls_message msg; | |
427 | ||
428 | /* Remove Orphan Edge ... */ | |
429 | for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) { | |
430 | if (edge->status == ORPHAN) { | |
431 | if (zclient) { | |
432 | edge->status = DELETE; | |
433 | ls_edge2msg(&msg, edge); | |
434 | ls_send_msg(zclient, &msg, NULL); | |
435 | } | |
436 | ls_edge_del_all(ted, edge); | |
437 | } | |
438 | } | |
439 | for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) { | |
440 | if (edge->status == ORPHAN) { | |
441 | if (zclient) { | |
442 | edge->status = DELETE; | |
443 | ls_edge2msg(&msg, edge); | |
444 | ls_send_msg(zclient, &msg, NULL); | |
445 | } | |
446 | ls_edge_del_all(ted, edge); | |
447 | } | |
448 | } | |
449 | ||
450 | /* ... and Subnet from the Vertex */ | |
451 | for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) { | |
452 | if (subnet->status == ORPHAN) { | |
453 | if (zclient) { | |
454 | subnet->status = DELETE; | |
455 | ls_subnet2msg(&msg, subnet); | |
456 | ls_send_msg(zclient, &msg, NULL); | |
457 | } | |
458 | ls_subnet_del_all(ted, subnet); | |
459 | } | |
460 | } | |
461 | } | |
462 | ||
bbd85e20 OD |
463 | /** |
464 | * Link State Edges management functions | |
465 | */ | |
466 | ||
467 | /** | |
468 | * This function allows to connect the Edge to the vertices present in the TED. | |
469 | * A temporary vertex that corresponds to the source of this Edge i.e. the | |
470 | * advertised router, is created if not found in the Data Base. If a Edge that | |
471 | * corresponds to the reverse path is found, the Edge is attached to the | |
472 | * destination vertex as destination and reverse Edge is attached to the source | |
473 | * vertex as source. | |
474 | * | |
475 | * @param ted Link State Data Base | |
476 | * @param edge Link State Edge to be attached | |
477 | */ | |
478 | static void ls_edge_connect_to(struct ls_ted *ted, struct ls_edge *edge) | |
479 | { | |
480 | struct ls_vertex *vertex = NULL; | |
481 | struct ls_node *node; | |
482 | struct ls_edge *dst; | |
483 | const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; | |
484 | ||
485 | /* First, search if there is a Vertex that correspond to the Node ID */ | |
486 | vertex = ls_find_vertex_by_id(ted, edge->attributes->adv); | |
487 | if (vertex == NULL) { | |
488 | /* Create a new temporary Node & Vertex if not found */ | |
489 | node = ls_node_new(edge->attributes->adv, inaddr_any, | |
490 | in6addr_any); | |
491 | vertex = ls_vertex_add(ted, node); | |
492 | } | |
493 | /* and attach the edge as source to the vertex */ | |
b0c0b433 | 494 | listnode_add_sort_nodup(vertex->outgoing_edges, edge); |
bbd85e20 OD |
495 | edge->source = vertex; |
496 | ||
497 | /* Then search if there is a reverse Edge */ | |
498 | dst = ls_find_edge_by_destination(ted, edge->attributes); | |
499 | /* attach the destination edge to the vertex */ | |
500 | if (dst) { | |
b0c0b433 | 501 | listnode_add_sort_nodup(vertex->incoming_edges, dst); |
bbd85e20 OD |
502 | dst->destination = vertex; |
503 | /* and destination vertex to this edge */ | |
504 | vertex = dst->source; | |
b0c0b433 | 505 | listnode_add_sort_nodup(vertex->incoming_edges, edge); |
bbd85e20 OD |
506 | edge->destination = vertex; |
507 | } | |
508 | } | |
509 | ||
510 | struct ls_edge *ls_edge_add(struct ls_ted *ted, | |
511 | struct ls_attributes *attributes) | |
512 | { | |
513 | struct ls_edge *new; | |
b0c0b433 | 514 | uint64_t key = 0; |
bbd85e20 OD |
515 | |
516 | if (attributes == NULL) | |
517 | return NULL; | |
518 | ||
bbd85e20 OD |
519 | /* Key is the IPv4 local address */ |
520 | if (!IPV4_NET0(attributes->standard.local.s_addr)) | |
b0c0b433 OD |
521 | key = ((uint64_t)ntohl(attributes->standard.local.s_addr)) |
522 | & 0xffffffff; | |
bbd85e20 OD |
523 | /* or the IPv6 local address if IPv4 is not defined */ |
524 | else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6)) | |
b0c0b433 OD |
525 | key = (uint64_t)(attributes->standard.local6.s6_addr32[0] |
526 | & 0xffffffff) | |
527 | | ((uint64_t)attributes->standard.local6.s6_addr32[1] | |
528 | << 32); | |
bbd85e20 OD |
529 | /* of local identifier if no IP addresses are defined */ |
530 | else if (attributes->standard.local_id != 0) | |
b0c0b433 | 531 | key = (uint64_t)( |
bbd85e20 OD |
532 | (attributes->standard.local_id & 0xffffffff) |
533 | | ((uint64_t)attributes->standard.remote_id << 32)); | |
534 | ||
b0c0b433 OD |
535 | /* Check that key is valid */ |
536 | if (key == 0) | |
537 | return NULL; | |
538 | ||
539 | /* Create Edge and add it to the TED */ | |
540 | new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge)); | |
bbd85e20 | 541 | |
b0c0b433 OD |
542 | new->attributes = attributes; |
543 | new->key = key; | |
544 | new->status = NEW; | |
545 | new->type = EDGE; | |
bbd85e20 OD |
546 | edges_add(&ted->edges, new); |
547 | ||
b0c0b433 | 548 | /* Finally, connect Edge to Vertices */ |
bbd85e20 OD |
549 | ls_edge_connect_to(ted, new); |
550 | ||
551 | return new; | |
552 | } | |
553 | ||
554 | struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted, const uint64_t key) | |
555 | { | |
556 | struct ls_edge edge = {}; | |
557 | ||
558 | if (key == 0) | |
559 | return NULL; | |
560 | ||
561 | edge.key = key; | |
562 | return edges_find(&ted->edges, &edge); | |
563 | } | |
564 | ||
565 | struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted, | |
566 | struct ls_attributes *attributes) | |
567 | { | |
568 | struct ls_edge edge = {}; | |
569 | ||
570 | if (attributes == NULL) | |
571 | return NULL; | |
572 | ||
b0c0b433 | 573 | edge.key = 0; |
bbd85e20 OD |
574 | /* Key is the IPv4 local address */ |
575 | if (!IPV4_NET0(attributes->standard.local.s_addr)) | |
b0c0b433 | 576 | edge.key = ((uint64_t)ntohl(attributes->standard.local.s_addr)) |
bbd85e20 OD |
577 | & 0xffffffff; |
578 | /* or the IPv6 local address if IPv4 is not defined */ | |
579 | else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6)) | |
580 | edge.key = (uint64_t)(attributes->standard.local6.s6_addr32[0] | |
581 | & 0xffffffff) | |
582 | | ((uint64_t)attributes->standard.local6.s6_addr32[1] | |
583 | << 32); | |
584 | /* of local identifier if no IP addresses are defined */ | |
585 | else if (attributes->standard.local_id != 0) | |
586 | edge.key = (uint64_t)( | |
587 | (attributes->standard.local_id & 0xffffffff) | |
588 | | ((uint64_t)attributes->standard.remote_id << 32)); | |
589 | ||
590 | if (edge.key == 0) | |
591 | return NULL; | |
592 | ||
593 | return edges_find(&ted->edges, &edge); | |
594 | } | |
595 | ||
596 | struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted, | |
597 | struct ls_attributes *attributes) | |
598 | { | |
599 | struct ls_edge edge = {}; | |
600 | ||
601 | if (attributes == NULL) | |
602 | return NULL; | |
603 | ||
b0c0b433 OD |
604 | edge.key = 0; |
605 | /* Key is the IPv4 remote address */ | |
bbd85e20 | 606 | if (!IPV4_NET0(attributes->standard.remote.s_addr)) |
b0c0b433 | 607 | edge.key = ((uint64_t)ntohl(attributes->standard.remote.s_addr)) |
bbd85e20 | 608 | & 0xffffffff; |
b0c0b433 | 609 | /* or the IPv6 remote address if IPv4 is not defined */ |
bbd85e20 OD |
610 | else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.remote6)) |
611 | edge.key = | |
612 | (uint64_t)(attributes->standard.remote6.s6_addr32[0] | |
613 | & 0xffffffff) | |
614 | | ((uint64_t)attributes->standard.remote6.s6_addr32[1] | |
615 | << 32); | |
b0c0b433 | 616 | /* of remote identifier if no IP addresses are defined */ |
bbd85e20 OD |
617 | else if (attributes->standard.remote_id != 0) |
618 | edge.key = (uint64_t)( | |
619 | (attributes->standard.remote_id & 0xffffffff) | |
620 | | ((uint64_t)attributes->standard.local_id << 32)); | |
621 | ||
622 | if (edge.key == 0) | |
623 | return NULL; | |
624 | ||
625 | return edges_find(&ted->edges, &edge); | |
626 | } | |
627 | ||
628 | struct ls_edge *ls_edge_update(struct ls_ted *ted, | |
629 | struct ls_attributes *attributes) | |
630 | { | |
631 | struct ls_edge *old; | |
632 | ||
633 | if (attributes == NULL) | |
634 | return NULL; | |
635 | ||
636 | /* First, search for an existing Edge */ | |
637 | old = ls_find_edge_by_source(ted, attributes); | |
638 | if (old) { | |
639 | /* Check if attributes are similar */ | |
640 | if (!ls_attributes_same(old->attributes, attributes)) { | |
641 | ls_attributes_del(old->attributes); | |
642 | old->attributes = attributes; | |
643 | } | |
b0c0b433 | 644 | old->status = UPDATE; |
bbd85e20 OD |
645 | return old; |
646 | } | |
647 | ||
648 | /* If not found, add new Edge from the attributes */ | |
649 | return ls_edge_add(ted, attributes); | |
650 | } | |
651 | ||
b0c0b433 OD |
652 | int ls_edge_same(struct ls_edge *e1, struct ls_edge *e2) |
653 | { | |
654 | if ((e1 && !e2) || (!e1 && e2)) | |
655 | return 0; | |
656 | ||
657 | if (!e1 && !e2) | |
658 | return 1; | |
659 | ||
660 | if (e1->key != e2->key) | |
661 | return 0; | |
662 | ||
663 | if (e1->attributes == e2->attributes) | |
664 | return 1; | |
665 | ||
666 | return ls_attributes_same(e1->attributes, e2->attributes); | |
667 | } | |
668 | ||
bbd85e20 OD |
669 | void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge) |
670 | { | |
b0c0b433 OD |
671 | if (!ted || !edge) |
672 | return; | |
673 | ||
674 | /* Fist disconnect Edge from Vertices */ | |
bbd85e20 OD |
675 | ls_disconnect_edge(edge); |
676 | /* Then remove it from the Data Base */ | |
677 | edges_del(&ted->edges, edge); | |
678 | XFREE(MTYPE_LS_DB, edge); | |
679 | } | |
680 | ||
b0c0b433 OD |
681 | void ls_edge_del_all(struct ls_ted *ted, struct ls_edge *edge) |
682 | { | |
683 | if (!ted || !edge) | |
684 | return; | |
685 | ||
686 | /* Remove associated Link State Attributes */ | |
687 | ls_attributes_del(edge->attributes); | |
688 | /* Then Edge itself */ | |
689 | ls_edge_del(ted, edge); | |
690 | } | |
691 | ||
bbd85e20 OD |
692 | /** |
693 | * Link State Subnet Management functions. | |
694 | */ | |
695 | struct ls_subnet *ls_subnet_add(struct ls_ted *ted, | |
696 | struct ls_prefix *ls_pref) | |
697 | { | |
698 | struct ls_subnet *new; | |
699 | struct ls_vertex *vertex; | |
700 | struct ls_node *node; | |
701 | const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; | |
702 | ||
703 | if (ls_pref == NULL) | |
704 | return NULL; | |
705 | ||
706 | new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_subnet)); | |
707 | new->ls_pref = ls_pref; | |
708 | new->key = ls_pref->pref; | |
b0c0b433 OD |
709 | new->status = NEW; |
710 | new->type = SUBNET; | |
bbd85e20 OD |
711 | |
712 | /* Find Vertex */ | |
713 | vertex = ls_find_vertex_by_id(ted, ls_pref->adv); | |
714 | if (vertex == NULL) { | |
715 | /* Create a new temporary Node & Vertex if not found */ | |
716 | node = ls_node_new(ls_pref->adv, inaddr_any, in6addr_any); | |
717 | vertex = ls_vertex_add(ted, node); | |
718 | } | |
719 | /* And attach the subnet to the corresponding Vertex */ | |
720 | new->vertex = vertex; | |
b0c0b433 | 721 | listnode_add_sort_nodup(vertex->prefixes, new); |
bbd85e20 OD |
722 | |
723 | subnets_add(&ted->subnets, new); | |
724 | ||
725 | return new; | |
726 | } | |
727 | ||
b0c0b433 OD |
728 | struct ls_subnet *ls_subnet_update(struct ls_ted *ted, struct ls_prefix *pref) |
729 | { | |
730 | struct ls_subnet *old; | |
731 | ||
732 | if (pref == NULL) | |
733 | return NULL; | |
734 | ||
735 | old = ls_find_subnet(ted, pref->pref); | |
736 | if (old) { | |
737 | if (!ls_prefix_same(old->ls_pref, pref)) { | |
738 | ls_prefix_del(old->ls_pref); | |
739 | old->ls_pref = pref; | |
740 | } | |
741 | old->status = UPDATE; | |
742 | return old; | |
743 | } | |
744 | ||
745 | return ls_subnet_add(ted, pref); | |
746 | } | |
747 | ||
748 | int ls_subnet_same(struct ls_subnet *s1, struct ls_subnet *s2) | |
749 | { | |
750 | if ((s1 && !s2) || (!s1 && s2)) | |
751 | return 0; | |
752 | ||
753 | if (!s1 && !s2) | |
754 | return 1; | |
755 | ||
756 | if (!prefix_same(&s1->key, &s2->key)) | |
757 | return 0; | |
758 | ||
759 | if (s1->ls_pref == s2->ls_pref) | |
760 | return 1; | |
761 | ||
762 | return ls_prefix_same(s1->ls_pref, s2->ls_pref); | |
763 | } | |
764 | ||
bbd85e20 OD |
765 | void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet) |
766 | { | |
b0c0b433 OD |
767 | if (!ted || !subnet) |
768 | return; | |
769 | ||
770 | /* First, disconnect Subnet from associated Vertex */ | |
771 | listnode_delete(subnet->vertex->prefixes, subnet); | |
772 | /* Then delete Subnet */ | |
bbd85e20 OD |
773 | subnets_del(&ted->subnets, subnet); |
774 | XFREE(MTYPE_LS_DB, subnet); | |
775 | } | |
776 | ||
b0c0b433 OD |
777 | void ls_subnet_del_all(struct ls_ted *ted, struct ls_subnet *subnet) |
778 | { | |
779 | if (!ted || !subnet) | |
780 | return; | |
781 | ||
782 | /* First, remove associated Link State Subnet */ | |
783 | ls_prefix_del(subnet->ls_pref); | |
784 | /* Then, delete Subnet itself */ | |
785 | ls_subnet_del(ted, subnet); | |
786 | } | |
787 | ||
bbd85e20 OD |
788 | struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix) |
789 | { | |
790 | struct ls_subnet subnet = {}; | |
791 | ||
792 | subnet.key = prefix; | |
793 | return subnets_find(&ted->subnets, &subnet); | |
794 | } | |
795 | ||
796 | /** | |
797 | * Link State TED management functions | |
798 | */ | |
799 | struct ls_ted *ls_ted_new(const uint32_t key, const char *name, | |
800 | uint32_t as_number) | |
801 | { | |
802 | struct ls_ted *new; | |
803 | ||
804 | new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_ted)); | |
bbd85e20 OD |
805 | |
806 | /* Set basic information for this ted */ | |
807 | new->key = key; | |
808 | new->as_number = as_number; | |
809 | strlcpy(new->name, name, MAX_NAME_LENGTH); | |
810 | ||
811 | /* Initialize the various RB tree */ | |
812 | vertices_init(&new->vertices); | |
813 | edges_init(&new->edges); | |
814 | subnets_init(&new->subnets); | |
815 | ||
816 | return new; | |
817 | } | |
818 | ||
819 | void ls_ted_del(struct ls_ted *ted) | |
820 | { | |
821 | if (ted == NULL) | |
822 | return; | |
823 | ||
b0c0b433 OD |
824 | /* Check that TED is empty */ |
825 | if (vertices_count(&ted->vertices) || edges_count(&ted->edges) | |
826 | || subnets_count(&ted->subnets)) | |
827 | return; | |
828 | ||
bbd85e20 OD |
829 | /* Release RB Tree */ |
830 | vertices_fini(&ted->vertices); | |
831 | edges_fini(&ted->edges); | |
832 | subnets_fini(&ted->subnets); | |
833 | ||
834 | XFREE(MTYPE_LS_DB, ted); | |
bbd85e20 OD |
835 | } |
836 | ||
b0c0b433 OD |
837 | void ls_ted_del_all(struct ls_ted *ted) |
838 | { | |
839 | struct ls_vertex *vertex; | |
840 | struct ls_edge *edge; | |
841 | struct ls_subnet *subnet; | |
842 | ||
843 | if (ted == NULL) | |
844 | return; | |
845 | ||
846 | /* First remove Vertices, Edges and Subnets and associated Link State */ | |
847 | frr_each (vertices, &ted->vertices, vertex) | |
848 | ls_vertex_del_all(ted, vertex); | |
849 | frr_each (edges, &ted->edges, edge) | |
850 | ls_edge_del_all(ted, edge); | |
851 | frr_each (subnets, &ted->subnets, subnet) | |
852 | ls_subnet_del_all(ted, subnet); | |
853 | ||
854 | /* then remove TED itself */ | |
855 | ls_ted_del(ted); | |
856 | } | |
857 | ||
858 | void ls_ted_clean(struct ls_ted *ted) | |
859 | { | |
860 | struct ls_vertex *vertex; | |
861 | struct ls_edge *edge; | |
862 | struct ls_subnet *subnet; | |
863 | ||
864 | if (ted == NULL) | |
865 | return; | |
866 | ||
867 | /* First, start with Vertices */ | |
868 | frr_each (vertices, &ted->vertices, vertex) | |
869 | if (vertex->status == ORPHAN) | |
870 | ls_vertex_del_all(ted, vertex); | |
871 | ||
872 | /* Then Edges */ | |
873 | frr_each (edges, &ted->edges, edge) | |
874 | if (edge->status == ORPHAN) | |
875 | ls_edge_del_all(ted, edge); | |
876 | ||
877 | /* and Subnets */ | |
878 | frr_each (subnets, &ted->subnets, subnet) | |
879 | if (subnet->status == ORPHAN) | |
880 | ls_subnet_del_all(ted, subnet); | |
881 | ||
882 | } | |
883 | ||
bbd85e20 OD |
884 | void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source) |
885 | { | |
886 | if (vertex == NULL || edge == NULL) | |
887 | return; | |
888 | ||
889 | if (source) { | |
b0c0b433 | 890 | listnode_add_sort_nodup(vertex->outgoing_edges, edge); |
bbd85e20 OD |
891 | edge->source = vertex; |
892 | } else { | |
b0c0b433 | 893 | listnode_add_sort_nodup(vertex->incoming_edges, edge); |
bbd85e20 OD |
894 | edge->destination = vertex; |
895 | } | |
896 | } | |
897 | ||
898 | void ls_disconnect(struct ls_vertex *vertex, struct ls_edge *edge, bool source) | |
899 | { | |
900 | ||
901 | if (vertex == NULL || edge == NULL) | |
902 | return; | |
903 | ||
904 | if (source) { | |
905 | listnode_delete(vertex->outgoing_edges, edge); | |
906 | edge->source = NULL; | |
907 | } else { | |
908 | listnode_delete(vertex->incoming_edges, edge); | |
909 | edge->destination = NULL; | |
910 | } | |
911 | } | |
912 | ||
913 | void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst, | |
914 | struct ls_edge *edge) | |
915 | { | |
916 | if (edge == NULL) | |
917 | return; | |
918 | ||
919 | edge->source = src; | |
920 | edge->destination = dst; | |
921 | ||
922 | if (src != NULL) | |
b0c0b433 | 923 | listnode_add_sort_nodup(src->outgoing_edges, edge); |
bbd85e20 OD |
924 | |
925 | if (dst != NULL) | |
b0c0b433 | 926 | listnode_add_sort_nodup(dst->incoming_edges, edge); |
bbd85e20 OD |
927 | } |
928 | ||
929 | void ls_disconnect_edge(struct ls_edge *edge) | |
930 | { | |
931 | if (edge == NULL) | |
932 | return; | |
933 | ||
934 | ls_disconnect(edge->source, edge, true); | |
935 | ls_disconnect(edge->destination, edge, false); | |
b0c0b433 OD |
936 | |
937 | /* Mark this Edge as ORPHAN for future cleanup */ | |
938 | edge->status = ORPHAN; | |
bbd85e20 OD |
939 | } |
940 | ||
941 | /** | |
942 | * Link State Message management functions | |
943 | */ | |
944 | ||
b0c0b433 OD |
945 | int ls_register(struct zclient *zclient, bool server) |
946 | { | |
947 | int rc; | |
948 | ||
949 | if (server) | |
950 | rc = zclient_register_opaque(zclient, LINK_STATE_SYNC); | |
951 | else | |
952 | rc = zclient_register_opaque(zclient, LINK_STATE_UPDATE); | |
953 | ||
954 | return rc; | |
955 | } | |
956 | ||
957 | int ls_unregister(struct zclient *zclient, bool server) | |
958 | { | |
959 | int rc; | |
960 | ||
961 | if (server) | |
962 | rc = zclient_unregister_opaque(zclient, LINK_STATE_SYNC); | |
963 | else | |
964 | rc = zclient_unregister_opaque(zclient, LINK_STATE_UPDATE); | |
965 | ||
966 | return rc; | |
967 | } | |
968 | ||
969 | int ls_request_sync(struct zclient *zclient) | |
970 | { | |
971 | struct stream *s; | |
972 | uint16_t flags = 0; | |
973 | ||
974 | /* Check buffer size */ | |
975 | if (STREAM_SIZE(zclient->obuf) | |
976 | < (ZEBRA_HEADER_SIZE + 3 * sizeof(uint32_t))) | |
977 | return -1; | |
978 | ||
979 | s = zclient->obuf; | |
980 | stream_reset(s); | |
981 | ||
982 | zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); | |
983 | ||
984 | /* Set type and flags */ | |
985 | stream_putl(s, LINK_STATE_SYNC); | |
986 | stream_putw(s, flags); | |
987 | /* Send destination client info */ | |
988 | stream_putc(s, zclient->redist_default); | |
989 | stream_putw(s, zclient->instance); | |
990 | stream_putl(s, zclient->session_id); | |
991 | ||
992 | /* Put length into the header at the start of the stream. */ | |
993 | stream_putw_at(s, 0, stream_get_endp(s)); | |
994 | ||
995 | return zclient_send_message(zclient); | |
996 | } | |
997 | ||
bbd85e20 OD |
998 | static struct ls_node *ls_parse_node(struct stream *s) |
999 | { | |
1000 | struct ls_node *node; | |
1001 | size_t len; | |
1002 | ||
1003 | node = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node)); | |
bbd85e20 OD |
1004 | |
1005 | STREAM_GET(&node->adv, s, sizeof(struct ls_node_id)); | |
1006 | STREAM_GETW(s, node->flags); | |
1007 | if (CHECK_FLAG(node->flags, LS_NODE_NAME)) { | |
1008 | STREAM_GETC(s, len); | |
1009 | STREAM_GET(node->name, s, len); | |
1010 | } | |
1011 | if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID)) | |
1012 | node->router_id.s_addr = stream_get_ipv4(s); | |
1013 | if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID6)) | |
1014 | STREAM_GET(&node->router6_id, s, IPV6_MAX_BYTELEN); | |
1015 | if (CHECK_FLAG(node->flags, LS_NODE_FLAG)) | |
1016 | STREAM_GETC(s, node->node_flag); | |
1017 | if (CHECK_FLAG(node->flags, LS_NODE_TYPE)) | |
1018 | STREAM_GETC(s, node->type); | |
1019 | if (CHECK_FLAG(node->flags, LS_NODE_AS_NUMBER)) | |
1020 | STREAM_GETL(s, node->as_number); | |
1021 | if (CHECK_FLAG(node->flags, LS_NODE_SR)) { | |
1022 | STREAM_GETL(s, node->srgb.lower_bound); | |
1023 | STREAM_GETL(s, node->srgb.range_size); | |
1024 | STREAM_GETC(s, node->srgb.flag); | |
1025 | STREAM_GET(node->algo, s, 2); | |
1026 | } | |
1027 | if (CHECK_FLAG(node->flags, LS_NODE_SRLB)) { | |
1028 | STREAM_GETL(s, node->srlb.lower_bound); | |
1029 | STREAM_GETL(s, node->srlb.range_size); | |
1030 | } | |
1031 | if (CHECK_FLAG(node->flags, LS_NODE_MSD)) | |
1032 | STREAM_GETC(s, node->msd); | |
1033 | ||
1034 | return node; | |
1035 | ||
1036 | stream_failure: | |
1037 | zlog_err("LS(%s): Could not parse Link State Node. Abort!", __func__); | |
1038 | XFREE(MTYPE_LS_DB, node); | |
1039 | return NULL; | |
1040 | } | |
1041 | ||
1042 | static struct ls_attributes *ls_parse_attributes(struct stream *s) | |
1043 | { | |
1044 | struct ls_attributes *attr; | |
1045 | size_t len; | |
1046 | ||
1047 | attr = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); | |
bbd85e20 OD |
1048 | attr->srlgs = NULL; |
1049 | ||
1050 | STREAM_GET(&attr->adv, s, sizeof(struct ls_node_id)); | |
1051 | STREAM_GETL(s, attr->flags); | |
1052 | if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) { | |
1053 | STREAM_GETC(s, len); | |
1054 | STREAM_GET(attr->name, s, len); | |
1055 | } | |
1056 | if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC)) | |
b0c0b433 | 1057 | STREAM_GETL(s, attr->metric); |
bbd85e20 OD |
1058 | if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) |
1059 | STREAM_GETL(s, attr->standard.te_metric); | |
1060 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) | |
1061 | STREAM_GETL(s, attr->standard.admin_group); | |
1062 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) | |
1063 | attr->standard.local.s_addr = stream_get_ipv4(s); | |
1064 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) | |
1065 | attr->standard.remote.s_addr = stream_get_ipv4(s); | |
1066 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) | |
1067 | STREAM_GET(&attr->standard.local6, s, IPV6_MAX_BYTELEN); | |
1068 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6)) | |
1069 | STREAM_GET(&attr->standard.remote6, s, IPV6_MAX_BYTELEN); | |
1070 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) | |
1071 | STREAM_GETL(s, attr->standard.local_id); | |
1072 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID)) | |
1073 | STREAM_GETL(s, attr->standard.remote_id); | |
1074 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW)) | |
1075 | STREAM_GETF(s, attr->standard.max_bw); | |
1076 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW)) | |
1077 | STREAM_GETF(s, attr->standard.max_rsv_bw); | |
1078 | if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) | |
1079 | for (len = 0; len < MAX_CLASS_TYPE; len++) | |
1080 | STREAM_GETF(s, attr->standard.unrsv_bw[len]); | |
1081 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS)) | |
1082 | STREAM_GETL(s, attr->standard.remote_as); | |
1083 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR)) | |
1084 | attr->standard.remote_addr.s_addr = stream_get_ipv4(s); | |
1085 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6)) | |
1086 | STREAM_GET(&attr->standard.remote_addr6, s, IPV6_MAX_BYTELEN); | |
1087 | if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY)) | |
1088 | STREAM_GETL(s, attr->extended.delay); | |
1089 | if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) { | |
1090 | STREAM_GETL(s, attr->extended.min_delay); | |
1091 | STREAM_GETL(s, attr->extended.max_delay); | |
1092 | } | |
1093 | if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER)) | |
1094 | STREAM_GETL(s, attr->extended.jitter); | |
1095 | if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS)) | |
1096 | STREAM_GETL(s, attr->extended.pkt_loss); | |
1097 | if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW)) | |
1098 | STREAM_GETF(s, attr->extended.ava_bw); | |
1099 | if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW)) | |
1100 | STREAM_GETF(s, attr->extended.rsv_bw); | |
1101 | if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW)) | |
1102 | STREAM_GETF(s, attr->extended.used_bw); | |
1103 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) { | |
1104 | STREAM_GETL(s, attr->adj_sid[0].sid); | |
1105 | STREAM_GETC(s, attr->adj_sid[0].flags); | |
1106 | STREAM_GETC(s, attr->adj_sid[0].weight); | |
1107 | if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2) | |
1108 | STREAM_GET(attr->adj_sid[0].neighbor.sysid, s, | |
1109 | ISO_SYS_ID_LEN); | |
1110 | else if (attr->adv.origin == OSPFv2) | |
1111 | attr->adj_sid[0].neighbor.addr.s_addr = | |
1112 | stream_get_ipv4(s); | |
1113 | } | |
1114 | if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { | |
1115 | STREAM_GETL(s, attr->adj_sid[1].sid); | |
1116 | STREAM_GETC(s, attr->adj_sid[1].flags); | |
1117 | STREAM_GETC(s, attr->adj_sid[1].weight); | |
1118 | if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2) | |
1119 | STREAM_GET(attr->adj_sid[1].neighbor.sysid, s, | |
1120 | ISO_SYS_ID_LEN); | |
1121 | else if (attr->adv.origin == OSPFv2) | |
1122 | attr->adj_sid[1].neighbor.addr.s_addr = | |
1123 | stream_get_ipv4(s); | |
1124 | } | |
1125 | if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { | |
1126 | STREAM_GETC(s, len); | |
1127 | attr->srlgs = XCALLOC(MTYPE_LS_DB, len*sizeof(uint32_t)); | |
1128 | attr->srlg_len = len; | |
1129 | for (len = 0; len < attr->srlg_len; len++) | |
1130 | STREAM_GETL(s, attr->srlgs[len]); | |
1131 | } | |
1132 | ||
1133 | return attr; | |
1134 | ||
1135 | stream_failure: | |
1136 | zlog_err("LS(%s): Could not parse Link State Attributes. Abort!", | |
1137 | __func__); | |
b0c0b433 | 1138 | /* Clean memory allocation */ |
bbd85e20 OD |
1139 | if (attr->srlgs != NULL) |
1140 | XFREE(MTYPE_LS_DB, attr->srlgs); | |
1141 | XFREE(MTYPE_LS_DB, attr); | |
1142 | return NULL; | |
1143 | ||
1144 | } | |
1145 | ||
1146 | static struct ls_prefix *ls_parse_prefix(struct stream *s) | |
1147 | { | |
1148 | struct ls_prefix *ls_pref; | |
1149 | size_t len; | |
1150 | ||
1151 | ls_pref = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_prefix)); | |
bbd85e20 OD |
1152 | |
1153 | STREAM_GET(&ls_pref->adv, s, sizeof(struct ls_node_id)); | |
1154 | STREAM_GETW(s, ls_pref->flags); | |
1155 | STREAM_GETC(s, ls_pref->pref.family); | |
1156 | STREAM_GETW(s, ls_pref->pref.prefixlen); | |
1157 | len = prefix_blen(&ls_pref->pref); | |
1158 | STREAM_GET(&ls_pref->pref.u.prefix, s, len); | |
1159 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_IGP_FLAG)) | |
1160 | STREAM_GETC(s, ls_pref->igp_flag); | |
1161 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_ROUTE_TAG)) | |
1162 | STREAM_GETL(s, ls_pref->route_tag); | |
1163 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_EXTENDED_TAG)) | |
1164 | STREAM_GETQ(s, ls_pref->extended_tag); | |
1165 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC)) | |
1166 | STREAM_GETL(s, ls_pref->metric); | |
1167 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) { | |
1168 | STREAM_GETL(s, ls_pref->sr.sid); | |
1169 | STREAM_GETC(s, ls_pref->sr.sid_flag); | |
1170 | STREAM_GETC(s, ls_pref->sr.algo); | |
1171 | } | |
1172 | ||
1173 | return ls_pref; | |
1174 | ||
1175 | stream_failure: | |
1176 | zlog_err("LS(%s): Could not parse Link State Prefix. Abort!", __func__); | |
1177 | XFREE(MTYPE_LS_DB, ls_pref); | |
1178 | return NULL; | |
1179 | } | |
1180 | ||
1181 | struct ls_message *ls_parse_msg(struct stream *s) | |
1182 | { | |
1183 | struct ls_message *msg; | |
1184 | ||
1185 | msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message)); | |
bbd85e20 OD |
1186 | |
1187 | /* Read LS Message header */ | |
1188 | STREAM_GETC(s, msg->event); | |
1189 | STREAM_GETC(s, msg->type); | |
1190 | STREAM_GET(&msg->remote_id, s, sizeof(struct ls_node_id)); | |
1191 | ||
1192 | /* Read Message Payload */ | |
1193 | switch (msg->type) { | |
1194 | case LS_MSG_TYPE_NODE: | |
1195 | msg->data.node = ls_parse_node(s); | |
1196 | break; | |
1197 | case LS_MSG_TYPE_ATTRIBUTES: | |
1198 | msg->data.attr = ls_parse_attributes(s); | |
1199 | break; | |
1200 | case LS_MSG_TYPE_PREFIX: | |
1201 | msg->data.prefix = ls_parse_prefix(s); | |
1202 | break; | |
1203 | default: | |
1204 | zlog_err("Unsupported Payload"); | |
1205 | goto stream_failure; | |
1206 | } | |
1207 | ||
1208 | if (msg->data.node == NULL || msg->data.attr == NULL | |
1209 | || msg->data.prefix == NULL) | |
1210 | goto stream_failure; | |
1211 | ||
1212 | return msg; | |
1213 | ||
1214 | stream_failure: | |
1215 | zlog_err("LS(%s): Could not parse LS message. Abort!", __func__); | |
1216 | XFREE(MTYPE_LS_DB, msg); | |
1217 | return NULL; | |
1218 | } | |
1219 | ||
1220 | static int ls_format_node(struct stream *s, struct ls_node *node) | |
1221 | { | |
1222 | size_t len; | |
1223 | ||
1224 | /* Push Advertise node information first */ | |
1225 | stream_put(s, &node->adv, sizeof(struct ls_node_id)); | |
1226 | ||
1227 | /* Push Flags & Origin then Node information if there are present */ | |
1228 | stream_putw(s, node->flags); | |
1229 | if (CHECK_FLAG(node->flags, LS_NODE_NAME)) { | |
1230 | len = strlen(node->name); | |
1231 | stream_putc(s, len + 1); | |
1232 | stream_put(s, node->name, len); | |
1233 | stream_putc(s, '\0'); | |
1234 | } | |
1235 | if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID)) | |
1236 | stream_put_ipv4(s, node->router_id.s_addr); | |
1237 | if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID6)) | |
1238 | stream_put(s, &node->router6_id, IPV6_MAX_BYTELEN); | |
1239 | if (CHECK_FLAG(node->flags, LS_NODE_FLAG)) | |
1240 | stream_putc(s, node->node_flag); | |
1241 | if (CHECK_FLAG(node->flags, LS_NODE_TYPE)) | |
1242 | stream_putc(s, node->type); | |
1243 | if (CHECK_FLAG(node->flags, LS_NODE_AS_NUMBER)) | |
1244 | stream_putl(s, node->as_number); | |
1245 | if (CHECK_FLAG(node->flags, LS_NODE_SR)) { | |
1246 | stream_putl(s, node->srgb.lower_bound); | |
1247 | stream_putl(s, node->srgb.range_size); | |
1248 | stream_putc(s, node->srgb.flag); | |
1249 | stream_put(s, node->algo, 2); | |
1250 | } | |
1251 | if (CHECK_FLAG(node->flags, LS_NODE_SRLB)) { | |
1252 | stream_putl(s, node->srlb.lower_bound); | |
1253 | stream_putl(s, node->srlb.range_size); | |
1254 | } | |
1255 | if (CHECK_FLAG(node->flags, LS_NODE_MSD)) | |
1256 | stream_putc(s, node->msd); | |
1257 | ||
1258 | return 0; | |
1259 | } | |
1260 | ||
1261 | static int ls_format_attributes(struct stream *s, struct ls_attributes *attr) | |
1262 | { | |
1263 | size_t len; | |
1264 | ||
1265 | /* Push Advertise node information first */ | |
1266 | stream_put(s, &attr->adv, sizeof(struct ls_node_id)); | |
1267 | ||
1268 | /* Push Flags & Origin then LS attributes if there are present */ | |
1269 | stream_putl(s, attr->flags); | |
1270 | if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) { | |
1271 | len = strlen(attr->name); | |
1272 | stream_putc(s, len + 1); | |
1273 | stream_put(s, attr->name, len); | |
1274 | stream_putc(s, '\0'); | |
1275 | } | |
1276 | if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC)) | |
b0c0b433 | 1277 | stream_putl(s, attr->metric); |
bbd85e20 OD |
1278 | if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) |
1279 | stream_putl(s, attr->standard.te_metric); | |
1280 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) | |
1281 | stream_putl(s, attr->standard.admin_group); | |
1282 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) | |
1283 | stream_put_ipv4(s, attr->standard.local.s_addr); | |
1284 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) | |
1285 | stream_put_ipv4(s, attr->standard.remote.s_addr); | |
1286 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) | |
1287 | stream_put(s, &attr->standard.local6, IPV6_MAX_BYTELEN); | |
1288 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6)) | |
1289 | stream_put(s, &attr->standard.remote6, IPV6_MAX_BYTELEN); | |
1290 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) | |
1291 | stream_putl(s, attr->standard.local_id); | |
1292 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID)) | |
1293 | stream_putl(s, attr->standard.remote_id); | |
1294 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW)) | |
1295 | stream_putf(s, attr->standard.max_bw); | |
1296 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW)) | |
1297 | stream_putf(s, attr->standard.max_rsv_bw); | |
1298 | if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) | |
1299 | for (len = 0; len < MAX_CLASS_TYPE; len++) | |
1300 | stream_putf(s, attr->standard.unrsv_bw[len]); | |
1301 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS)) | |
1302 | stream_putl(s, attr->standard.remote_as); | |
1303 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR)) | |
1304 | stream_put_ipv4(s, attr->standard.remote_addr.s_addr); | |
1305 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6)) | |
1306 | stream_put(s, &attr->standard.remote_addr6, IPV6_MAX_BYTELEN); | |
1307 | if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY)) | |
1308 | stream_putl(s, attr->extended.delay); | |
1309 | if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) { | |
1310 | stream_putl(s, attr->extended.min_delay); | |
1311 | stream_putl(s, attr->extended.max_delay); | |
1312 | } | |
1313 | if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER)) | |
1314 | stream_putl(s, attr->extended.jitter); | |
1315 | if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS)) | |
1316 | stream_putl(s, attr->extended.pkt_loss); | |
1317 | if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW)) | |
1318 | stream_putf(s, attr->extended.ava_bw); | |
1319 | if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW)) | |
1320 | stream_putf(s, attr->extended.rsv_bw); | |
1321 | if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW)) | |
1322 | stream_putf(s, attr->extended.used_bw); | |
1323 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) { | |
1324 | stream_putl(s, attr->adj_sid[0].sid); | |
1325 | stream_putc(s, attr->adj_sid[0].flags); | |
1326 | stream_putc(s, attr->adj_sid[0].weight); | |
1327 | if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2) | |
1328 | stream_put(s, attr->adj_sid[0].neighbor.sysid, | |
1329 | ISO_SYS_ID_LEN); | |
1330 | else if (attr->adv.origin == OSPFv2) | |
1331 | stream_put_ipv4(s, | |
1332 | attr->adj_sid[0].neighbor.addr.s_addr); | |
1333 | } | |
1334 | if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { | |
1335 | stream_putl(s, attr->adj_sid[1].sid); | |
1336 | stream_putc(s, attr->adj_sid[1].flags); | |
1337 | stream_putc(s, attr->adj_sid[1].weight); | |
1338 | if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2) | |
1339 | stream_put(s, attr->adj_sid[1].neighbor.sysid, | |
1340 | ISO_SYS_ID_LEN); | |
1341 | else if (attr->adv.origin == OSPFv2) | |
1342 | stream_put_ipv4(s, | |
1343 | attr->adj_sid[1].neighbor.addr.s_addr); | |
1344 | } | |
1345 | if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { | |
1346 | stream_putc(s, attr->srlg_len); | |
1347 | for (len = 0; len < attr->srlg_len; len++) | |
1348 | stream_putl(s, attr->srlgs[len]); | |
1349 | } | |
1350 | ||
1351 | return 0; | |
1352 | } | |
1353 | ||
1354 | static int ls_format_prefix(struct stream *s, struct ls_prefix *ls_pref) | |
1355 | { | |
1356 | size_t len; | |
1357 | ||
1358 | /* Push Advertise node information first */ | |
1359 | stream_put(s, &ls_pref->adv, sizeof(struct ls_node_id)); | |
1360 | ||
1361 | /* Push Flags, Origin & Prefix then information if there are present */ | |
1362 | stream_putw(s, ls_pref->flags); | |
1363 | stream_putc(s, ls_pref->pref.family); | |
1364 | stream_putw(s, ls_pref->pref.prefixlen); | |
1365 | len = prefix_blen(&ls_pref->pref); | |
1366 | stream_put(s, &ls_pref->pref.u.prefix, len); | |
1367 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_IGP_FLAG)) | |
1368 | stream_putc(s, ls_pref->igp_flag); | |
1369 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_ROUTE_TAG)) | |
1370 | stream_putl(s, ls_pref->route_tag); | |
1371 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_EXTENDED_TAG)) | |
1372 | stream_putq(s, ls_pref->extended_tag); | |
1373 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC)) | |
1374 | stream_putl(s, ls_pref->metric); | |
1375 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) { | |
1376 | stream_putl(s, ls_pref->sr.sid); | |
1377 | stream_putc(s, ls_pref->sr.sid_flag); | |
1378 | stream_putc(s, ls_pref->sr.algo); | |
1379 | } | |
1380 | ||
1381 | return 0; | |
1382 | } | |
1383 | ||
1384 | static int ls_format_msg(struct stream *s, struct ls_message *msg) | |
1385 | { | |
1386 | ||
1387 | /* Prepare Link State header */ | |
1388 | stream_putc(s, msg->event); | |
1389 | stream_putc(s, msg->type); | |
1390 | stream_put(s, &msg->remote_id, sizeof(struct ls_node_id)); | |
1391 | ||
1392 | /* Add Message Payload */ | |
1393 | switch (msg->type) { | |
1394 | case LS_MSG_TYPE_NODE: | |
1395 | return ls_format_node(s, msg->data.node); | |
1396 | case LS_MSG_TYPE_ATTRIBUTES: | |
1397 | return ls_format_attributes(s, msg->data.attr); | |
1398 | case LS_MSG_TYPE_PREFIX: | |
1399 | return ls_format_prefix(s, msg->data.prefix); | |
1400 | default: | |
1401 | zlog_warn("Unsupported Payload"); | |
1402 | break; | |
1403 | } | |
1404 | ||
1405 | return -1; | |
1406 | } | |
1407 | ||
1408 | int ls_send_msg(struct zclient *zclient, struct ls_message *msg, | |
1409 | struct zapi_opaque_reg_info *dst) | |
1410 | { | |
1411 | struct stream *s; | |
1412 | uint16_t flags = 0; | |
1413 | ||
b0c0b433 OD |
1414 | /* Check if we have a valid message */ |
1415 | if (msg->event == LS_MSG_EVENT_UNDEF) | |
1416 | return -1; | |
1417 | ||
bbd85e20 OD |
1418 | /* Check buffer size */ |
1419 | if (STREAM_SIZE(zclient->obuf) < | |
1420 | (ZEBRA_HEADER_SIZE + sizeof(uint32_t) + sizeof(msg))) | |
1421 | return -1; | |
1422 | ||
1423 | s = zclient->obuf; | |
1424 | stream_reset(s); | |
1425 | ||
1426 | zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); | |
1427 | ||
b0c0b433 | 1428 | /* Set sub-type, flags and destination for unicast message */ |
bbd85e20 OD |
1429 | stream_putl(s, LINK_STATE_UPDATE); |
1430 | if (dst != NULL) { | |
1431 | SET_FLAG(flags, ZAPI_OPAQUE_FLAG_UNICAST); | |
1432 | stream_putw(s, flags); | |
1433 | /* Send destination client info */ | |
1434 | stream_putc(s, dst->proto); | |
1435 | stream_putw(s, dst->instance); | |
1436 | stream_putl(s, dst->session_id); | |
b0c0b433 | 1437 | } else { |
bbd85e20 | 1438 | stream_putw(s, flags); |
b0c0b433 | 1439 | } |
bbd85e20 OD |
1440 | |
1441 | /* Format Link State message */ | |
1442 | if (ls_format_msg(s, msg) < 0) { | |
1443 | stream_reset(s); | |
1444 | return -1; | |
1445 | } | |
1446 | ||
1447 | /* Put length into the header at the start of the stream. */ | |
1448 | stream_putw_at(s, 0, stream_get_endp(s)); | |
1449 | ||
1450 | return zclient_send_message(zclient); | |
1451 | } | |
1452 | ||
1453 | struct ls_message *ls_vertex2msg(struct ls_message *msg, | |
1454 | struct ls_vertex *vertex) | |
1455 | { | |
1456 | /* Allocate space if needed */ | |
1457 | if (msg == NULL) | |
1458 | msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message)); | |
1459 | else | |
1460 | memset(msg, 0, sizeof(*msg)); | |
1461 | ||
1462 | msg->type = LS_MSG_TYPE_NODE; | |
b0c0b433 OD |
1463 | switch (vertex->status) { |
1464 | case NEW: | |
1465 | msg->event = LS_MSG_EVENT_ADD; | |
1466 | break; | |
1467 | case UPDATE: | |
1468 | msg->event = LS_MSG_EVENT_UPDATE; | |
1469 | break; | |
1470 | case DELETE: | |
1471 | msg->event = LS_MSG_EVENT_DELETE; | |
1472 | break; | |
1473 | case SYNC: | |
1474 | msg->event = LS_MSG_EVENT_SYNC; | |
1475 | break; | |
1476 | default: | |
1477 | msg->event = LS_MSG_EVENT_UNDEF; | |
1478 | break; | |
1479 | } | |
bbd85e20 | 1480 | msg->data.node = vertex->node; |
b0c0b433 | 1481 | msg->remote_id.origin = UNKNOWN; |
bbd85e20 OD |
1482 | |
1483 | return msg; | |
1484 | } | |
1485 | ||
1486 | struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge) | |
1487 | { | |
1488 | /* Allocate space if needed */ | |
1489 | if (msg == NULL) | |
1490 | msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message)); | |
1491 | else | |
1492 | memset(msg, 0, sizeof(*msg)); | |
1493 | ||
1494 | msg->type = LS_MSG_TYPE_ATTRIBUTES; | |
b0c0b433 OD |
1495 | switch (edge->status) { |
1496 | case NEW: | |
1497 | msg->event = LS_MSG_EVENT_ADD; | |
1498 | break; | |
1499 | case UPDATE: | |
1500 | msg->event = LS_MSG_EVENT_UPDATE; | |
1501 | break; | |
1502 | case DELETE: | |
1503 | msg->event = LS_MSG_EVENT_DELETE; | |
1504 | break; | |
1505 | case SYNC: | |
1506 | msg->event = LS_MSG_EVENT_SYNC; | |
1507 | break; | |
1508 | default: | |
1509 | msg->event = LS_MSG_EVENT_UNDEF; | |
1510 | break; | |
1511 | } | |
bbd85e20 OD |
1512 | msg->data.attr = edge->attributes; |
1513 | if (edge->destination != NULL) | |
1514 | msg->remote_id = edge->destination->node->adv; | |
1515 | else | |
b0c0b433 | 1516 | msg->remote_id.origin = UNKNOWN; |
bbd85e20 OD |
1517 | |
1518 | return msg; | |
1519 | } | |
1520 | ||
1521 | struct ls_message *ls_subnet2msg(struct ls_message *msg, | |
1522 | struct ls_subnet *subnet) | |
1523 | { | |
1524 | /* Allocate space if needed */ | |
1525 | if (msg == NULL) | |
1526 | msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message)); | |
1527 | else | |
1528 | memset(msg, 0, sizeof(*msg)); | |
1529 | ||
1530 | msg->type = LS_MSG_TYPE_PREFIX; | |
b0c0b433 OD |
1531 | switch (subnet->status) { |
1532 | case NEW: | |
1533 | msg->event = LS_MSG_EVENT_ADD; | |
1534 | break; | |
1535 | case UPDATE: | |
1536 | msg->event = LS_MSG_EVENT_UPDATE; | |
1537 | break; | |
1538 | case DELETE: | |
1539 | msg->event = LS_MSG_EVENT_DELETE; | |
1540 | break; | |
1541 | case SYNC: | |
1542 | msg->event = LS_MSG_EVENT_SYNC; | |
1543 | break; | |
1544 | default: | |
1545 | msg->event = LS_MSG_EVENT_UNDEF; | |
1546 | break; | |
1547 | } | |
bbd85e20 | 1548 | msg->data.prefix = subnet->ls_pref; |
b0c0b433 | 1549 | msg->remote_id.origin = UNKNOWN; |
bbd85e20 OD |
1550 | |
1551 | return msg; | |
1552 | } | |
1553 | ||
b0c0b433 OD |
1554 | struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg, |
1555 | bool delete) | |
bbd85e20 | 1556 | { |
b0c0b433 OD |
1557 | struct ls_node *node = (struct ls_node *)msg->data.node; |
1558 | struct ls_vertex *vertex = NULL; | |
1559 | ||
1560 | switch (msg->event) { | |
1561 | case LS_MSG_EVENT_SYNC: | |
1562 | vertex = ls_vertex_add(ted, node); | |
1563 | if (vertex) | |
1564 | vertex->status = SYNC; | |
1565 | break; | |
1566 | case LS_MSG_EVENT_ADD: | |
1567 | vertex = ls_vertex_add(ted, node); | |
1568 | if (vertex) | |
1569 | vertex->status = NEW; | |
1570 | break; | |
1571 | case LS_MSG_EVENT_UPDATE: | |
1572 | vertex = ls_vertex_update(ted, node); | |
1573 | if (vertex) | |
1574 | vertex->status = UPDATE; | |
1575 | break; | |
1576 | case LS_MSG_EVENT_DELETE: | |
1577 | vertex = ls_find_vertex_by_id(ted, node->adv); | |
1578 | if (vertex) { | |
1579 | if (delete) | |
1580 | ls_vertex_del_all(ted, vertex); | |
1581 | else | |
1582 | vertex->status = DELETE; | |
1583 | } | |
1584 | break; | |
1585 | default: | |
1586 | vertex = NULL; | |
1587 | break; | |
1588 | } | |
1589 | ||
1590 | return vertex; | |
1591 | } | |
1592 | ||
1593 | struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, | |
1594 | bool delete) | |
1595 | { | |
1596 | struct ls_attributes *attr = (struct ls_attributes *)msg->data.attr; | |
1597 | struct ls_edge *edge = NULL; | |
1598 | ||
1599 | switch (msg->event) { | |
1600 | case LS_MSG_EVENT_SYNC: | |
1601 | edge = ls_edge_add(ted, attr); | |
1602 | if (edge) | |
1603 | edge->status = SYNC; | |
1604 | break; | |
1605 | case LS_MSG_EVENT_ADD: | |
1606 | edge = ls_edge_add(ted, attr); | |
1607 | if (edge) | |
1608 | edge->status = NEW; | |
1609 | break; | |
1610 | case LS_MSG_EVENT_UPDATE: | |
1611 | edge = ls_edge_update(ted, attr); | |
1612 | if (edge) | |
1613 | edge->status = UPDATE; | |
1614 | break; | |
1615 | case LS_MSG_EVENT_DELETE: | |
1616 | edge = ls_find_edge_by_source(ted, attr); | |
1617 | if (edge) { | |
1618 | if (delete) | |
1619 | ls_edge_del_all(ted, edge); | |
1620 | else | |
1621 | edge->status = DELETE; | |
1622 | } | |
1623 | break; | |
1624 | default: | |
1625 | edge = NULL; | |
1626 | break; | |
1627 | } | |
1628 | ||
1629 | return edge; | |
1630 | } | |
1631 | ||
1632 | struct ls_subnet *ls_msg2subnet(struct ls_ted *ted, struct ls_message *msg, | |
1633 | bool delete) | |
1634 | { | |
1635 | struct ls_prefix *pref = (struct ls_prefix *)msg->data.prefix; | |
1636 | struct ls_subnet *subnet = NULL; | |
1637 | ||
1638 | switch (msg->event) { | |
1639 | case LS_MSG_EVENT_SYNC: | |
1640 | subnet = ls_subnet_add(ted, pref); | |
1641 | if (subnet) | |
1642 | subnet->status = SYNC; | |
1643 | break; | |
1644 | case LS_MSG_EVENT_ADD: | |
1645 | subnet = ls_subnet_add(ted, pref); | |
1646 | if (subnet) | |
1647 | subnet->status = NEW; | |
1648 | break; | |
1649 | case LS_MSG_EVENT_UPDATE: | |
1650 | subnet = ls_subnet_update(ted, pref); | |
1651 | if (subnet) | |
1652 | subnet->status = UPDATE; | |
1653 | break; | |
1654 | case LS_MSG_EVENT_DELETE: | |
1655 | subnet = ls_find_subnet(ted, pref->pref); | |
1656 | if (subnet) { | |
1657 | if (delete) | |
1658 | ls_subnet_del_all(ted, subnet); | |
1659 | else | |
1660 | subnet->status = DELETE; | |
1661 | } | |
1662 | break; | |
1663 | default: | |
1664 | subnet = NULL; | |
1665 | break; | |
1666 | } | |
1667 | ||
1668 | return subnet; | |
1669 | } | |
1670 | ||
1671 | struct ls_element *ls_msg2ted(struct ls_ted *ted, struct ls_message *msg, | |
1672 | bool delete) | |
1673 | { | |
1674 | struct ls_element *lse = NULL; | |
bbd85e20 OD |
1675 | |
1676 | switch (msg->type) { | |
1677 | case LS_MSG_TYPE_NODE: | |
b0c0b433 | 1678 | lse = (struct ls_element *)ls_msg2vertex(ted, msg, delete); |
bbd85e20 OD |
1679 | break; |
1680 | case LS_MSG_TYPE_ATTRIBUTES: | |
b0c0b433 | 1681 | lse = (struct ls_element *)ls_msg2edge(ted, msg, delete); |
bbd85e20 OD |
1682 | break; |
1683 | case LS_MSG_TYPE_PREFIX: | |
b0c0b433 | 1684 | lse = (struct ls_element *)ls_msg2subnet(ted, msg, delete); |
bbd85e20 OD |
1685 | break; |
1686 | default: | |
b0c0b433 | 1687 | lse = NULL; |
bbd85e20 OD |
1688 | break; |
1689 | } | |
1690 | ||
b0c0b433 OD |
1691 | return lse; |
1692 | } | |
1693 | ||
1694 | struct ls_element *ls_stream2ted(struct ls_ted *ted, struct stream *s, | |
1695 | bool delete) | |
1696 | { | |
1697 | struct ls_message *msg; | |
1698 | struct ls_element *lse = NULL; | |
1699 | ||
1700 | msg = ls_parse_msg(s); | |
1701 | if (msg) { | |
1702 | lse = ls_msg2ted(ted, msg, delete); | |
1703 | ls_delete_msg(msg); | |
1704 | } | |
1705 | ||
1706 | return lse; | |
1707 | } | |
1708 | ||
1709 | void ls_delete_msg(struct ls_message *msg) | |
1710 | { | |
1711 | if (msg == NULL) | |
1712 | return; | |
1713 | ||
bbd85e20 OD |
1714 | XFREE(MTYPE_LS_DB, msg); |
1715 | } | |
1716 | ||
1717 | int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient, | |
1718 | struct zapi_opaque_reg_info *dst) | |
1719 | { | |
1720 | struct ls_vertex *vertex; | |
1721 | struct ls_edge *edge; | |
1722 | struct ls_subnet *subnet; | |
1723 | struct ls_message msg; | |
1724 | ||
bbd85e20 OD |
1725 | /* Loop TED, start sending Node, then Attributes and finally Prefix */ |
1726 | frr_each(vertices, &ted->vertices, vertex) { | |
1727 | ls_vertex2msg(&msg, vertex); | |
1728 | ls_send_msg(zclient, &msg, dst); | |
1729 | } | |
1730 | frr_each(edges, &ted->edges, edge) { | |
1731 | ls_edge2msg(&msg, edge); | |
1732 | ls_send_msg(zclient, &msg, dst); | |
1733 | } | |
1734 | frr_each(subnets, &ted->subnets, subnet) { | |
1735 | ls_subnet2msg(&msg, subnet); | |
1736 | ls_send_msg(zclient, &msg, dst); | |
1737 | } | |
1738 | return 0; | |
1739 | } | |
1740 | ||
b0c0b433 OD |
1741 | /** |
1742 | * Link State Show functions | |
1743 | */ | |
1744 | static const char *const origin2txt[] = { | |
1745 | "Unknown", | |
1746 | "ISIS_L1", | |
1747 | "ISIS_L2", | |
1748 | "OSPFv2", | |
1749 | "Direct", | |
1750 | "Static" | |
1751 | }; | |
1752 | ||
1753 | static const char *const type2txt[] = { | |
1754 | "Unknown", | |
1755 | "Standard", | |
1756 | "ABR", | |
1757 | "ASBR", | |
1758 | "Remote ASBR", | |
1759 | "Pseudo" | |
1760 | }; | |
1761 | ||
1762 | static const char *const status2txt[] = { | |
1763 | "Unknown", | |
1764 | "New", | |
1765 | "Update", | |
1766 | "Delete", | |
1767 | "Sync", | |
1768 | "Orphan" | |
1769 | }; | |
1770 | ||
1771 | static const char *ls_node_id_to_text(struct ls_node_id lnid, char *str, | |
1772 | size_t size) | |
1773 | { | |
1774 | if (lnid.origin == ISIS_L1 || lnid.origin == ISIS_L2) { | |
1775 | uint8_t *id; | |
1776 | ||
1777 | id = lnid.id.iso.sys_id; | |
1778 | snprintfrr(str, size, "%02x%02x.%02x%02x.%02x%02x", id[0], | |
1779 | id[1], id[2], id[3], id[4], id[5]); | |
1780 | } else | |
1781 | snprintfrr(str, size, "%pI4", &lnid.id.ip.addr); | |
1782 | ||
1783 | return str; | |
1784 | } | |
1785 | ||
1786 | static void ls_show_vertex_vty(struct ls_vertex *vertex, struct vty *vty, | |
1787 | bool verbose) | |
1788 | { | |
1789 | struct listnode *node; | |
1790 | struct ls_node *lsn; | |
1791 | struct ls_edge *edge; | |
1792 | struct ls_subnet *subnet; | |
1793 | struct sbuf sbuf; | |
1794 | uint32_t upper; | |
1795 | ||
1796 | /* Sanity Check */ | |
1797 | if (!vertex) | |
1798 | return; | |
1799 | ||
1800 | lsn = vertex->node; | |
1801 | ||
1802 | sbuf_init(&sbuf, NULL, 0); | |
1803 | ||
1804 | sbuf_push(&sbuf, 2, "Vertex (%" PRIu64 "): %s", vertex->key, lsn->name); | |
1805 | sbuf_push(&sbuf, 0, "\tRouter Id: %pI4", &lsn->router_id); | |
1806 | sbuf_push(&sbuf, 0, "\tOrigin: %s", origin2txt[lsn->adv.origin]); | |
1807 | sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[vertex->status]); | |
1808 | if (!verbose) { | |
1809 | sbuf_push( | |
1810 | &sbuf, 0, | |
1811 | "\t%d Outgoing Edges, %d Incoming Edges, %d Subnets\n", | |
1812 | listcount(vertex->outgoing_edges), | |
1813 | listcount(vertex->incoming_edges), | |
1814 | listcount(vertex->prefixes)); | |
1815 | goto end; | |
1816 | } | |
1817 | ||
1818 | if (CHECK_FLAG(lsn->flags, LS_NODE_TYPE)) | |
1819 | sbuf_push(&sbuf, 4, "Type: %s\n", type2txt[lsn->type]); | |
1820 | if (CHECK_FLAG(lsn->flags, LS_NODE_AS_NUMBER)) | |
1821 | sbuf_push(&sbuf, 4, "AS number: %u\n", lsn->as_number); | |
1822 | if (CHECK_FLAG(lsn->flags, LS_NODE_SR)) { | |
1823 | sbuf_push(&sbuf, 4, "Segment Routing Capabilities:\n"); | |
1824 | upper = lsn->srgb.lower_bound + lsn->srgb.range_size - 1; | |
1825 | sbuf_push(&sbuf, 8, "SRGB: [%d/%d]", lsn->srgb.lower_bound, | |
1826 | upper); | |
1827 | if (CHECK_FLAG(lsn->flags, LS_NODE_SRLB)) { | |
1828 | upper = lsn->srlb.lower_bound + lsn->srlb.range_size | |
1829 | - 1; | |
1830 | sbuf_push(&sbuf, 0, "\tSRLB: [%d/%d]", | |
1831 | lsn->srlb.lower_bound, upper); | |
1832 | } | |
1833 | sbuf_push(&sbuf, 0, "\tAlgo: "); | |
1834 | for (int i = 0; i < 2; i++) { | |
1835 | if (lsn->algo[i] == 255) | |
1836 | continue; | |
1837 | ||
1838 | sbuf_push(&sbuf, 0, | |
1839 | lsn->algo[i] == 0 ? "SPF " : "S-SPF "); | |
1840 | } | |
1841 | if (CHECK_FLAG(lsn->flags, LS_NODE_MSD)) | |
1842 | sbuf_push(&sbuf, 0, "\tMSD: %d", lsn->msd); | |
1843 | sbuf_push(&sbuf, 0, "\n"); | |
1844 | } | |
1845 | ||
1846 | sbuf_push(&sbuf, 4, "Outgoing Edges: %d\n", | |
1847 | listcount(vertex->outgoing_edges)); | |
1848 | for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) { | |
1849 | if (edge->destination) { | |
1850 | lsn = edge->destination->node; | |
1851 | sbuf_push(&sbuf, 6, "To:\t%s(%pI4)", lsn->name, | |
1852 | &lsn->router_id); | |
1853 | } else { | |
1854 | sbuf_push(&sbuf, 6, "To:\t- (0.0.0.0)"); | |
1855 | } | |
1856 | sbuf_push(&sbuf, 0, "\tLocal: %pI4\tRemote: %pI4\n", | |
1857 | &edge->attributes->standard.local, | |
1858 | &edge->attributes->standard.remote); | |
1859 | } | |
1860 | ||
1861 | sbuf_push(&sbuf, 4, "Incoming Edges: %d\n", | |
1862 | listcount(vertex->incoming_edges)); | |
1863 | for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, node, edge)) { | |
1864 | if (edge->source) { | |
1865 | lsn = edge->source->node; | |
1866 | sbuf_push(&sbuf, 6, "From:\t%s(%pI4)", lsn->name, | |
1867 | &lsn->router_id); | |
1868 | } else { | |
1869 | sbuf_push(&sbuf, 6, "From:\t- (0.0.0.0)"); | |
1870 | } | |
1871 | sbuf_push(&sbuf, 0, "\tRemote: %pI4\tLocal: %pI4\n", | |
1872 | &edge->attributes->standard.local, | |
1873 | &edge->attributes->standard.remote); | |
1874 | } | |
1875 | ||
1876 | sbuf_push(&sbuf, 4, "Subnets: %d\n", listcount(vertex->prefixes)); | |
1877 | for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet)) | |
1878 | sbuf_push(&sbuf, 6, "Prefix:\t%pFX\n", &subnet->key); | |
1879 | ||
1880 | end: | |
1881 | vty_out(vty, "%s\n", sbuf_buf(&sbuf)); | |
1882 | sbuf_free(&sbuf); | |
1883 | } | |
1884 | ||
1885 | static void ls_show_vertex_json(struct ls_vertex *vertex, | |
1886 | struct json_object *json) | |
1887 | { | |
1888 | struct ls_node *lsn; | |
1889 | json_object *jsr, *jalgo, *jobj; | |
1890 | char buf[INET6_BUFSIZ]; | |
1891 | ||
1892 | /* Sanity Check */ | |
1893 | if (!vertex) | |
1894 | return; | |
1895 | ||
1896 | lsn = vertex->node; | |
1897 | ||
1898 | json_object_int_add(json, "vertex-id", vertex->key); | |
1899 | json_object_string_add(json, "status", status2txt[vertex->status]); | |
1900 | json_object_string_add(json, "origin", origin2txt[lsn->adv.origin]); | |
1901 | if (CHECK_FLAG(lsn->flags, LS_NODE_NAME)) | |
1902 | json_object_string_add(json, "name", lsn->name); | |
1903 | if (CHECK_FLAG(lsn->flags, LS_NODE_ROUTER_ID)) { | |
1904 | snprintfrr(buf, INET6_BUFSIZ, "%pI4", &lsn->router_id); | |
1905 | json_object_string_add(json, "router-id", buf); | |
1906 | } | |
1907 | if (CHECK_FLAG(lsn->flags, LS_NODE_ROUTER_ID6)) { | |
1908 | snprintfrr(buf, INET6_BUFSIZ, "%pI6", &lsn->router6_id); | |
1909 | json_object_string_add(json, "router-id-v6", buf); | |
1910 | } | |
1911 | if (CHECK_FLAG(lsn->flags, LS_NODE_TYPE)) | |
1912 | json_object_string_add(json, "vertex-type", | |
1913 | type2txt[lsn->type]); | |
1914 | if (CHECK_FLAG(lsn->flags, LS_NODE_AS_NUMBER)) | |
1915 | json_object_int_add(json, "asn", lsn->as_number); | |
1916 | if (CHECK_FLAG(lsn->flags, LS_NODE_SR)) { | |
1917 | jsr = json_object_new_object(); | |
1918 | json_object_object_add(json, "segment-routing", jsr); | |
1919 | json_object_int_add(jsr, "srgb-size", lsn->srgb.range_size); | |
1920 | json_object_int_add(jsr, "srgb-lower", lsn->srgb.lower_bound); | |
1921 | jalgo = json_object_new_array(); | |
1922 | json_object_object_add(jsr, "algorithms", jalgo); | |
1923 | for (int i = 0; i < 2; i++) { | |
1924 | if (lsn->algo[i] == 255) | |
1925 | continue; | |
1926 | jobj = json_object_new_object(); | |
1927 | ||
1928 | snprintfrr(buf, 2, "%u", i); | |
1929 | json_object_string_add( | |
1930 | jobj, buf, lsn->algo[i] == 0 ? "SPF" : "S-SPF"); | |
1931 | json_object_array_add(jalgo, jobj); | |
1932 | } | |
1933 | if (CHECK_FLAG(lsn->flags, LS_NODE_SRLB)) { | |
1934 | json_object_int_add(jsr, "srlb-size", | |
1935 | lsn->srlb.range_size); | |
1936 | json_object_int_add(jsr, "srlb-lower", | |
1937 | lsn->srlb.lower_bound); | |
1938 | } | |
1939 | if (CHECK_FLAG(lsn->flags, LS_NODE_MSD)) | |
1940 | json_object_int_add(jsr, "msd", lsn->msd); | |
1941 | } | |
1942 | } | |
1943 | ||
1944 | void ls_show_vertex(struct ls_vertex *vertex, struct vty *vty, | |
1945 | struct json_object *json, bool verbose) | |
1946 | { | |
1947 | if (json) | |
1948 | ls_show_vertex_json(vertex, json); | |
1949 | else if (vty) | |
1950 | ls_show_vertex_vty(vertex, vty, verbose); | |
1951 | } | |
1952 | ||
1953 | void ls_show_vertices(struct ls_ted *ted, struct vty *vty, | |
1954 | struct json_object *json, bool verbose) | |
1955 | { | |
1956 | struct ls_vertex *vertex; | |
1957 | json_object *jnodes, *jnode; | |
1958 | ||
1959 | if (json) { | |
1960 | jnodes = json_object_new_array(); | |
1961 | json_object_object_add(json, "vertices", jnodes); | |
1962 | frr_each (vertices, &ted->vertices, vertex) { | |
1963 | jnode = json_object_new_object(); | |
1964 | ls_show_vertex(vertex, NULL, jnode, verbose); | |
1965 | json_object_array_add(jnodes, jnode); | |
1966 | } | |
1967 | } else if (vty) { | |
1968 | frr_each (vertices, &ted->vertices, vertex) | |
1969 | ls_show_vertex(vertex, vty, NULL, verbose); | |
1970 | } | |
1971 | } | |
1972 | ||
1973 | static void ls_show_edge_vty(struct ls_edge *edge, struct vty *vty, | |
1974 | bool verbose) | |
1975 | { | |
1976 | struct ls_attributes *attr; | |
1977 | struct sbuf sbuf; | |
1978 | char buf[INET6_BUFSIZ]; | |
1979 | ||
1980 | attr = edge->attributes; | |
1981 | sbuf_init(&sbuf, NULL, 0); | |
1982 | ||
1983 | sbuf_push(&sbuf, 2, "Edge (%" PRIu64 "): ", edge->key); | |
1984 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) | |
1985 | sbuf_push(&sbuf, 0, "%pI4", &attr->standard.local); | |
1986 | else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) | |
1987 | sbuf_push(&sbuf, 0, "%pI6", &attr->standard.local6); | |
1988 | else | |
1989 | sbuf_push(&sbuf, 0, "%u/%u", attr->standard.local_id, | |
1990 | attr->standard.remote_id); | |
1991 | ls_node_id_to_text(attr->adv, buf, INET6_BUFSIZ); | |
1992 | sbuf_push(&sbuf, 0, "\tAdv. Vertex: %s", buf); | |
1993 | sbuf_push(&sbuf, 0, "\tMetric: %u", attr->metric); | |
1994 | sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[edge->status]); | |
1995 | ||
1996 | if (!verbose) | |
1997 | goto end; | |
1998 | ||
1999 | sbuf_push(&sbuf, 4, "Origin: %s\n", origin2txt[attr->adv.origin]); | |
2000 | if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) | |
2001 | sbuf_push(&sbuf, 4, "Name: %s\n", attr->name); | |
2002 | if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) | |
2003 | sbuf_push(&sbuf, 4, "TE Metric: %u\n", | |
2004 | attr->standard.te_metric); | |
2005 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) | |
2006 | sbuf_push(&sbuf, 4, "Admin Group: 0x%x\n", | |
2007 | attr->standard.admin_group); | |
2008 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) | |
2009 | sbuf_push(&sbuf, 4, "Local IPv4 address: %pI4\n", | |
2010 | &attr->standard.local); | |
2011 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) | |
2012 | sbuf_push(&sbuf, 4, "Remote IPv4 address: %pI4\n", | |
2013 | &attr->standard.remote); | |
2014 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) | |
2015 | sbuf_push(&sbuf, 4, "Local IPv6 address: %pI6\n", | |
2016 | &attr->standard.local6); | |
2017 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6)) | |
2018 | sbuf_push(&sbuf, 4, "Remote IPv6 address: %pI6\n", | |
2019 | &attr->standard.remote6); | |
2020 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) | |
2021 | sbuf_push(&sbuf, 4, "Local Identifier: %u\n", | |
2022 | attr->standard.local_id); | |
2023 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID)) | |
2024 | sbuf_push(&sbuf, 4, "Remote Identifier: %u\n", | |
2025 | attr->standard.remote_id); | |
2026 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW)) | |
2027 | sbuf_push(&sbuf, 4, "Maximum Bandwidth: %g (Bytes/s)\n", | |
2028 | attr->standard.max_bw); | |
2029 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW)) | |
2030 | sbuf_push(&sbuf, 4, | |
2031 | "Maximum Reservable Bandwidth: %g (Bytes/s)\n", | |
2032 | attr->standard.max_rsv_bw); | |
2033 | if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) { | |
2034 | sbuf_push(&sbuf, 4, "Unreserved Bandwidth per Class Type\n"); | |
2035 | for (int i = 0; i < MAX_CLASS_TYPE; i += 2) | |
2036 | sbuf_push(&sbuf, 8, | |
2037 | "[%d]: %g (Bytes/sec)\t[%d]: %g (Bytes/s)\n", | |
2038 | i, attr->standard.unrsv_bw[i], i + 1, | |
2039 | attr->standard.unrsv_bw[i + 1]); | |
2040 | } | |
2041 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS)) | |
2042 | sbuf_push(&sbuf, 4, "Remote AS: %u\n", | |
2043 | attr->standard.remote_as); | |
2044 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR)) | |
2045 | sbuf_push(&sbuf, 4, "Remote ASBR IPv4 address: %pI4\n", | |
2046 | &attr->standard.remote_addr); | |
2047 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6)) | |
2048 | sbuf_push(&sbuf, 4, "Remote ASBR IPv6 address: %pI6\n", | |
2049 | &attr->standard.remote_addr6); | |
2050 | if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY)) | |
2051 | sbuf_push(&sbuf, 4, "Average Link Delay: %d (micro-sec)\n", | |
2052 | attr->extended.delay); | |
2053 | if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) | |
2054 | sbuf_push(&sbuf, 4, "Min/Max Link Delay: %d/%d (micro-sec)\n", | |
2055 | attr->extended.min_delay, attr->extended.max_delay); | |
2056 | if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER)) | |
2057 | sbuf_push(&sbuf, 4, "Delay Variation: %d (micro-sec)\n", | |
2058 | attr->extended.jitter); | |
2059 | if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS)) | |
2060 | sbuf_push(&sbuf, 4, "Link Loss: %g (%%)\n", | |
2061 | (float)(attr->extended.pkt_loss * LOSS_PRECISION)); | |
2062 | if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW)) | |
2063 | sbuf_push(&sbuf, 4, "Available Bandwidth: %g (Bytes/s)\n", | |
2064 | attr->extended.ava_bw); | |
2065 | if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW)) | |
2066 | sbuf_push(&sbuf, 4, "Residual Bandwidth: %g (Bytes/s)\n", | |
2067 | attr->extended.rsv_bw); | |
2068 | if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW)) | |
2069 | sbuf_push(&sbuf, 4, "Utilized Bandwidth: %g (Bytes/s)\n", | |
2070 | attr->extended.used_bw); | |
2071 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) { | |
2072 | sbuf_push(&sbuf, 4, "Adjacency-SID: %u", attr->adj_sid[0].sid); | |
2073 | sbuf_push(&sbuf, 0, "\tFlags: 0x%x\tWeight: 0x%x\n", | |
2074 | attr->adj_sid[0].flags, attr->adj_sid[0].weight); | |
2075 | } | |
2076 | if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { | |
2077 | sbuf_push(&sbuf, 4, "Bck. Adjacency-SID: %u", | |
2078 | attr->adj_sid[1].sid); | |
2079 | sbuf_push(&sbuf, 0, "\tFlags: 0x%x\tWeight: 0x%x\n", | |
2080 | attr->adj_sid[1].flags, attr->adj_sid[1].weight); | |
2081 | } | |
2082 | if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { | |
2083 | sbuf_push(&sbuf, 4, "SRLGs: %d", attr->srlg_len); | |
2084 | for (int i = 1; i < attr->srlg_len; i++) { | |
2085 | if (i % 8) | |
2086 | sbuf_push(&sbuf, 8, "\n%u", attr->srlgs[i]); | |
2087 | else | |
2088 | sbuf_push(&sbuf, 8, ", %u", attr->srlgs[i]); | |
2089 | } | |
2090 | sbuf_push(&sbuf, 0, "\n"); | |
2091 | } | |
2092 | ||
2093 | end: | |
2094 | vty_out(vty, "%s\n", sbuf_buf(&sbuf)); | |
2095 | sbuf_free(&sbuf); | |
2096 | } | |
2097 | ||
2098 | static void ls_show_edge_json(struct ls_edge *edge, struct json_object *json) | |
2099 | { | |
2100 | struct ls_attributes *attr; | |
2101 | struct json_object *jte, *jbw, *jobj, *jsr = NULL, *jsrlg; | |
2102 | char buf[INET6_BUFSIZ]; | |
2103 | ||
2104 | attr = edge->attributes; | |
2105 | ||
2106 | json_object_int_add(json, "edge-id", edge->key); | |
2107 | json_object_string_add(json, "status", status2txt[edge->status]); | |
2108 | json_object_string_add(json, "origin", origin2txt[attr->adv.origin]); | |
2109 | ls_node_id_to_text(attr->adv, buf, INET6_BUFSIZ); | |
2110 | json_object_string_add(json, "advertised-router", buf); | |
2111 | if (edge->source) | |
2112 | json_object_int_add(json, "local-vertex-id", edge->source->key); | |
2113 | if (edge->destination) | |
2114 | json_object_int_add(json, "remote-vertex-id", | |
2115 | edge->destination->key); | |
2116 | json_object_int_add(json, "metric", attr->metric); | |
2117 | if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) | |
2118 | json_object_string_add(json, "name", attr->name); | |
2119 | jte = json_object_new_object(); | |
2120 | json_object_object_add(json, "edge-attributes", jte); | |
2121 | if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) | |
2122 | json_object_int_add(jte, "te-metric", attr->standard.te_metric); | |
2123 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) | |
2124 | json_object_int_add(jte, "admin-group", | |
2125 | attr->standard.admin_group); | |
2126 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) { | |
2127 | snprintfrr(buf, INET6_BUFSIZ, "%pI4", &attr->standard.local); | |
2128 | json_object_string_add(jte, "local-address", buf); | |
2129 | } | |
2130 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) { | |
2131 | snprintfrr(buf, INET6_BUFSIZ, "%pI4", &attr->standard.remote); | |
2132 | json_object_string_add(jte, "remote-address", buf); | |
2133 | } | |
2134 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) { | |
2135 | snprintfrr(buf, INET6_BUFSIZ, "%pI6", &attr->standard.local6); | |
2136 | json_object_string_add(jte, "local-address-v6", buf); | |
2137 | } | |
2138 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6)) { | |
2139 | snprintfrr(buf, INET6_BUFSIZ, "%pI6", &attr->standard.remote6); | |
2140 | json_object_string_add(jte, "remote-address-v6", buf); | |
2141 | } | |
2142 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) | |
2143 | json_object_int_add(jte, "local-identifier", | |
2144 | attr->standard.local_id); | |
2145 | if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID)) | |
2146 | json_object_int_add(jte, "remote-identifier", | |
2147 | attr->standard.remote_id); | |
2148 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW)) | |
2149 | json_object_double_add(jte, "max-link-bandwidth", | |
2150 | attr->standard.max_bw); | |
2151 | if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW)) | |
2152 | json_object_double_add(jte, "max-resv-link-bandwidth", | |
2153 | attr->standard.max_rsv_bw); | |
2154 | if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) { | |
2155 | jbw = json_object_new_array(); | |
2156 | json_object_object_add(jte, "unreserved-bandwidth", jbw); | |
2157 | for (int i = 0; i < MAX_CLASS_TYPE; i++) { | |
2158 | jobj = json_object_new_object(); | |
2159 | snprintfrr(buf, 13, "class-type-%u", i); | |
2160 | json_object_double_add(jobj, buf, | |
2161 | attr->standard.unrsv_bw[i]); | |
2162 | json_object_array_add(jbw, jobj); | |
2163 | } | |
2164 | } | |
2165 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS)) | |
2166 | json_object_int_add(jte, "remote-asn", | |
2167 | attr->standard.remote_as); | |
2168 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR)) { | |
2169 | snprintfrr(buf, INET6_BUFSIZ, "%pI4", | |
2170 | &attr->standard.remote_addr); | |
2171 | json_object_string_add(jte, "remote-as-address", buf); | |
2172 | } | |
2173 | if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6)) { | |
2174 | snprintfrr(buf, INET6_BUFSIZ, "%pI6", | |
2175 | &attr->standard.remote_addr6); | |
2176 | json_object_string_add(jte, "remote-as-address-v6", buf); | |
2177 | } | |
2178 | if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY)) | |
2179 | json_object_int_add(jte, "delay", attr->extended.delay); | |
2180 | if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) { | |
2181 | json_object_int_add(jte, "min-delay", attr->extended.min_delay); | |
2182 | json_object_int_add(jte, "max-delay", attr->extended.max_delay); | |
2183 | } | |
2184 | if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER)) | |
2185 | json_object_int_add(jte, "jitter", attr->extended.jitter); | |
2186 | if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS)) | |
2187 | json_object_double_add( | |
2188 | jte, "loss", attr->extended.pkt_loss * LOSS_PRECISION); | |
2189 | if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW)) | |
2190 | json_object_double_add(jte, "available-bandwidth", | |
2191 | attr->extended.ava_bw); | |
2192 | if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW)) | |
2193 | json_object_double_add(jte, "residual-bandwidth", | |
2194 | attr->extended.rsv_bw); | |
2195 | if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW)) | |
2196 | json_object_double_add(jte, "utilized-bandwidth", | |
2197 | attr->extended.used_bw); | |
2198 | if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { | |
2199 | jsrlg = json_object_new_array(); | |
2200 | json_object_object_add(jte, "srlgs", jsrlg); | |
2201 | for (int i = 1; i < attr->srlg_len; i++) { | |
2202 | jobj = json_object_new_object(); | |
2203 | json_object_int_add(jobj, "srlg", attr->srlgs[i]); | |
2204 | json_object_array_add(jsrlg, jobj); | |
2205 | } | |
2206 | } | |
2207 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) { | |
2208 | jsr = json_object_new_array(); | |
2209 | json_object_object_add(json, "segment-routing", jsr); | |
2210 | jobj = json_object_new_object(); | |
2211 | json_object_int_add(jobj, "adj-sid", attr->adj_sid[0].sid); | |
2212 | snprintfrr(buf, 6, "0x%x", attr->adj_sid[0].flags); | |
2213 | json_object_string_add(jobj, "flags", buf); | |
2214 | json_object_int_add(jobj, "weight", attr->adj_sid[0].weight); | |
2215 | json_object_array_add(jsr, jobj); | |
2216 | } | |
2217 | if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { | |
2218 | if (!jsr) { | |
2219 | jsr = json_object_new_array(); | |
2220 | json_object_object_add(json, "segment-routing", jsr); | |
2221 | } | |
2222 | jobj = json_object_new_object(); | |
2223 | json_object_int_add(jobj, "adj-sid", attr->adj_sid[1].sid); | |
2224 | snprintfrr(buf, 6, "0x%x", attr->adj_sid[1].flags); | |
2225 | json_object_string_add(jobj, "flags", buf); | |
2226 | json_object_int_add(jobj, "weight", attr->adj_sid[1].weight); | |
2227 | json_object_array_add(jsr, jobj); | |
2228 | } | |
2229 | } | |
2230 | ||
2231 | void ls_show_edge(struct ls_edge *edge, struct vty *vty, | |
2232 | struct json_object *json, bool verbose) | |
2233 | { | |
2234 | /* Sanity Check */ | |
2235 | if (!edge) | |
2236 | return; | |
2237 | ||
2238 | if (json) | |
2239 | ls_show_edge_json(edge, json); | |
2240 | else if (vty) | |
2241 | ls_show_edge_vty(edge, vty, verbose); | |
2242 | } | |
2243 | ||
2244 | void ls_show_edges(struct ls_ted *ted, struct vty *vty, | |
2245 | struct json_object *json, bool verbose) | |
2246 | { | |
2247 | struct ls_edge *edge; | |
2248 | json_object *jedges, *jedge; | |
2249 | ||
2250 | if (json) { | |
2251 | jedges = json_object_new_array(); | |
2252 | json_object_object_add(json, "edges", jedges); | |
2253 | frr_each (edges, &ted->edges, edge) { | |
2254 | jedge = json_object_new_object(); | |
2255 | ls_show_edge(edge, NULL, jedge, verbose); | |
2256 | json_object_array_add(jedges, jedge); | |
2257 | } | |
2258 | } else if (vty) { | |
2259 | frr_each (edges, &ted->edges, edge) | |
2260 | ls_show_edge(edge, vty, NULL, verbose); | |
2261 | } | |
2262 | } | |
2263 | ||
2264 | static void ls_show_subnet_vty(struct ls_subnet *subnet, struct vty *vty, | |
2265 | bool verbose) | |
2266 | { | |
2267 | struct ls_prefix *pref; | |
2268 | struct sbuf sbuf; | |
2269 | char buf[INET6_BUFSIZ]; | |
2270 | ||
2271 | pref = subnet->ls_pref; | |
2272 | sbuf_init(&sbuf, NULL, 0); | |
2273 | ||
2274 | sbuf_push(&sbuf, 2, "Subnet: %pFX", &subnet->key); | |
2275 | ls_node_id_to_text(pref->adv, buf, INET6_BUFSIZ); | |
2276 | sbuf_push(&sbuf, 0, "\tAdv. Vertex: %s", buf); | |
2277 | sbuf_push(&sbuf, 0, "\tMetric: %d", pref->metric); | |
2278 | sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[subnet->status]); | |
2279 | ||
2280 | if (!verbose) | |
2281 | goto end; | |
2282 | ||
2283 | sbuf_push(&sbuf, 4, "Origin: %s\n", origin2txt[pref->adv.origin]); | |
2284 | if (CHECK_FLAG(pref->flags, LS_PREF_IGP_FLAG)) | |
2285 | sbuf_push(&sbuf, 4, "Flags: %d\n", pref->igp_flag); | |
2286 | ||
2287 | if (CHECK_FLAG(pref->flags, LS_PREF_ROUTE_TAG)) | |
2288 | sbuf_push(&sbuf, 4, "Tag: %d\n", pref->route_tag); | |
2289 | ||
2290 | if (CHECK_FLAG(pref->flags, LS_PREF_EXTENDED_TAG)) | |
2291 | sbuf_push(&sbuf, 4, "Extended Tag: %" PRIu64 "\n", | |
2292 | pref->extended_tag); | |
2293 | ||
2294 | if (CHECK_FLAG(pref->flags, LS_PREF_SR)) | |
2295 | sbuf_push(&sbuf, 4, "SID: %d\tAlgorithm: %d\tFlags: 0x%x\n", | |
2296 | pref->sr.sid, pref->sr.algo, pref->sr.sid_flag); | |
2297 | ||
2298 | end: | |
2299 | vty_out(vty, "%s\n", sbuf_buf(&sbuf)); | |
2300 | sbuf_free(&sbuf); | |
2301 | } | |
2302 | ||
2303 | static void ls_show_subnet_json(struct ls_subnet *subnet, | |
2304 | struct json_object *json) | |
2305 | { | |
2306 | struct ls_prefix *pref; | |
2307 | json_object *jsr; | |
2308 | char buf[INET6_BUFSIZ]; | |
2309 | ||
2310 | pref = subnet->ls_pref; | |
2311 | ||
2312 | snprintfrr(buf, INET6_BUFSIZ, "%pFX", &subnet->key); | |
2313 | json_object_string_add(json, "subnet-id", buf); | |
2314 | json_object_string_add(json, "status", status2txt[subnet->status]); | |
2315 | json_object_string_add(json, "origin", origin2txt[pref->adv.origin]); | |
2316 | ls_node_id_to_text(pref->adv, buf, INET6_BUFSIZ); | |
2317 | json_object_string_add(json, "advertised-router", buf); | |
2318 | if (subnet->vertex) | |
2319 | json_object_int_add(json, "vertex-id", subnet->vertex->key); | |
2320 | json_object_int_add(json, "metric", pref->metric); | |
2321 | if (CHECK_FLAG(pref->flags, LS_PREF_IGP_FLAG)) { | |
2322 | snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->igp_flag); | |
2323 | json_object_string_add(json, "flags", buf); | |
2324 | } | |
2325 | if (CHECK_FLAG(pref->flags, LS_PREF_ROUTE_TAG)) | |
2326 | json_object_int_add(json, "tag", pref->route_tag); | |
2327 | if (CHECK_FLAG(pref->flags, LS_PREF_EXTENDED_TAG)) | |
2328 | json_object_int_add(json, "extended-tag", pref->extended_tag); | |
2329 | if (CHECK_FLAG(pref->flags, LS_PREF_SR)) { | |
2330 | jsr = json_object_new_object(); | |
2331 | json_object_object_add(json, "segment-routing", jsr); | |
2332 | json_object_int_add(jsr, "pref-sid", pref->sr.sid); | |
2333 | json_object_int_add(jsr, "algo", pref->sr.algo); | |
2334 | snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->sr.sid_flag); | |
2335 | json_object_string_add(jsr, "flags", buf); | |
2336 | } | |
2337 | } | |
2338 | ||
2339 | void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, | |
2340 | struct json_object *json, bool verbose) | |
2341 | { | |
2342 | /* Sanity Check */ | |
2343 | if (!subnet) | |
2344 | return; | |
2345 | ||
2346 | if (json) | |
2347 | ls_show_subnet_json(subnet, json); | |
2348 | else if (vty) | |
2349 | ls_show_subnet_vty(subnet, vty, verbose); | |
2350 | } | |
2351 | ||
2352 | void ls_show_subnets(struct ls_ted *ted, struct vty *vty, | |
2353 | struct json_object *json, bool verbose) | |
2354 | { | |
2355 | struct ls_subnet *subnet; | |
2356 | json_object *jsubs, *jsub; | |
2357 | ||
2358 | if (json) { | |
2359 | jsubs = json_object_new_array(); | |
2360 | json_object_object_add(json, "subnets", jsubs); | |
2361 | frr_each (subnets, &ted->subnets, subnet) { | |
2362 | jsub = json_object_new_object(); | |
2363 | ls_show_subnet(subnet, NULL, jsub, verbose); | |
2364 | json_object_array_add(jsubs, jsub); | |
2365 | } | |
2366 | } else if (vty) { | |
2367 | frr_each (subnets, &ted->subnets, subnet) | |
2368 | ls_show_subnet(subnet, vty, NULL, verbose); | |
2369 | } | |
2370 | } | |
2371 | ||
2372 | void ls_show_ted(struct ls_ted *ted, struct vty *vty, struct json_object *json, | |
2373 | bool verbose) | |
2374 | { | |
2375 | json_object *jted; | |
2376 | ||
2377 | if (json) { | |
2378 | jted = json_object_new_object(); | |
2379 | json_object_object_add(json, "ted", jted); | |
2380 | json_object_string_add(jted, "name", ted->name); | |
2381 | json_object_int_add(jted, "key", ted->key); | |
2382 | json_object_int_add(jted, "verticesCount", | |
2383 | vertices_count(&ted->vertices)); | |
2384 | json_object_int_add(jted, "edgesCount", | |
2385 | edges_count(&ted->edges)); | |
2386 | json_object_int_add(jted, "subnetsCount", | |
2387 | subnets_count(&ted->subnets)); | |
2388 | ls_show_vertices(ted, NULL, jted, verbose); | |
2389 | ls_show_edges(ted, NULL, jted, verbose); | |
2390 | ls_show_subnets(ted, NULL, jted, verbose); | |
2391 | return; | |
2392 | } | |
2393 | ||
2394 | if (vty) { | |
2395 | vty_out(vty, | |
2396 | "\n\tTraffic Engineering Database: %s (key: %d)\n\n", | |
2397 | ted->name, ted->key); | |
2398 | ls_show_vertices(ted, vty, NULL, verbose); | |
2399 | ls_show_edges(ted, vty, NULL, verbose); | |
2400 | ls_show_subnets(ted, vty, NULL, verbose); | |
2401 | vty_out(vty, | |
2402 | "\n\tTotal: %zu Vertices, %zu Edges, %zu Subnets\n\n", | |
2403 | vertices_count(&ted->vertices), | |
2404 | edges_count(&ted->edges), subnets_count(&ted->subnets)); | |
2405 | } | |
2406 | } | |
2407 | ||
bbd85e20 OD |
2408 | void ls_dump_ted(struct ls_ted *ted) |
2409 | { | |
2410 | struct ls_vertex *vertex; | |
2411 | struct ls_edge *edge; | |
2412 | struct ls_subnet *subnet; | |
b0c0b433 | 2413 | const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; |
bbd85e20 OD |
2414 | |
2415 | zlog_debug("(%s) Ted init", __func__); | |
bbd85e20 OD |
2416 | |
2417 | /* Loop TED, start printing Node, then Attributes and finally Prefix */ | |
b0c0b433 | 2418 | frr_each (vertices, &ted->vertices, vertex) { |
1d5453d6 | 2419 | zlog_debug(" Ted node (%s %pI4 %s)", |
bbd85e20 OD |
2420 | vertex->node->name[0] ? vertex->node->name |
2421 | : "no name node", | |
2422 | &vertex->node->router_id, | |
b0c0b433 | 2423 | origin2txt[vertex->node->adv.origin]); |
bbd85e20 OD |
2424 | struct listnode *lst_node; |
2425 | struct ls_edge *vertex_edge; | |
2426 | ||
2427 | for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, lst_node, | |
2428 | vertex_edge)) { | |
2429 | zlog_debug( | |
b0c0b433 | 2430 | " inc edge key:%" PRIu64 " attr key:%pI4 loc:(%pI4) rmt:(%pI4)", |
bbd85e20 OD |
2431 | vertex_edge->key, |
2432 | &vertex_edge->attributes->adv.id.ip.addr, | |
2433 | &vertex_edge->attributes->standard.local, | |
2434 | &vertex_edge->attributes->standard.remote); | |
2435 | } | |
2436 | for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, lst_node, | |
2437 | vertex_edge)) { | |
2438 | zlog_debug( | |
b0c0b433 | 2439 | " out edge key:%" PRIu64 " attr key:%pI4 loc:(%pI4) rmt:(%pI4)", |
bbd85e20 OD |
2440 | vertex_edge->key, |
2441 | &vertex_edge->attributes->adv.id.ip.addr, | |
2442 | &vertex_edge->attributes->standard.local, | |
2443 | &vertex_edge->attributes->standard.remote); | |
2444 | } | |
2445 | } | |
b0c0b433 OD |
2446 | frr_each (edges, &ted->edges, edge) { |
2447 | zlog_debug(" Ted edge key:%" PRIu64 "src:%pI4 dst:%pI4", edge->key, | |
2448 | edge->source ? &edge->source->node->router_id | |
2449 | : &inaddr_any, | |
2450 | edge->destination | |
2451 | ? &edge->destination->node->router_id | |
2452 | : &inaddr_any); | |
bbd85e20 | 2453 | } |
b0c0b433 OD |
2454 | frr_each (subnets, &ted->subnets, subnet) { |
2455 | zlog_debug(" Ted subnet key:%pFX vertex:%pI4", | |
2456 | &subnet->ls_pref->pref, | |
2457 | &subnet->vertex->node->adv.id.ip.addr); | |
bbd85e20 OD |
2458 | } |
2459 | zlog_debug("(%s) Ted end", __func__); | |
2460 | } |