]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_ri.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / ospfd / ospf_ri.c
1 /*
2 * This is an implementation of RFC4970 Router Information
3 * with support of RFC5088 PCE Capabilites announcement
4 *
5 * Module name: Router Information
6 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
7 * Copyright (C) 2012 - 2017 Orange Labs http://www.orange.com/
8 *
9 * This file is part of GNU Quagga.
10 *
11 * GNU Zebra is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2, or (at your option) any
14 * later version.
15 *
16 * GNU Quagga is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; see the file COPYING; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 #include <zebra.h>
27 #include <math.h>
28
29 #include "linklist.h"
30 #include "prefix.h"
31 #include "if.h"
32 #include "table.h"
33 #include "memory.h"
34 #include "command.h"
35 #include "vty.h"
36 #include "stream.h"
37 #include "log.h"
38 #include "thread.h"
39 #include "hash.h"
40 #include "sockunion.h" /* for inet_aton() */
41 #include "mpls.h"
42
43 #include "ospfd/ospfd.h"
44 #include "ospfd/ospf_interface.h"
45 #include "ospfd/ospf_ism.h"
46 #include "ospfd/ospf_asbr.h"
47 #include "ospfd/ospf_lsa.h"
48 #include "ospfd/ospf_lsdb.h"
49 #include "ospfd/ospf_neighbor.h"
50 #include "ospfd/ospf_nsm.h"
51 #include "ospfd/ospf_flood.h"
52 #include "ospfd/ospf_packet.h"
53 #include "ospfd/ospf_spf.h"
54 #include "ospfd/ospf_dump.h"
55 #include "ospfd/ospf_route.h"
56 #include "ospfd/ospf_ase.h"
57 #include "ospfd/ospf_zebra.h"
58 #include "ospfd/ospf_sr.h"
59 #include "ospfd/ospf_ri.h"
60 #include "ospfd/ospf_errors.h"
61
62 /*
63 * Global variable to manage Opaque-LSA/Router Information on this node.
64 * Note that all parameter values are stored in network byte order.
65 */
66 static struct ospf_router_info OspfRI;
67
68 /*------------------------------------------------------------------------------*
69 * Followings are initialize/terminate functions for Router Information
70 *handling.
71 *------------------------------------------------------------------------------*/
72
73 static void ospf_router_info_ism_change(struct ospf_interface *oi,
74 int old_status);
75 static void ospf_router_info_config_write_router(struct vty *vty);
76 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa);
77 static int ospf_router_info_lsa_originate(void *arg);
78 static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa);
79 static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai,
80 enum lsa_opcode opcode);
81 static void ospf_router_info_register_vty(void);
82 static int ospf_router_info_lsa_update(struct ospf_lsa *lsa);
83 static void del_area_info(void *val);
84 static void del_pce_info(void *val);
85
86 int ospf_router_info_init(void)
87 {
88
89 zlog_info("RI (%s): Initialize Router Information", __func__);
90
91 memset(&OspfRI, 0, sizeof(struct ospf_router_info));
92 OspfRI.enabled = false;
93 OspfRI.registered = 0;
94 OspfRI.scope = OSPF_OPAQUE_AS_LSA;
95 OspfRI.as_flags = RIFLG_LSA_INACTIVE;
96 OspfRI.area_info = list_new();
97 OspfRI.area_info->del = del_area_info;
98
99 /* Initialize pce domain and neighbor list */
100 OspfRI.pce_info.enabled = false;
101 OspfRI.pce_info.pce_domain = list_new();
102 OspfRI.pce_info.pce_domain->del = del_pce_info;
103 OspfRI.pce_info.pce_neighbor = list_new();
104 OspfRI.pce_info.pce_neighbor->del = del_pce_info;
105
106 /* Initialize Segment Routing information structure */
107 OspfRI.sr_info.enabled = false;
108
109 ospf_router_info_register_vty();
110
111 return 0;
112 }
113
114 static int ospf_router_info_register(uint8_t scope)
115 {
116 int rc = 0;
117
118 if (OspfRI.registered)
119 return rc;
120
121 zlog_info("RI (%s): Register Router Information with scope %s(%d)",
122 __func__,
123 scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope);
124 rc = ospf_register_opaque_functab(
125 scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA,
126 NULL, /* new interface */
127 NULL, /* del interface */
128 ospf_router_info_ism_change,
129 NULL, /* NSM change */
130 ospf_router_info_config_write_router,
131 NULL, /* Config. write interface */
132 NULL, /* Config. write debug */
133 ospf_router_info_show_info, ospf_router_info_lsa_originate,
134 ospf_router_info_lsa_refresh, ospf_router_info_lsa_update,
135 NULL); /* del_lsa_hook */
136
137 if (rc != 0) {
138 flog_warn(
139 EC_OSPF_OPAQUE_REGISTRATION,
140 "RI (%s): Failed to register functions", __func__);
141 return rc;
142 }
143
144 OspfRI.registered = 1;
145 OspfRI.scope = scope;
146 return rc;
147 }
148
149 static int ospf_router_info_unregister()
150 {
151
152 if ((OspfRI.scope != OSPF_OPAQUE_AS_LSA)
153 && (OspfRI.scope != OSPF_OPAQUE_AREA_LSA)) {
154 assert("Unable to unregister Router Info functions: Wrong scope!"
155 == NULL);
156 return -1;
157 }
158
159 ospf_delete_opaque_functab(OspfRI.scope,
160 OPAQUE_TYPE_ROUTER_INFORMATION_LSA);
161
162 OspfRI.registered = 0;
163 return 0;
164 }
165
166 void ospf_router_info_term(void)
167 {
168
169 list_delete(&OspfRI.pce_info.pce_domain);
170 list_delete(&OspfRI.pce_info.pce_neighbor);
171
172 OspfRI.enabled = false;
173
174 ospf_router_info_unregister();
175
176 return;
177 }
178
179 void ospf_router_info_finish(void)
180 {
181 list_delete_all_node(OspfRI.pce_info.pce_domain);
182 list_delete_all_node(OspfRI.pce_info.pce_neighbor);
183
184 OspfRI.enabled = false;
185 }
186
187 static void del_area_info(void *val)
188 {
189 XFREE(MTYPE_OSPF_ROUTER_INFO, val);
190 }
191
192 static void del_pce_info(void *val)
193 {
194 XFREE(MTYPE_OSPF_PCE_PARAMS, val);
195 }
196
197 /* Catch RI LSA flooding Scope for ospf_ext.[h,c] code */
198 struct scope_info ospf_router_info_get_flooding_scope(void)
199 {
200 struct scope_info flooding_scope;
201
202 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
203 flooding_scope.scope = OSPF_OPAQUE_AS_LSA;
204 flooding_scope.areas = NULL;
205 return flooding_scope;
206 }
207 flooding_scope.scope = OSPF_OPAQUE_AREA_LSA;
208 flooding_scope.areas = OspfRI.area_info;
209 return flooding_scope;
210 }
211
212 static struct ospf_ri_area_info *lookup_by_area(struct ospf_area *area)
213 {
214 struct listnode *node, *nnode;
215 struct ospf_ri_area_info *ai;
216
217 for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai))
218 if (ai->area == area)
219 return ai;
220
221 return NULL;
222 }
223
224 /*------------------------------------------------------------------------*
225 * Followings are control functions for ROUTER INFORMATION parameters
226 *management.
227 *------------------------------------------------------------------------*/
228
229 static void set_router_info_capabilities(struct ri_tlv_router_cap *ric,
230 uint32_t cap)
231 {
232 ric->header.type = htons(RI_TLV_CAPABILITIES);
233 ric->header.length = htons(RI_TLV_LENGTH);
234 ric->value = htonl(cap);
235 return;
236 }
237
238 static int set_pce_header(struct ospf_pce_info *pce)
239 {
240 uint16_t length = 0;
241 struct listnode *node;
242 struct ri_pce_subtlv_domain *domain;
243 struct ri_pce_subtlv_neighbor *neighbor;
244
245 /* PCE Address */
246 if (ntohs(pce->pce_address.header.type) != 0)
247 length += TLV_SIZE(&pce->pce_address.header);
248
249 /* PCE Path Scope */
250 if (ntohs(pce->pce_scope.header.type) != 0)
251 length += TLV_SIZE(&pce->pce_scope.header);
252
253 /* PCE Domain */
254 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
255 if (ntohs(domain->header.type) != 0)
256 length += TLV_SIZE(&domain->header);
257 }
258
259 /* PCE Neighbor */
260 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
261 if (ntohs(neighbor->header.type) != 0)
262 length += TLV_SIZE(&neighbor->header);
263 }
264
265 /* PCE Capabilities */
266 if (ntohs(pce->pce_cap_flag.header.type) != 0)
267 length += TLV_SIZE(&pce->pce_cap_flag.header);
268
269 if (length != 0) {
270 pce->pce_header.header.type = htons(RI_TLV_PCE);
271 pce->pce_header.header.length = htons(length);
272 pce->enabled = true;
273 } else {
274 pce->pce_header.header.type = 0;
275 pce->pce_header.header.length = 0;
276 pce->enabled = false;
277 }
278
279 return length;
280 }
281
282 static void set_pce_address(struct in_addr ipv4, struct ospf_pce_info *pce)
283 {
284
285 /* Enable PCE Info */
286 pce->pce_header.header.type = htons(RI_TLV_PCE);
287 /* Set PCE Address */
288 pce->pce_address.header.type = htons(RI_PCE_SUBTLV_ADDRESS);
289 pce->pce_address.header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
290 pce->pce_address.address.type = htons(PCE_ADDRESS_TYPE_IPV4);
291 pce->pce_address.address.value = ipv4;
292
293 return;
294 }
295
296 static void set_pce_path_scope(uint32_t scope, struct ospf_pce_info *pce)
297 {
298
299 /* Set PCE Scope */
300 pce->pce_scope.header.type = htons(RI_PCE_SUBTLV_PATH_SCOPE);
301 pce->pce_scope.header.length = htons(RI_TLV_LENGTH);
302 pce->pce_scope.value = htonl(scope);
303
304 return;
305 }
306
307 static void set_pce_domain(uint16_t type, uint32_t domain,
308 struct ospf_pce_info *pce)
309 {
310
311 struct ri_pce_subtlv_domain *new;
312
313 /* Create new domain info */
314 new = XCALLOC(MTYPE_OSPF_PCE_PARAMS,
315 sizeof(struct ri_pce_subtlv_domain));
316
317 new->header.type = htons(RI_PCE_SUBTLV_DOMAIN);
318 new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
319 new->type = htons(type);
320 new->value = htonl(domain);
321
322 /* Add new domain to the list */
323 listnode_add(pce->pce_domain, new);
324
325 return;
326 }
327
328 static void unset_pce_domain(uint16_t type, uint32_t domain,
329 struct ospf_pce_info *pce)
330 {
331 struct listnode *node;
332 struct ri_pce_subtlv_domain *old = NULL;
333 int found = 0;
334
335 /* Search the corresponding node */
336 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, old)) {
337 if ((old->type == htons(type))
338 && (old->value == htonl(domain))) {
339 found = 1;
340 break;
341 }
342 }
343
344 /* if found remove it */
345 if (found) {
346 listnode_delete(pce->pce_domain, old);
347
348 /* Finally free the old domain */
349 XFREE(MTYPE_OSPF_PCE_PARAMS, old);
350 }
351 }
352
353 static void set_pce_neighbor(uint16_t type, uint32_t domain,
354 struct ospf_pce_info *pce)
355 {
356
357 struct ri_pce_subtlv_neighbor *new;
358
359 /* Create new neighbor info */
360 new = XCALLOC(MTYPE_OSPF_PCE_PARAMS,
361 sizeof(struct ri_pce_subtlv_neighbor));
362
363 new->header.type = htons(RI_PCE_SUBTLV_NEIGHBOR);
364 new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
365 new->type = htons(type);
366 new->value = htonl(domain);
367
368 /* Add new domain to the list */
369 listnode_add(pce->pce_neighbor, new);
370
371 return;
372 }
373
374 static void unset_pce_neighbor(uint16_t type, uint32_t domain,
375 struct ospf_pce_info *pce)
376 {
377 struct listnode *node;
378 struct ri_pce_subtlv_neighbor *old = NULL;
379 int found = 0;
380
381 /* Search the corresponding node */
382 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, old)) {
383 if ((old->type == htons(type))
384 && (old->value == htonl(domain))) {
385 found = 1;
386 break;
387 }
388 }
389
390 /* if found remove it */
391 if (found) {
392 listnode_delete(pce->pce_neighbor, old);
393
394 /* Finally free the old domain */
395 XFREE(MTYPE_OSPF_PCE_PARAMS, old);
396 }
397 }
398
399 static void set_pce_cap_flag(uint32_t cap, struct ospf_pce_info *pce)
400 {
401
402 /* Set PCE Capabilities flag */
403 pce->pce_cap_flag.header.type = htons(RI_PCE_SUBTLV_CAP_FLAG);
404 pce->pce_cap_flag.header.length = htons(RI_TLV_LENGTH);
405 pce->pce_cap_flag.value = htonl(cap);
406
407 return;
408 }
409
410 /* Segment Routing TLV setter */
411
412 /* Algorithm SubTLV - section 3.1 */
413 static void set_sr_algorithm(uint8_t algo)
414 {
415
416 OspfRI.sr_info.algo.value[0] = algo;
417 for (int i = 1; i < ALGORITHM_COUNT; i++)
418 OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET;
419
420 /* Set TLV type and length == only 1 Algorithm */
421 TLV_TYPE(OspfRI.sr_info.algo) = htons(RI_SR_TLV_SR_ALGORITHM);
422 TLV_LEN(OspfRI.sr_info.algo) = htons(sizeof(uint8_t));
423 }
424
425 /* unset Aglogithm SubTLV */
426 static void unset_sr_algorithm(uint8_t algo)
427 {
428
429 for (int i = 0; i < ALGORITHM_COUNT; i++)
430 OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET;
431
432 /* Unset TLV type and length */
433 TLV_TYPE(OspfRI.sr_info.algo) = htons(0);
434 TLV_LEN(OspfRI.sr_info.algo) = htons(0);
435 }
436
437 /* Segment Routing Global Block SubTLV - section 3.2 */
438 static void set_sr_sid_label_range(struct sr_srgb srgb)
439 {
440 /* Set Header */
441 TLV_TYPE(OspfRI.sr_info.range) = htons(RI_SR_TLV_SID_LABEL_RANGE);
442 TLV_LEN(OspfRI.sr_info.range) =
443 htons(SUBTLV_SID_LABEL_SIZE + sizeof(uint32_t));
444 /* Set Range Size */
445 OspfRI.sr_info.range.size = htonl(SET_RANGE_SIZE(srgb.range_size));
446 /* Set Lower bound label SubTLV */
447 TLV_TYPE(OspfRI.sr_info.range.lower) = htons(SUBTLV_SID_LABEL);
448 TLV_LEN(OspfRI.sr_info.range.lower) = htons(SID_RANGE_LABEL_LENGTH);
449 OspfRI.sr_info.range.lower.value = htonl(SET_LABEL(srgb.lower_bound));
450 }
451
452 /* Unset this SRGB SubTLV */
453 static void unset_sr_sid_label_range(void)
454 {
455
456 TLV_TYPE(OspfRI.sr_info.range) = htons(0);
457 TLV_LEN(OspfRI.sr_info.range) = htons(0);
458 TLV_TYPE(OspfRI.sr_info.range.lower) = htons(0);
459 TLV_LEN(OspfRI.sr_info.range.lower) = htons(0);
460 }
461
462 /* Set Maximum Stack Depth for this router */
463 static void set_sr_node_msd(uint8_t msd)
464 {
465 TLV_TYPE(OspfRI.sr_info.msd) = htons(RI_SR_TLV_NODE_MSD);
466 TLV_LEN(OspfRI.sr_info.msd) = htons(sizeof(uint32_t));
467 OspfRI.sr_info.msd.value = msd;
468 }
469
470 /* Unset this router MSD */
471 static void unset_sr_node_msd(void)
472 {
473 TLV_TYPE(OspfRI.sr_info.msd) = htons(0);
474 TLV_LEN(OspfRI.sr_info.msd) = htons(0);
475 }
476
477 static void unset_param(void *tlv_buffer)
478 {
479 struct tlv_header *tlv = (struct tlv_header *)tlv_buffer;
480
481 tlv->type = 0;
482 /* Fill the Value to 0 */
483 memset(TLV_DATA(tlv_buffer), 0, TLV_BODY_SIZE(tlv));
484 tlv->length = 0;
485
486 return;
487 }
488
489 static void initialize_params(struct ospf_router_info *ori)
490 {
491 uint32_t cap = 0;
492 struct ospf *top;
493 struct listnode *node, *nnode;
494 struct ospf_area *area;
495 struct ospf_ri_area_info *new;
496
497 /*
498 * Initialize default Router Information Capabilities.
499 */
500 cap = RI_TE_SUPPORT;
501
502 set_router_info_capabilities(&ori->router_cap, cap);
503
504 /* If Area address is not null and exist, retrieve corresponding
505 * structure */
506 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
507 zlog_info("RI (%s): Initialize Router Info for %s scope", __func__,
508 OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS");
509
510 /* Try to get available Area's context from ospf at this step.
511 * Do it latter if not available */
512 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
513 for (ALL_LIST_ELEMENTS(top->areas, node, nnode, area)) {
514 zlog_debug("RI (%s): Add area %s to Router Information",
515 __func__, inet_ntoa(area->area_id));
516 new = XCALLOC(MTYPE_OSPF_ROUTER_INFO,
517 sizeof(struct ospf_ri_area_info));
518 new->area = area;
519 new->flags = RIFLG_LSA_INACTIVE;
520 listnode_add(OspfRI.area_info, new);
521 }
522 }
523
524 /*
525 * Initialize default PCE Information values
526 */
527 /* PCE address == OSPF Router ID */
528 set_pce_address(top->router_id, &ori->pce_info);
529
530 /* PCE scope */
531 cap = 7; /* Set L, R and Rd bits to one = intra & inter-area path
532 computation */
533 set_pce_path_scope(cap, &ori->pce_info);
534
535 /* PCE Capabilities */
536 cap = PCE_CAP_BIDIRECTIONAL | PCE_CAP_DIVERSE_PATH | PCE_CAP_OBJECTIVES
537 | PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ;
538 set_pce_cap_flag(cap, &ori->pce_info);
539
540 return;
541 }
542
543 static int is_mandated_params_set(struct ospf_router_info ori)
544 {
545 int rc = 0;
546
547 if (ntohs(ori.router_cap.header.type) == 0)
548 return rc;
549
550 if ((ntohs(ori.pce_info.pce_header.header.type) == RI_TLV_PCE)
551 && (ntohs(ori.pce_info.pce_address.header.type) == 0)
552 && (ntohs(ori.pce_info.pce_cap_flag.header.type) == 0))
553 return rc;
554
555 if ((ori.sr_info.enabled) && (ntohs(TLV_TYPE(ori.sr_info.algo)) == 0)
556 && (ntohs(TLV_TYPE(ori.sr_info.range)) == 0))
557 return rc;
558
559 rc = 1;
560
561 return rc;
562 }
563
564 /*
565 * Used by Segment Routing to set new TLVs and Sub-TLVs values
566 *
567 * @param enable To activate or not Segment Routing router Information flooding
568 * @param size Size of Label Range i.e. SRGB size
569 * @param lower Lower bound of the Label Range i.e. SRGB first label
570 * @param msd Maximum label Stack Depth supported by the router
571 *
572 * @return none
573 */
574 void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
575 {
576 struct listnode *node, *nnode;
577 struct ospf_ri_area_info *ai;
578
579 /* First, check if Router Information is registered or not */
580 if (!OspfRI.registered)
581 ospf_router_info_register(OSPF_OPAQUE_AREA_LSA);
582
583 /* Verify that scope is AREA */
584 if (OspfRI.scope != OSPF_OPAQUE_AREA_LSA) {
585 zlog_err(
586 "RI (%s): Router Info is %s flooding: Change scope to Area flooding for Segment Routing",
587 __func__,
588 OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS");
589 return;
590 }
591
592 /* Then, activate and initialize Router Information if necessary */
593 if (!OspfRI.enabled) {
594 OspfRI.enabled = true;
595 initialize_params(&OspfRI);
596 }
597
598 if (IS_DEBUG_OSPF_SR)
599 zlog_debug("RI (%s): %s Routing Information for Segment Routing",
600 __func__, enable ? "Enable" : "Disable");
601
602 /* Unset or Set SR parameters */
603 if (!enable) {
604 unset_sr_algorithm(SR_ALGORITHM_SPF);
605 unset_sr_sid_label_range();
606 unset_sr_node_msd();
607 OspfRI.sr_info.enabled = false;
608 } else {
609 // Only SR_ALGORITHM_SPF is supported
610 set_sr_algorithm(SR_ALGORITHM_SPF);
611 set_sr_sid_label_range(srgb);
612 if (msd != 0)
613 set_sr_node_msd(msd);
614 else
615 unset_sr_node_msd();
616 OspfRI.sr_info.enabled = true;
617 }
618
619 /* Refresh if already engaged or originate RI LSA */
620 for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) {
621 if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED))
622 ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA);
623 else
624 ospf_router_info_lsa_schedule(ai,
625 REORIGINATE_THIS_LSA);
626
627 }
628 }
629
630 /*------------------------------------------------------------------------*
631 * Followings are callback functions against generic Opaque-LSAs handling.
632 *------------------------------------------------------------------------*/
633 static void ospf_router_info_ism_change(struct ospf_interface *oi,
634 int old_state)
635 {
636
637 struct ospf_ri_area_info *ai;
638
639 /* Collect area information */
640 ai = lookup_by_area(oi->area);
641
642 /* Check if area is not yet registered */
643 if (ai != NULL)
644 return;
645
646 /* Add this new area to the list */
647 ai = XCALLOC(MTYPE_OSPF_ROUTER_INFO, sizeof(struct ospf_ri_area_info));
648 ai->area = oi->area;
649 ai->flags = RIFLG_LSA_INACTIVE;
650 listnode_add(OspfRI.area_info, ai);
651
652 return;
653 }
654
655 /*------------------------------------------------------------------------*
656 * Followings are OSPF protocol processing functions for ROUTER INFORMATION
657 *------------------------------------------------------------------------*/
658
659 static void build_tlv_header(struct stream *s, struct tlv_header *tlvh)
660 {
661
662 stream_put(s, tlvh, sizeof(struct tlv_header));
663 return;
664 }
665
666 static void build_tlv(struct stream *s, struct tlv_header *tlvh)
667 {
668
669 if (ntohs(tlvh->type) != 0) {
670 build_tlv_header(s, tlvh);
671 stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
672 }
673 return;
674 }
675
676 static void ospf_router_info_lsa_body_set(struct stream *s)
677 {
678
679 struct listnode *node;
680 struct ri_pce_subtlv_domain *domain;
681 struct ri_pce_subtlv_neighbor *neighbor;
682
683 /* Build Router Information TLV */
684 build_tlv(s, &OspfRI.router_cap.header);
685
686 /* Build Segment Routing TLVs if enabled */
687 if (OspfRI.sr_info.enabled) {
688 /* Build Algorithm TLV */
689 build_tlv(s, &TLV_HDR(OspfRI.sr_info.algo));
690 /* Build SRGB TLV */
691 build_tlv(s, &TLV_HDR(OspfRI.sr_info.range));
692 /* Build MSD TLV */
693 build_tlv(s, &TLV_HDR(OspfRI.sr_info.msd));
694 }
695
696 /* Add RI PCE TLV if it is set */
697 if (OspfRI.pce_info.enabled) {
698
699 /* Compute PCE Info header first */
700 set_pce_header(&OspfRI.pce_info);
701
702 /* Build PCE TLV */
703 build_tlv_header(s, &OspfRI.pce_info.pce_header.header);
704
705 /* Build PCE address sub-tlv */
706 build_tlv(s, &OspfRI.pce_info.pce_address.header);
707
708 /* Build PCE path scope sub-tlv */
709 build_tlv(s, &OspfRI.pce_info.pce_scope.header);
710
711 /* Build PCE domain sub-tlv */
712 for (ALL_LIST_ELEMENTS_RO(OspfRI.pce_info.pce_domain, node,
713 domain))
714 build_tlv(s, &domain->header);
715
716 /* Build PCE neighbor sub-tlv */
717 for (ALL_LIST_ELEMENTS_RO(OspfRI.pce_info.pce_neighbor, node,
718 neighbor))
719 build_tlv(s, &neighbor->header);
720
721 /* Build PCE cap flag sub-tlv */
722 build_tlv(s, &OspfRI.pce_info.pce_cap_flag.header);
723 }
724
725 return;
726 }
727
728 /* Create new opaque-LSA. */
729 static struct ospf_lsa *ospf_router_info_lsa_new(struct ospf_area *area)
730 {
731 struct ospf *top;
732 struct stream *s;
733 struct lsa_header *lsah;
734 struct ospf_lsa *new = NULL;
735 uint8_t options, lsa_type;
736 struct in_addr lsa_id;
737 uint32_t tmp;
738 uint16_t length;
739
740 /* Create a stream for LSA. */
741 s = stream_new(OSPF_MAX_LSA_SIZE);
742
743 lsah = (struct lsa_header *)STREAM_DATA(s);
744
745 options = OSPF_OPTION_E; /* Enable AS external as we flood RI with
746 Opaque Type 11 */
747 options |= OSPF_OPTION_O; /* Don't forget this :-) */
748
749 lsa_type = OspfRI.scope;
750 /* LSA ID == 0 for Router Information see RFC 4970 */
751 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0);
752 lsa_id.s_addr = htonl(tmp);
753
754 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
755 zlog_debug(
756 "LSA[Type%d:%s]: Create an Opaque-LSA/ROUTER INFORMATION instance",
757 lsa_type, inet_ntoa(lsa_id));
758
759 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
760
761 /* Set opaque-LSA header fields. */
762 lsa_header_set(s, options, lsa_type, lsa_id, top->router_id);
763
764 /* Set opaque-LSA body fields. */
765 ospf_router_info_lsa_body_set(s);
766
767 /* Set length. */
768 length = stream_get_endp(s);
769 lsah->length = htons(length);
770
771 /* Now, create an OSPF LSA instance. */
772 new = ospf_lsa_new_and_data(length);
773
774 new->area = area;
775
776 if (new->area && new->area->ospf)
777 new->vrf_id = new->area->ospf->vrf_id;
778 else
779 new->vrf_id = VRF_DEFAULT;
780
781 SET_FLAG(new->flags, OSPF_LSA_SELF);
782 memcpy(new->data, lsah, length);
783 stream_free(s);
784
785 return new;
786 }
787
788 static int ospf_router_info_lsa_originate_as(void *arg)
789 {
790 struct ospf_lsa *new;
791 struct ospf *top;
792 int rc = -1;
793 vrf_id_t vrf_id = VRF_DEFAULT;
794
795 /* Sanity Check */
796 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
797 flog_warn(
798 EC_OSPF_LSA_INSTALL_FAILURE,
799 "RI (%s): wrong flooding scope AREA instead of AS ?",
800 __func__);
801 return rc;
802 }
803
804 /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
805 new = ospf_router_info_lsa_new(NULL);
806 new->vrf_id = VRF_DEFAULT;
807 top = (struct ospf *)arg;
808
809 /* Check ospf info */
810 if (top == NULL) {
811 zlog_debug("RI (%s): ospf instance not found for vrf id %u",
812 __func__, vrf_id);
813 ospf_lsa_unlock(&new);
814 return rc;
815 }
816
817 /* Install this LSA into LSDB. */
818 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
819 flog_warn(
820 EC_OSPF_LSA_INSTALL_FAILURE,
821 "RI (%s): ospf_lsa_install() ?", __func__);
822 ospf_lsa_unlock(&new);
823 return rc;
824 }
825
826 /* Update new LSA origination count. */
827 top->lsa_originate_count++;
828
829 /* Flood new LSA through AREA or AS. */
830 SET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED);
831 ospf_flood_through_as(top, NULL /*nbr */, new);
832
833 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
834 zlog_debug(
835 "LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION",
836 new->data->type, inet_ntoa(new->data->id));
837 ospf_lsa_header_dump(new->data);
838 }
839
840 rc = 0;
841 return rc;
842 }
843
844 static int ospf_router_info_lsa_originate_area(void *arg)
845 {
846 struct ospf_lsa *new;
847 struct ospf *top;
848 struct ospf_ri_area_info *ai = NULL;
849 int rc = -1;
850 vrf_id_t vrf_id = VRF_DEFAULT;
851
852 /* Sanity Check */
853 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
854 flog_warn(
855 EC_OSPF_LSA_INSTALL_FAILURE,
856 "RI (%s): wrong flooding scope AS instead of AREA ?",
857 __func__);
858 return rc;
859 }
860
861 /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
862 ai = lookup_by_area((struct ospf_area *)arg);
863 if (ai == NULL) {
864 zlog_debug(
865 "RI (%s): There is no context for this Router Information. Stop processing",
866 __func__);
867 return rc;
868 }
869 if (ai->area->ospf) {
870 vrf_id = ai->area->ospf->vrf_id;
871 top = ai->area->ospf;
872 } else {
873 top = ospf_lookup_by_vrf_id(vrf_id);
874 }
875 new = ospf_router_info_lsa_new(ai->area);
876 new->vrf_id = vrf_id;
877
878 /* Check ospf info */
879 if (top == NULL) {
880 zlog_debug("RI (%s): ospf instance not found for vrf id %u",
881 __func__, vrf_id);
882 ospf_lsa_unlock(&new);
883 return rc;
884 }
885
886 /* Install this LSA into LSDB. */
887 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
888 flog_warn(
889 EC_OSPF_LSA_INSTALL_FAILURE,
890 "RI (%s): ospf_lsa_install() ?", __func__);
891 ospf_lsa_unlock(&new);
892 return rc;
893 }
894
895 /* Update new LSA origination count. */
896 top->lsa_originate_count++;
897
898 /* Flood new LSA through AREA or AS. */
899 SET_FLAG(ai->flags, RIFLG_LSA_ENGAGED);
900 ospf_flood_through_area(ai->area, NULL /*nbr */, new);
901
902 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
903 zlog_debug(
904 "LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION",
905 new->data->type, inet_ntoa(new->data->id));
906 ospf_lsa_header_dump(new->data);
907 }
908
909 rc = 0;
910 return rc;
911 }
912
913 static int ospf_router_info_lsa_originate(void *arg)
914 {
915
916 struct ospf_ri_area_info *ai;
917 int rc = -1;
918
919 if (!OspfRI.enabled) {
920 zlog_info("RI (%s): ROUTER INFORMATION is disabled now.",
921 __func__);
922 rc = 0; /* This is not an error case. */
923 return rc;
924 }
925
926 /* Check if Router Information LSA is already engaged */
927 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
928 if ((CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED))
929 && (CHECK_FLAG(OspfRI.as_flags,
930 RIFLG_LSA_FORCED_REFRESH))) {
931 UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_FORCED_REFRESH);
932 ospf_router_info_lsa_schedule(NULL, REFRESH_THIS_LSA);
933 rc = 0;
934 return rc;
935 }
936 } else {
937 ai = lookup_by_area((struct ospf_area *)arg);
938 if (ai == NULL) {
939 flog_warn(
940 EC_OSPF_LSA,
941 "RI (%s): Missing area information", __func__);
942 return rc;
943 }
944 if ((CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED))
945 && (CHECK_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH))) {
946 UNSET_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH);
947 ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA);
948 rc = 0;
949 return rc;
950 }
951 }
952
953 /* Router Information is not yet Engaged, check parameters */
954 if (!is_mandated_params_set(OspfRI))
955 flog_warn(
956 EC_OSPF_LSA,
957 "RI (%s): lacks mandated ROUTER INFORMATION parameters",
958 __func__);
959
960 /* Ok, let's try to originate an LSA */
961 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
962 rc = ospf_router_info_lsa_originate_as(arg);
963 else
964 rc = ospf_router_info_lsa_originate_area(arg);
965
966 return rc;
967 }
968
969 static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
970 {
971 struct ospf_ri_area_info *ai = NULL;
972 struct ospf_lsa *new = NULL;
973 struct ospf *top;
974
975 if (!OspfRI.enabled) {
976 /*
977 * This LSA must have flushed before due to ROUTER INFORMATION
978 * status change.
979 * It seems a slip among routers in the routing domain.
980 */
981 zlog_info("RI (%s): ROUTER INFORMATION is disabled now.",
982 __func__);
983 lsa->data->ls_age =
984 htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */
985 }
986
987 /* Verify that the Router Information ID is supported */
988 if (GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)) != 0) {
989 flog_warn(
990 EC_OSPF_LSA,
991 "RI (%s): Unsupported Router Information ID",
992 __func__);
993 return NULL;
994 }
995
996 /* Process LSA depending of the flooding scope */
997 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
998 /* Get context AREA context */
999 ai = lookup_by_area(lsa->area);
1000 if (ai == NULL) {
1001 flog_warn(
1002 EC_OSPF_LSA,
1003 "RI (%s): No associated Area", __func__);
1004 return NULL;
1005 }
1006 /* Flush LSA, if the lsa's age reached to MaxAge. */
1007 if (IS_LSA_MAXAGE(lsa)) {
1008 UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED);
1009 ospf_opaque_lsa_flush_schedule(lsa);
1010 return NULL;
1011 }
1012 /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
1013 new = ospf_router_info_lsa_new(ai->area);
1014 new->data->ls_seqnum = lsa_seqnum_increment(lsa);
1015 new->vrf_id = lsa->vrf_id;
1016 /* Install this LSA into LSDB. */
1017 /* Given "lsa" will be freed in the next function. */
1018 top = ospf_lookup_by_vrf_id(lsa->vrf_id);
1019 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
1020 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
1021 "RI (%s): ospf_lsa_install() ?", __func__);
1022 ospf_lsa_unlock(&new);
1023 return new;
1024 }
1025 /* Flood updated LSA through AREA */
1026 ospf_flood_through_area(ai->area, NULL /*nbr */, new);
1027
1028 } else { /* AS Flooding scope */
1029 /* Flush LSA, if the lsa's age reached to MaxAge. */
1030 if (IS_LSA_MAXAGE(lsa)) {
1031 UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED);
1032 ospf_opaque_lsa_flush_schedule(lsa);
1033 return NULL;
1034 }
1035 /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
1036 new = ospf_router_info_lsa_new(NULL);
1037 new->data->ls_seqnum = lsa_seqnum_increment(lsa);
1038 new->vrf_id = lsa->vrf_id;
1039 /* Install this LSA into LSDB. */
1040 /* Given "lsa" will be freed in the next function. */
1041 top = ospf_lookup_by_vrf_id(lsa->vrf_id);
1042 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
1043 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
1044 "RI (%s): ospf_lsa_install() ?", __func__);
1045 ospf_lsa_unlock(&new);
1046 return new;
1047 }
1048 /* Flood updated LSA through AS */
1049 ospf_flood_through_as(top, NULL /*nbr */, new);
1050 }
1051
1052 /* Debug logging. */
1053 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
1054 zlog_debug(
1055 "LSA[Type%d:%s]: Refresh Opaque-LSA/ROUTER INFORMATION",
1056 new->data->type, inet_ntoa(new->data->id));
1057 ospf_lsa_header_dump(new->data);
1058 }
1059
1060 return new;
1061 }
1062
1063 static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai,
1064 enum lsa_opcode opcode)
1065 {
1066 struct ospf_lsa lsa;
1067 struct lsa_header lsah;
1068 struct ospf *top;
1069 uint32_t tmp;
1070
1071 memset(&lsa, 0, sizeof(lsa));
1072 memset(&lsah, 0, sizeof(lsah));
1073
1074 zlog_debug("RI (%s): LSA schedule %s%s%s", __func__,
1075 opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
1076 opcode == REFRESH_THIS_LSA ? "Refresh" : "",
1077 opcode == FLUSH_THIS_LSA ? "Flush" : "");
1078
1079 /* Check LSA flags state coherence and collect area information */
1080 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
1081 if ((ai == NULL) || (ai->area == NULL)) {
1082 flog_warn(
1083 EC_OSPF_LSA,
1084 "RI (%s): Router Info is Area scope flooding but area is not set",
1085 __func__);
1086 return;
1087 }
1088
1089 if (!CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)
1090 && (opcode != REORIGINATE_THIS_LSA))
1091 return;
1092
1093 if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)
1094 && (opcode == REORIGINATE_THIS_LSA))
1095 opcode = REFRESH_THIS_LSA;
1096
1097 lsa.area = ai->area;
1098 top = ai->area->ospf;
1099 } else {
1100 if (!CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)
1101 && (opcode != REORIGINATE_THIS_LSA))
1102 return;
1103
1104 if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)
1105 && (opcode == REORIGINATE_THIS_LSA))
1106 opcode = REFRESH_THIS_LSA;
1107
1108 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1109 lsa.area = NULL;
1110 }
1111
1112 lsa.data = &lsah;
1113 lsah.type = OspfRI.scope;
1114
1115 /* LSA ID is set to 0 for the Router Information. See RFC 4970 */
1116 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0);
1117 lsah.id.s_addr = htonl(tmp);
1118
1119 switch (opcode) {
1120 case REORIGINATE_THIS_LSA:
1121 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA)
1122 ospf_opaque_lsa_reoriginate_schedule(
1123 (void *)ai->area, OSPF_OPAQUE_AREA_LSA,
1124 OPAQUE_TYPE_ROUTER_INFORMATION_LSA);
1125 else
1126 ospf_opaque_lsa_reoriginate_schedule(
1127 (void *)top, OSPF_OPAQUE_AS_LSA,
1128 OPAQUE_TYPE_ROUTER_INFORMATION_LSA);
1129 break;
1130 case REFRESH_THIS_LSA:
1131 ospf_opaque_lsa_refresh_schedule(&lsa);
1132 break;
1133 case FLUSH_THIS_LSA:
1134 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA)
1135 UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED);
1136 else
1137 UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED);
1138 ospf_opaque_lsa_flush_schedule(&lsa);
1139 break;
1140 }
1141
1142 return;
1143 }
1144
1145 /* Callback to handle Segment Routing information */
1146 static int ospf_router_info_lsa_update(struct ospf_lsa *lsa)
1147 {
1148
1149 /* Sanity Check */
1150 if (lsa == NULL) {
1151 flog_warn(EC_OSPF_LSA, "RI (%s): Abort! LSA is NULL",
1152 __func__);
1153 return -1;
1154 }
1155
1156 /* Process only Opaque LSA */
1157 if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
1158 && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
1159 return 0;
1160
1161 /* Process only Router Information LSA */
1162 if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr))
1163 != OPAQUE_TYPE_ROUTER_INFORMATION_LSA)
1164 return 0;
1165
1166 /* Check if it is not my LSA */
1167 if (IS_LSA_SELF(lsa))
1168 return 0;
1169
1170 /* Check if Router Info & Segment Routing are enable */
1171 if (!OspfRI.enabled || !OspfRI.sr_info.enabled)
1172 return 0;
1173
1174 /* Call Segment Routing LSA update or deletion */
1175 if (!IS_LSA_MAXAGE(lsa))
1176 ospf_sr_ri_lsa_update(lsa);
1177 else
1178 ospf_sr_ri_lsa_delete(lsa);
1179
1180 return 0;
1181 }
1182
1183 /*------------------------------------------------------------------------*
1184 * Followings are vty session control functions.
1185 *------------------------------------------------------------------------*/
1186
1187 static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh)
1188 {
1189 struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh;
1190
1191 if (vty != NULL)
1192 vty_out(vty, " Router Capabilities: 0x%x\n",
1193 ntohl(top->value));
1194 else
1195 zlog_debug(" Router Capabilities: 0x%x", ntohl(top->value));
1196
1197 return TLV_SIZE(tlvh);
1198 }
1199
1200 static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
1201 struct tlv_header *tlvh)
1202 {
1203 struct ri_pce_subtlv_address *top =
1204 (struct ri_pce_subtlv_address *)tlvh;
1205
1206 if (ntohs(top->address.type) == PCE_ADDRESS_TYPE_IPV4) {
1207 if (vty != NULL)
1208 vty_out(vty, " PCE Address: %s\n",
1209 inet_ntoa(top->address.value));
1210 else
1211 zlog_debug(" PCE Address: %s",
1212 inet_ntoa(top->address.value));
1213 } else {
1214 /* TODO: Add support to IPv6 with inet_ntop() */
1215 if (vty != NULL)
1216 vty_out(vty, " PCE Address: 0x%x\n",
1217 ntohl(top->address.value.s_addr));
1218 else
1219 zlog_debug(" PCE Address: 0x%x",
1220 ntohl(top->address.value.s_addr));
1221 }
1222
1223 return TLV_SIZE(tlvh);
1224 }
1225
1226 static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
1227 struct tlv_header *tlvh)
1228 {
1229 struct ri_pce_subtlv_path_scope *top =
1230 (struct ri_pce_subtlv_path_scope *)tlvh;
1231
1232 if (vty != NULL)
1233 vty_out(vty, " PCE Path Scope: 0x%x\n", ntohl(top->value));
1234 else
1235 zlog_debug(" PCE Path Scope: 0x%x", ntohl(top->value));
1236
1237 return TLV_SIZE(tlvh);
1238 }
1239
1240 static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
1241 struct tlv_header *tlvh)
1242 {
1243 struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh;
1244 struct in_addr tmp;
1245
1246 if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
1247 tmp.s_addr = top->value;
1248 if (vty != NULL)
1249 vty_out(vty, " PCE domain Area: %s\n", inet_ntoa(tmp));
1250 else
1251 zlog_debug(" PCE domain Area: %s", inet_ntoa(tmp));
1252 } else {
1253 if (vty != NULL)
1254 vty_out(vty, " PCE domain AS: %d\n",
1255 ntohl(top->value));
1256 else
1257 zlog_debug(" PCE domain AS: %d", ntohl(top->value));
1258 }
1259 return TLV_SIZE(tlvh);
1260 }
1261
1262 static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
1263 struct tlv_header *tlvh)
1264 {
1265
1266 struct ri_pce_subtlv_neighbor *top =
1267 (struct ri_pce_subtlv_neighbor *)tlvh;
1268 struct in_addr tmp;
1269
1270 if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
1271 tmp.s_addr = top->value;
1272 if (vty != NULL)
1273 vty_out(vty, " PCE neighbor Area: %s\n",
1274 inet_ntoa(tmp));
1275 else
1276 zlog_debug(" PCE neighbor Area: %s", inet_ntoa(tmp));
1277 } else {
1278 if (vty != NULL)
1279 vty_out(vty, " PCE neighbor AS: %d\n",
1280 ntohl(top->value));
1281 else
1282 zlog_debug(" PCE neighbor AS: %d",
1283 ntohl(top->value));
1284 }
1285 return TLV_SIZE(tlvh);
1286 }
1287
1288 static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
1289 struct tlv_header *tlvh)
1290 {
1291 struct ri_pce_subtlv_cap_flag *top =
1292 (struct ri_pce_subtlv_cap_flag *)tlvh;
1293
1294 if (vty != NULL)
1295 vty_out(vty, " PCE Capabilities Flag: 0x%x\n",
1296 ntohl(top->value));
1297 else
1298 zlog_debug(" PCE Capabilities Flag: 0x%x",
1299 ntohl(top->value));
1300
1301 return TLV_SIZE(tlvh);
1302 }
1303
1304 static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
1305 {
1306 if (vty != NULL)
1307 vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
1308 ntohs(tlvh->type), ntohs(tlvh->length));
1309 else
1310 zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]",
1311 ntohs(tlvh->type), ntohs(tlvh->length));
1312
1313 return TLV_SIZE(tlvh);
1314 }
1315
1316 static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
1317 uint32_t total)
1318 {
1319 struct tlv_header *tlvh;
1320 uint16_t sum = 0;
1321
1322 for (tlvh = ri; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) {
1323 switch (ntohs(tlvh->type)) {
1324 case RI_PCE_SUBTLV_ADDRESS:
1325 sum += show_vty_pce_subtlv_address(vty, tlvh);
1326 break;
1327 case RI_PCE_SUBTLV_PATH_SCOPE:
1328 sum += show_vty_pce_subtlv_path_scope(vty, tlvh);
1329 break;
1330 case RI_PCE_SUBTLV_DOMAIN:
1331 sum += show_vty_pce_subtlv_domain(vty, tlvh);
1332 break;
1333 case RI_PCE_SUBTLV_NEIGHBOR:
1334 sum += show_vty_pce_subtlv_neighbor(vty, tlvh);
1335 break;
1336 case RI_PCE_SUBTLV_CAP_FLAG:
1337 sum += show_vty_pce_subtlv_cap_flag(vty, tlvh);
1338 break;
1339 default:
1340 sum += show_vty_unknown_tlv(vty, tlvh);
1341 break;
1342 }
1343 }
1344 return sum;
1345 }
1346
1347 /* Display Segment Routing Algorithm TLV information */
1348 static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
1349 {
1350 struct ri_sr_tlv_sr_algorithm *algo =
1351 (struct ri_sr_tlv_sr_algorithm *)tlvh;
1352 int i;
1353
1354 if (vty != NULL) {
1355 vty_out(vty, " Segment Routing Algorithm TLV:\n");
1356 for (i = 0; i < ntohs(algo->header.length); i++) {
1357 switch (algo->value[i]) {
1358 case 0:
1359 vty_out(vty, " Algorithm %d: SPF\n", i);
1360 break;
1361 case 1:
1362 vty_out(vty, " Algorithm %d: Strict SPF\n",
1363 i);
1364 break;
1365 default:
1366 vty_out(vty,
1367 " Algorithm %d: Unknown value %d\n", i,
1368 algo->value[i]);
1369 break;
1370 }
1371 }
1372 }
1373
1374 else {
1375 zlog_debug(" Segment Routing Algorithm TLV:\n");
1376 for (i = 0; i < ntohs(algo->header.length); i++)
1377 switch (algo->value[i]) {
1378 case 0:
1379 zlog_debug(" Algorithm %d: SPF\n", i);
1380 break;
1381 case 1:
1382 zlog_debug(" Algorithm %d: Strict SPF\n", i);
1383 break;
1384 default:
1385 zlog_debug(
1386 " Algorithm %d: Unknown value %d\n",
1387 i, algo->value[i]);
1388 break;
1389 }
1390 }
1391
1392 return TLV_SIZE(tlvh);
1393 }
1394
1395 /* Display Segment Routing SID/Label Range TLV information */
1396 static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
1397 {
1398 struct ri_sr_tlv_sid_label_range *range =
1399 (struct ri_sr_tlv_sid_label_range *)tlvh;
1400
1401 if (vty != NULL) {
1402 vty_out(vty,
1403 " Segment Routing Range TLV:\n"
1404 " Range Size = %d\n"
1405 " SID Label = %d\n\n",
1406 GET_RANGE_SIZE(ntohl(range->size)),
1407 GET_LABEL(ntohl(range->lower.value)));
1408 } else {
1409 zlog_debug(
1410 " Segment Routing Range TLV:\n"
1411 " Range Size = %d\n"
1412 " SID Label = %d\n\n",
1413 GET_RANGE_SIZE(ntohl(range->size)),
1414 GET_LABEL(ntohl(range->lower.value)));
1415 }
1416
1417 return TLV_SIZE(tlvh);
1418 }
1419
1420 /* Display Segment Routing Maximum Stack Depth TLV information */
1421 static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh)
1422 {
1423 struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh;
1424
1425 if (vty != NULL) {
1426 vty_out(vty,
1427 " Segment Routing MSD TLV:\n"
1428 " Node Maximum Stack Depth = %d\n",
1429 msd->value);
1430 } else {
1431 zlog_debug(
1432 " Segment Routing MSD TLV:\n"
1433 " Node Maximum Stack Depth = %d\n",
1434 msd->value);
1435 }
1436
1437 return TLV_SIZE(tlvh);
1438 }
1439
1440 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
1441 {
1442 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1443 struct tlv_header *tlvh;
1444 uint16_t length = 0, sum = 0;
1445
1446 /* Initialize TLV browsing */
1447 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
1448
1449 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
1450 tlvh = TLV_HDR_NEXT(tlvh)) {
1451 switch (ntohs(tlvh->type)) {
1452 case RI_TLV_CAPABILITIES:
1453 sum += show_vty_router_cap(vty, tlvh);
1454 break;
1455 case RI_TLV_PCE:
1456 tlvh++;
1457 sum += TLV_HDR_SIZE;
1458 sum += show_vty_pce_info(vty, tlvh, length - sum);
1459 break;
1460 case RI_SR_TLV_SR_ALGORITHM:
1461 sum += show_vty_sr_algorithm(vty, tlvh);
1462 break;
1463 case RI_SR_TLV_SID_LABEL_RANGE:
1464 sum += show_vty_sr_range(vty, tlvh);
1465 break;
1466 case RI_SR_TLV_NODE_MSD:
1467 sum += show_vty_sr_msd(vty, tlvh);
1468 break;
1469
1470 default:
1471 sum += show_vty_unknown_tlv(vty, tlvh);
1472 break;
1473 }
1474 }
1475
1476 return;
1477 }
1478
1479 static void ospf_router_info_config_write_router(struct vty *vty)
1480 {
1481 struct ospf_pce_info *pce = &OspfRI.pce_info;
1482 struct listnode *node;
1483 struct ri_pce_subtlv_domain *domain;
1484 struct ri_pce_subtlv_neighbor *neighbor;
1485 struct in_addr tmp;
1486
1487 if (!OspfRI.enabled)
1488 return;
1489
1490 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
1491 vty_out(vty, " router-info as\n");
1492 else
1493 vty_out(vty, " router-info area\n");
1494
1495 if (OspfRI.pce_info.enabled) {
1496
1497 if (pce->pce_address.header.type != 0)
1498 vty_out(vty, " pce address %s\n",
1499 inet_ntoa(pce->pce_address.address.value));
1500
1501 if (pce->pce_cap_flag.header.type != 0)
1502 vty_out(vty, " pce flag 0x%x\n",
1503 ntohl(pce->pce_cap_flag.value));
1504
1505 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
1506 if (domain->header.type != 0) {
1507 if (domain->type == PCE_DOMAIN_TYPE_AREA) {
1508 tmp.s_addr = domain->value;
1509 vty_out(vty, " pce domain area %s\n",
1510 inet_ntoa(tmp));
1511 } else {
1512 vty_out(vty, " pce domain as %d\n",
1513 ntohl(domain->value));
1514 }
1515 }
1516 }
1517
1518 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
1519 if (neighbor->header.type != 0) {
1520 if (neighbor->type == PCE_DOMAIN_TYPE_AREA) {
1521 tmp.s_addr = neighbor->value;
1522 vty_out(vty, " pce neighbor area %s\n",
1523 inet_ntoa(tmp));
1524 } else {
1525 vty_out(vty, " pce neighbor as %d\n",
1526 ntohl(neighbor->value));
1527 }
1528 }
1529 }
1530
1531 if (pce->pce_scope.header.type != 0)
1532 vty_out(vty, " pce scope 0x%x\n",
1533 ntohl(OspfRI.pce_info.pce_scope.value));
1534 }
1535 return;
1536 }
1537
1538 /*------------------------------------------------------------------------*
1539 * Followings are vty command functions.
1540 *------------------------------------------------------------------------*/
1541 /* Simple wrapper schedule RI LSA action in function of the scope */
1542 static void ospf_router_info_schedule(enum lsa_opcode opcode)
1543 {
1544 struct listnode *node, *nnode;
1545 struct ospf_ri_area_info *ai;
1546
1547 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
1548 if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED))
1549 ospf_router_info_lsa_schedule(NULL, opcode);
1550 else if (opcode == REORIGINATE_THIS_LSA)
1551 ospf_router_info_lsa_schedule(NULL, opcode);
1552 } else {
1553 for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) {
1554 if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED))
1555 ospf_router_info_lsa_schedule(ai, opcode);
1556 }
1557 }
1558 }
1559
1560 DEFUN (router_info,
1561 router_info_area_cmd,
1562 "router-info <as|area [A.B.C.D]>",
1563 OSPF_RI_STR
1564 "Enable the Router Information functionality with AS flooding scope\n"
1565 "Enable the Router Information functionality with Area flooding scope\n"
1566 "OSPF area ID in IP format (deprecated)\n")
1567 {
1568 int idx_mode = 1;
1569 uint8_t scope;
1570
1571 if (OspfRI.enabled)
1572 return CMD_SUCCESS;
1573
1574 /* Check and get Area value if present */
1575 if (strncmp(argv[idx_mode]->arg, "as", 2) == 0)
1576 scope = OSPF_OPAQUE_AS_LSA;
1577 else
1578 scope = OSPF_OPAQUE_AREA_LSA;
1579
1580 /* First start to register Router Information callbacks */
1581 if (!OspfRI.registered && (ospf_router_info_register(scope)) != 0) {
1582 vty_out(vty,
1583 "%% Unable to register Router Information callbacks.");
1584 flog_err(
1585 EC_OSPF_INIT_FAIL,
1586 "RI (%s): Unable to register Router Information callbacks. Abort!",
1587 __func__);
1588 return CMD_WARNING_CONFIG_FAILED;
1589 }
1590
1591 OspfRI.enabled = true;
1592
1593 if (IS_DEBUG_OSPF_EVENT)
1594 zlog_debug("RI-> Router Information (%s flooding): OFF -> ON",
1595 OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area"
1596 : "AS");
1597
1598 /*
1599 * Following code is intended to handle two cases;
1600 *
1601 * 1) Router Information was disabled at startup time, but now become
1602 * enabled.
1603 * 2) Router Information was once enabled then disabled, and now enabled
1604 * again.
1605 */
1606
1607 initialize_params(&OspfRI);
1608
1609 /* Originate or Refresh RI LSA if already engaged */
1610 ospf_router_info_schedule(REORIGINATE_THIS_LSA);
1611 return CMD_SUCCESS;
1612 }
1613
1614
1615 DEFUN (no_router_info,
1616 no_router_info_cmd,
1617 "no router-info",
1618 NO_STR
1619 "Disable the Router Information functionality\n")
1620 {
1621
1622 if (!OspfRI.enabled)
1623 return CMD_SUCCESS;
1624
1625 if (IS_DEBUG_OSPF_EVENT)
1626 zlog_debug("RI-> Router Information: ON -> OFF");
1627
1628 ospf_router_info_schedule(FLUSH_THIS_LSA);
1629
1630 OspfRI.enabled = false;
1631
1632 return CMD_SUCCESS;
1633 }
1634
1635 static int ospf_ri_enabled(struct vty *vty)
1636 {
1637 if (OspfRI.enabled)
1638 return 1;
1639
1640 if (vty)
1641 vty_out(vty, "%% OSPF RI is not turned on\n");
1642
1643 return 0;
1644 }
1645
1646 DEFUN (pce_address,
1647 pce_address_cmd,
1648 "pce address A.B.C.D",
1649 PCE_STR
1650 "Stable IP address of the PCE\n"
1651 "PCE address in IPv4 address format\n")
1652 {
1653 int idx_ipv4 = 2;
1654 struct in_addr value;
1655 struct ospf_pce_info *pi = &OspfRI.pce_info;
1656
1657 if (!ospf_ri_enabled(vty))
1658 return CMD_WARNING_CONFIG_FAILED;
1659
1660 if (!inet_aton(argv[idx_ipv4]->arg, &value)) {
1661 vty_out(vty, "Please specify PCE Address by A.B.C.D\n");
1662 return CMD_WARNING_CONFIG_FAILED;
1663 }
1664
1665 if (ntohs(pi->pce_address.header.type) == 0
1666 || ntohl(pi->pce_address.address.value.s_addr)
1667 != ntohl(value.s_addr)) {
1668
1669 set_pce_address(value, pi);
1670
1671 /* Refresh RI LSA if already engaged */
1672 ospf_router_info_schedule(REFRESH_THIS_LSA);
1673 }
1674
1675 return CMD_SUCCESS;
1676 }
1677
1678 DEFUN (no_pce_address,
1679 no_pce_address_cmd,
1680 "no pce address [A.B.C.D]",
1681 NO_STR
1682 PCE_STR
1683 "Disable PCE address\n"
1684 "PCE address in IPv4 address format\n")
1685 {
1686
1687 unset_param(&OspfRI.pce_info.pce_address);
1688
1689 /* Refresh RI LSA if already engaged */
1690 ospf_router_info_schedule(REFRESH_THIS_LSA);
1691
1692 return CMD_SUCCESS;
1693 }
1694
1695 DEFUN (pce_path_scope,
1696 pce_path_scope_cmd,
1697 "pce scope BITPATTERN",
1698 PCE_STR
1699 "Path scope visibilities of the PCE for path computation\n"
1700 "32-bit Hexadecimal value\n")
1701 {
1702 int idx_bitpattern = 2;
1703 uint32_t scope;
1704 struct ospf_pce_info *pi = &OspfRI.pce_info;
1705
1706 if (!ospf_ri_enabled(vty))
1707 return CMD_WARNING_CONFIG_FAILED;
1708
1709 if (sscanf(argv[idx_bitpattern]->arg, "0x%x", &scope) != 1) {
1710 vty_out(vty, "pce_path_scope: fscanf: %s\n",
1711 safe_strerror(errno));
1712 return CMD_WARNING_CONFIG_FAILED;
1713 }
1714
1715 if (ntohl(pi->pce_scope.header.type) == 0
1716 || scope != pi->pce_scope.value) {
1717 set_pce_path_scope(scope, pi);
1718
1719 /* Refresh RI LSA if already engaged */
1720 ospf_router_info_schedule(REFRESH_THIS_LSA);
1721 }
1722
1723 return CMD_SUCCESS;
1724 }
1725
1726 DEFUN (no_pce_path_scope,
1727 no_pce_path_scope_cmd,
1728 "no pce scope [BITPATTERN]",
1729 NO_STR
1730 PCE_STR
1731 "Disable PCE path scope\n"
1732 "32-bit Hexadecimal value\n")
1733 {
1734
1735 unset_param(&OspfRI.pce_info.pce_address);
1736
1737 /* Refresh RI LSA if already engaged */
1738 ospf_router_info_schedule(REFRESH_THIS_LSA);
1739
1740 return CMD_SUCCESS;
1741 }
1742
1743 DEFUN (pce_domain,
1744 pce_domain_cmd,
1745 "pce domain as (0-65535)",
1746 PCE_STR
1747 "Configure PCE domain AS number\n"
1748 "AS number where the PCE as visibilities for path computation\n"
1749 "AS number in decimal <0-65535>\n")
1750 {
1751 int idx_number = 3;
1752
1753 uint32_t as;
1754 struct ospf_pce_info *pce = &OspfRI.pce_info;
1755 struct listnode *node;
1756 struct ri_pce_subtlv_domain *domain;
1757
1758 if (!ospf_ri_enabled(vty))
1759 return CMD_WARNING_CONFIG_FAILED;
1760
1761 if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
1762 vty_out(vty, "pce_domain: fscanf: %s\n", safe_strerror(errno));
1763 return CMD_WARNING_CONFIG_FAILED;
1764 }
1765
1766 /* Check if the domain is not already in the domain list */
1767 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
1768 if (ntohl(domain->header.type) == 0 && as == domain->value)
1769 return CMD_SUCCESS;
1770 }
1771
1772 /* Create new domain if not found */
1773 set_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
1774
1775 /* Refresh RI LSA if already engaged */
1776 ospf_router_info_schedule(REFRESH_THIS_LSA);
1777
1778 return CMD_SUCCESS;
1779 }
1780
1781 DEFUN (no_pce_domain,
1782 no_pce_domain_cmd,
1783 "no pce domain as (0-65535)",
1784 NO_STR
1785 PCE_STR
1786 "Disable PCE domain AS number\n"
1787 "AS number where the PCE as visibilities for path computation\n"
1788 "AS number in decimal <0-65535>\n")
1789 {
1790 int idx_number = 4;
1791
1792 uint32_t as;
1793 struct ospf_pce_info *pce = &OspfRI.pce_info;
1794
1795 if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
1796 vty_out(vty, "no_pce_domain: fscanf: %s\n",
1797 safe_strerror(errno));
1798 return CMD_WARNING_CONFIG_FAILED;
1799 }
1800
1801 /* Unset corresponding PCE domain */
1802 unset_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
1803
1804 /* Refresh RI LSA if already engaged */
1805 ospf_router_info_schedule(REFRESH_THIS_LSA);
1806
1807 return CMD_SUCCESS;
1808 }
1809
1810 DEFUN (pce_neigbhor,
1811 pce_neighbor_cmd,
1812 "pce neighbor as (0-65535)",
1813 PCE_STR
1814 "Configure PCE neighbor domain AS number\n"
1815 "AS number of PCE neighbors\n"
1816 "AS number in decimal <0-65535>\n")
1817 {
1818 int idx_number = 3;
1819
1820 uint32_t as;
1821 struct ospf_pce_info *pce = &OspfRI.pce_info;
1822 struct listnode *node;
1823 struct ri_pce_subtlv_neighbor *neighbor;
1824
1825 if (!ospf_ri_enabled(vty))
1826 return CMD_WARNING_CONFIG_FAILED;
1827
1828 if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
1829 vty_out(vty, "pce_neighbor: fscanf: %s\n",
1830 safe_strerror(errno));
1831 return CMD_WARNING_CONFIG_FAILED;
1832 }
1833
1834 /* Check if the domain is not already in the domain list */
1835 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
1836 if (ntohl(neighbor->header.type) == 0 && as == neighbor->value)
1837 return CMD_SUCCESS;
1838 }
1839
1840 /* Create new domain if not found */
1841 set_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
1842
1843 /* Refresh RI LSA if already engaged */
1844 ospf_router_info_schedule(REFRESH_THIS_LSA);
1845
1846 return CMD_SUCCESS;
1847 }
1848
1849 DEFUN (no_pce_neighbor,
1850 no_pce_neighbor_cmd,
1851 "no pce neighbor as (0-65535)",
1852 NO_STR
1853 PCE_STR
1854 "Disable PCE neighbor AS number\n"
1855 "AS number of PCE neighbor\n"
1856 "AS number in decimal <0-65535>\n")
1857 {
1858 int idx_number = 4;
1859
1860 uint32_t as;
1861 struct ospf_pce_info *pce = &OspfRI.pce_info;
1862
1863 if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) {
1864 vty_out(vty, "no_pce_neighbor: fscanf: %s\n",
1865 safe_strerror(errno));
1866 return CMD_WARNING_CONFIG_FAILED;
1867 }
1868
1869 /* Unset corresponding PCE domain */
1870 unset_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
1871
1872 /* Refresh RI LSA if already engaged */
1873 ospf_router_info_schedule(REFRESH_THIS_LSA);
1874
1875 return CMD_SUCCESS;
1876 }
1877
1878 DEFUN (pce_cap_flag,
1879 pce_cap_flag_cmd,
1880 "pce flag BITPATTERN",
1881 PCE_STR
1882 "Capabilities of the PCE for path computation\n"
1883 "32-bit Hexadecimal value\n")
1884 {
1885 int idx_bitpattern = 2;
1886
1887 uint32_t cap;
1888 struct ospf_pce_info *pce = &OspfRI.pce_info;
1889
1890 if (!ospf_ri_enabled(vty))
1891 return CMD_WARNING_CONFIG_FAILED;
1892
1893 if (sscanf(argv[idx_bitpattern]->arg, "0x%x", &cap) != 1) {
1894 vty_out(vty, "pce_cap_flag: fscanf: %s\n",
1895 safe_strerror(errno));
1896 return CMD_WARNING_CONFIG_FAILED;
1897 }
1898
1899 if (ntohl(pce->pce_cap_flag.header.type) == 0
1900 || cap != pce->pce_cap_flag.value) {
1901 set_pce_cap_flag(cap, pce);
1902
1903 /* Refresh RI LSA if already engaged */
1904 ospf_router_info_schedule(REFRESH_THIS_LSA);
1905 }
1906
1907 return CMD_SUCCESS;
1908 }
1909
1910 DEFUN (no_pce_cap_flag,
1911 no_pce_cap_flag_cmd,
1912 "no pce flag",
1913 NO_STR
1914 PCE_STR
1915 "Disable PCE capabilities\n")
1916 {
1917
1918 unset_param(&OspfRI.pce_info.pce_cap_flag);
1919
1920 /* Refresh RI LSA if already engaged */
1921 ospf_router_info_schedule(REFRESH_THIS_LSA);
1922
1923 return CMD_SUCCESS;
1924 }
1925
1926 DEFUN (show_ip_ospf_router_info,
1927 show_ip_ospf_router_info_cmd,
1928 "show ip ospf router-info",
1929 SHOW_STR
1930 IP_STR
1931 OSPF_STR
1932 "Router Information\n")
1933 {
1934
1935 if (OspfRI.enabled) {
1936 vty_out(vty, "--- Router Information parameters ---\n");
1937 show_vty_router_cap(vty, &OspfRI.router_cap.header);
1938 } else {
1939 if (vty != NULL)
1940 vty_out(vty,
1941 " Router Information is disabled on this router\n");
1942 }
1943 return CMD_SUCCESS;
1944 }
1945
1946 DEFUN (show_ip_opsf_router_info_pce,
1947 show_ip_ospf_router_info_pce_cmd,
1948 "show ip ospf router-info pce",
1949 SHOW_STR
1950 IP_STR
1951 OSPF_STR
1952 "Router Information\n"
1953 "PCE information\n")
1954 {
1955
1956 struct ospf_pce_info *pce = &OspfRI.pce_info;
1957 struct listnode *node;
1958 struct ri_pce_subtlv_domain *domain;
1959 struct ri_pce_subtlv_neighbor *neighbor;
1960
1961 if ((OspfRI.enabled) && (OspfRI.pce_info.enabled)) {
1962 vty_out(vty, "--- PCE parameters ---\n");
1963
1964 if (pce->pce_address.header.type != 0)
1965 show_vty_pce_subtlv_address(vty,
1966 &pce->pce_address.header);
1967
1968 if (pce->pce_scope.header.type != 0)
1969 show_vty_pce_subtlv_path_scope(vty,
1970 &pce->pce_scope.header);
1971
1972 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
1973 if (domain->header.type != 0)
1974 show_vty_pce_subtlv_domain(vty,
1975 &domain->header);
1976 }
1977
1978 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
1979 if (neighbor->header.type != 0)
1980 show_vty_pce_subtlv_neighbor(vty,
1981 &neighbor->header);
1982 }
1983
1984 if (pce->pce_cap_flag.header.type != 0)
1985 show_vty_pce_subtlv_cap_flag(vty,
1986 &pce->pce_cap_flag.header);
1987
1988 } else {
1989 vty_out(vty, " PCE info is disabled on this router\n");
1990 }
1991
1992 return CMD_SUCCESS;
1993 }
1994
1995 /* Install new CLI commands */
1996 static void ospf_router_info_register_vty(void)
1997 {
1998 install_element(VIEW_NODE, &show_ip_ospf_router_info_cmd);
1999 install_element(VIEW_NODE, &show_ip_ospf_router_info_pce_cmd);
2000
2001 install_element(OSPF_NODE, &router_info_area_cmd);
2002 install_element(OSPF_NODE, &no_router_info_cmd);
2003 install_element(OSPF_NODE, &pce_address_cmd);
2004 install_element(OSPF_NODE, &no_pce_address_cmd);
2005 install_element(OSPF_NODE, &pce_path_scope_cmd);
2006 install_element(OSPF_NODE, &no_pce_path_scope_cmd);
2007 install_element(OSPF_NODE, &pce_domain_cmd);
2008 install_element(OSPF_NODE, &no_pce_domain_cmd);
2009 install_element(OSPF_NODE, &pce_neighbor_cmd);
2010 install_element(OSPF_NODE, &no_pce_neighbor_cmd);
2011 install_element(OSPF_NODE, &pce_cap_flag_cmd);
2012 install_element(OSPF_NODE, &no_pce_cap_flag_cmd);
2013
2014 return;
2015 }