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