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