]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_ri.c
bgpd: Fix bgp_vty.h to conform to coding standard
[mirror_frr.git] / ospfd / ospf_ri.c
1 /*
2 * This is an implementation of RFC4970 Router Information
3 * with support of RFC5088 PCE Capabilites announcement
4 *
5 * Module name: Router Information
6 * Version: 0.99.22
7 * Created: 2012-02-01 by Olivier Dugeon
8 * Copyright (C) 2012 Orange Labs http://www.orange.com/
9 *
10 * This file is part of GNU Quagga.
11 *
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
15 * later version.
16 *
17 * GNU Quagga is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26
27 #include <zebra.h>
28 #include <math.h>
29
30 #include "linklist.h"
31 #include "prefix.h"
32 #include "if.h"
33 #include "table.h"
34 #include "memory.h"
35 #include "command.h"
36 #include "vty.h"
37 #include "stream.h"
38 #include "log.h"
39 #include "thread.h"
40 #include "hash.h"
41 #include "sockunion.h" /* for inet_aton() */
42
43 #include "ospfd/ospfd.h"
44 #include "ospfd/ospf_interface.h"
45 #include "ospfd/ospf_ism.h"
46 #include "ospfd/ospf_asbr.h"
47 #include "ospfd/ospf_lsa.h"
48 #include "ospfd/ospf_lsdb.h"
49 #include "ospfd/ospf_neighbor.h"
50 #include "ospfd/ospf_nsm.h"
51 #include "ospfd/ospf_flood.h"
52 #include "ospfd/ospf_packet.h"
53 #include "ospfd/ospf_spf.h"
54 #include "ospfd/ospf_dump.h"
55 #include "ospfd/ospf_route.h"
56 #include "ospfd/ospf_ase.h"
57 #include "ospfd/ospf_zebra.h"
58 #include "ospfd/ospf_ri.h"
59 #include "ospfd/ospf_te.h"
60
61 /* Store Router Information PCE TLV and SubTLV in network byte order. */
62 struct ospf_pce_info {
63 bool enabled;
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;
70 };
71
72 /* Following structure are internal use only. */
73 struct ospf_router_info {
74 bool enabled;
75
76 u_int8_t registered;
77 u_int8_t scope;
78
79 /* Flags to manage this router information. */
80 #define RIFLG_LSA_ENGAGED 0x1
81 #define RIFLG_LSA_FORCED_REFRESH 0x2
82 u_int32_t flags;
83
84 /* area pointer if flooding is Type 10 Null if flooding is AS scope */
85 struct ospf_area *area;
86 struct in_addr area_id;
87
88 /* Store Router Information Capabilities LSA */
89 struct ri_tlv_router_cap router_cap;
90
91 /* Store PCE capability LSA */
92 struct ospf_pce_info pce_info;
93 };
94
95 /*
96 * Global variable to manage Opaque-LSA/Router Information on this node.
97 * Note that all parameter values are stored in network byte order.
98 */
99 static struct ospf_router_info OspfRI;
100
101 /*------------------------------------------------------------------------------*
102 * Followings are initialize/terminate functions for Router Information
103 *handling.
104 *------------------------------------------------------------------------------*/
105
106 static void ospf_router_info_ism_change(struct ospf_interface *oi,
107 int old_status);
108 static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr,
109 int old_status);
110 static void ospf_router_info_config_write_router(struct vty *vty);
111 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa);
112 static int ospf_router_info_lsa_originate(void *arg);
113 static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa);
114 static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode);
115 static void ospf_router_info_register_vty(void);
116 static void del_pce_info(void *val);
117
118 int ospf_router_info_init(void)
119 {
120
121 memset(&OspfRI, 0, sizeof(struct ospf_router_info));
122 OspfRI.enabled = false;
123 OspfRI.registered = 0;
124 OspfRI.scope = OSPF_OPAQUE_AS_LSA;
125 OspfRI.flags = 0;
126
127 /* Initialize pce domain and neighbor list */
128 OspfRI.pce_info.enabled = false;
129 OspfRI.pce_info.pce_domain = list_new();
130 OspfRI.pce_info.pce_domain->del = del_pce_info;
131 OspfRI.pce_info.pce_neighbor = list_new();
132 OspfRI.pce_info.pce_neighbor->del = del_pce_info;
133
134 ospf_router_info_register_vty();
135
136 return 0;
137 }
138
139 static int ospf_router_info_register(u_int8_t scope)
140 {
141 int rc = 0;
142
143 if (OspfRI.registered)
144 return rc;
145
146 zlog_info("Register Router Information with scope %s(%d)",
147 scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope);
148 rc = ospf_register_opaque_functab(
149 scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA,
150 NULL, /* new interface */
151 NULL, /* del interface */
152 ospf_router_info_ism_change, ospf_router_info_nsm_change,
153 ospf_router_info_config_write_router,
154 NULL, /* Config. write interface */
155 NULL, /* Config. write debug */
156 ospf_router_info_show_info, ospf_router_info_lsa_originate,
157 ospf_router_info_lsa_refresh, NULL, /* new_lsa_hook */
158 NULL); /* del_lsa_hook */
159
160 if (rc != 0) {
161 zlog_warn(
162 "ospf_router_info_init: Failed to register functions");
163 return rc;
164 }
165
166 OspfRI.registered = 1;
167 OspfRI.scope = scope;
168 return rc;
169 }
170
171 static int ospf_router_info_unregister()
172 {
173
174 if ((OspfRI.scope != OSPF_OPAQUE_AS_LSA)
175 && (OspfRI.scope != OSPF_OPAQUE_AREA_LSA)) {
176 zlog_warn(
177 "Unable to unregister Router Info functions: Wrong scope!");
178 return -1;
179 }
180
181 ospf_delete_opaque_functab(OspfRI.scope,
182 OPAQUE_TYPE_ROUTER_INFORMATION_LSA);
183
184 OspfRI.registered = 0;
185 return 0;
186 }
187
188 void ospf_router_info_term(void)
189 {
190
191 list_delete_and_null(&OspfRI.pce_info.pce_domain);
192 list_delete_and_null(&OspfRI.pce_info.pce_neighbor);
193
194 OspfRI.enabled = false;
195
196 ospf_router_info_unregister();
197
198 return;
199 }
200
201 static void del_pce_info(void *val)
202 {
203 XFREE(MTYPE_OSPF_PCE_PARAMS, val);
204 return;
205 }
206
207 /*------------------------------------------------------------------------*
208 * Followings are control functions for ROUTER INFORMATION parameters
209 *management.
210 *------------------------------------------------------------------------*/
211
212 static void set_router_info_capabilities(struct ri_tlv_router_cap *ric,
213 u_int32_t cap)
214 {
215 ric->header.type = htons(RI_TLV_CAPABILITIES);
216 ric->header.length = htons(RI_TLV_LENGTH);
217 ric->value = htonl(cap);
218 return;
219 }
220
221 static int set_pce_header(struct ospf_pce_info *pce)
222 {
223 u_int16_t length = 0;
224 struct listnode *node;
225 struct ri_pce_subtlv_domain *domain;
226 struct ri_pce_subtlv_neighbor *neighbor;
227
228 /* PCE Address */
229 if (ntohs(pce->pce_address.header.type) != 0)
230 length += TLV_SIZE(&pce->pce_address.header);
231
232 /* PCE Path Scope */
233 if (ntohs(pce->pce_scope.header.type) != 0)
234 length += TLV_SIZE(&pce->pce_scope.header);
235
236 /* PCE Domain */
237 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
238 if (ntohs(domain->header.type) != 0)
239 length += TLV_SIZE(&domain->header);
240 }
241
242 /* PCE Neighbor */
243 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
244 if (ntohs(neighbor->header.type) != 0)
245 length += TLV_SIZE(&neighbor->header);
246 }
247
248 /* PCE Capabilities */
249 if (ntohs(pce->pce_cap_flag.header.type) != 0)
250 length += TLV_SIZE(&pce->pce_cap_flag.header);
251
252 if (length != 0) {
253 pce->pce_header.header.type = htons(RI_TLV_PCE);
254 pce->pce_header.header.length = htons(length);
255 pce->enabled = true;
256 } else {
257 pce->pce_header.header.type = 0;
258 pce->pce_header.header.length = 0;
259 pce->enabled = false;
260 }
261
262 return length;
263 }
264
265 static void set_pce_address(struct in_addr ipv4, struct ospf_pce_info *pce)
266 {
267
268 /* Enable PCE Info */
269 pce->pce_header.header.type = htons(RI_TLV_PCE);
270 /* Set PCE Address */
271 pce->pce_address.header.type = htons(RI_PCE_SUBTLV_ADDRESS);
272 pce->pce_address.header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
273 pce->pce_address.address.type = htons(PCE_ADDRESS_TYPE_IPV4);
274 pce->pce_address.address.value = ipv4;
275
276 return;
277 }
278
279 static void set_pce_path_scope(u_int32_t scope, struct ospf_pce_info *pce)
280 {
281
282 /* Set PCE Scope */
283 pce->pce_scope.header.type = htons(RI_PCE_SUBTLV_PATH_SCOPE);
284 pce->pce_scope.header.length = htons(RI_TLV_LENGTH);
285 pce->pce_scope.value = htonl(scope);
286
287 return;
288 }
289
290 static void set_pce_domain(u_int16_t type, u_int32_t domain,
291 struct ospf_pce_info *pce)
292 {
293
294 struct ri_pce_subtlv_domain *new;
295
296 /* Create new domain info */
297 new = XCALLOC(MTYPE_OSPF_PCE_PARAMS,
298 sizeof(struct ri_pce_subtlv_domain));
299
300 new->header.type = htons(RI_PCE_SUBTLV_DOMAIN);
301 new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
302 new->type = htons(type);
303 new->value = htonl(domain);
304
305 /* Add new domain to the list */
306 listnode_add(pce->pce_domain, new);
307
308 return;
309 }
310
311 static void unset_pce_domain(u_int16_t type, u_int32_t domain,
312 struct ospf_pce_info *pce)
313 {
314 struct listnode *node;
315 struct ri_pce_subtlv_domain *old = NULL;
316 int found = 0;
317
318 /* Search the corresponding node */
319 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, old)) {
320 if ((old->type == htons(type))
321 && (old->value == htonl(domain))) {
322 found = 1;
323 break;
324 }
325 }
326
327 /* if found remove it */
328 if (found) {
329 listnode_delete(pce->pce_domain, old);
330
331 /* Avoid misjudgement in the next lookup. */
332 if (listcount(pce->pce_domain) == 0)
333 pce->pce_domain->head = pce->pce_domain->tail = NULL;
334
335 /* Finally free the old domain */
336 XFREE(MTYPE_OSPF_PCE_PARAMS, old);
337 }
338 }
339
340 static void set_pce_neighbor(u_int16_t type, u_int32_t domain,
341 struct ospf_pce_info *pce)
342 {
343
344 struct ri_pce_subtlv_neighbor *new;
345
346 /* Create new neighbor info */
347 new = XCALLOC(MTYPE_OSPF_PCE_PARAMS,
348 sizeof(struct ri_pce_subtlv_neighbor));
349
350 new->header.type = htons(RI_PCE_SUBTLV_NEIGHBOR);
351 new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4);
352 new->type = htons(type);
353 new->value = htonl(domain);
354
355 /* Add new domain to the list */
356 listnode_add(pce->pce_neighbor, new);
357
358 return;
359 }
360
361 static void unset_pce_neighbor(u_int16_t type, u_int32_t domain,
362 struct ospf_pce_info *pce)
363 {
364 struct listnode *node;
365 struct ri_pce_subtlv_neighbor *old = NULL;
366 int found = 0;
367
368 /* Search the corresponding node */
369 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, 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_neighbor, old);
380
381 /* Avoid misjudgement in the next lookup. */
382 if (listcount(pce->pce_neighbor) == 0)
383 pce->pce_neighbor->head = pce->pce_neighbor->tail =
384 NULL;
385
386 /* Finally free the old domain */
387 XFREE(MTYPE_OSPF_PCE_PARAMS, old);
388 }
389 }
390
391 static void set_pce_cap_flag(u_int32_t cap, struct ospf_pce_info *pce)
392 {
393
394 /* Set PCE Capabilities flag */
395 pce->pce_cap_flag.header.type = htons(RI_PCE_SUBTLV_CAP_FLAG);
396 pce->pce_cap_flag.header.length = htons(RI_TLV_LENGTH);
397 pce->pce_cap_flag.value = htonl(cap);
398
399 return;
400 }
401
402
403 static void unset_param(struct tlv_header *tlv)
404 {
405
406 tlv->type = 0;
407 /* Fill the Value to 0 */
408 memset(TLV_DATA(tlv), 0, TLV_BODY_SIZE(tlv));
409 tlv->length = 0;
410
411 return;
412 }
413
414 static void initialize_params(struct ospf_router_info *ori)
415 {
416 u_int32_t cap = 0;
417 struct ospf *top;
418
419 /*
420 * Initialize default Router Information Capabilities.
421 */
422 cap = RI_TE_SUPPORT;
423
424 set_router_info_capabilities(&ori->router_cap, cap);
425
426 /* If Area address is not null and exist, retrieve corresponding
427 * structure */
428 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
429 zlog_info("RI-> Initialize Router Info for %s scope within area %s",
430 OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS",
431 inet_ntoa(OspfRI.area_id));
432
433 /* Try to get the Area context at this step. Do it latter if not
434 * available */
435 if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL))
436 OspfRI.area = ospf_area_lookup_by_area_id(top, OspfRI.area_id);
437
438 /*
439 * Initialize default PCE Information values
440 */
441 /* PCE address == OSPF Router ID */
442 set_pce_address(top->router_id, &ori->pce_info);
443
444 /* PCE scope */
445 cap = 7; /* Set L, R and Rd bits to one = intra & inter-area path
446 computation */
447 set_pce_path_scope(cap, &ori->pce_info);
448
449 /* PCE Capabilities */
450 cap = PCE_CAP_BIDIRECTIONAL | PCE_CAP_DIVERSE_PATH | PCE_CAP_OBJECTIVES
451 | PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ;
452 set_pce_cap_flag(cap, &ori->pce_info);
453
454 return;
455 }
456
457 static int is_mandated_params_set(struct ospf_router_info ori)
458 {
459 int rc = 0;
460
461 if (ntohs(ori.router_cap.header.type) == 0)
462 return rc;
463
464 if ((ntohs(ori.pce_info.pce_header.header.type) == RI_TLV_PCE)
465 && (ntohs(ori.pce_info.pce_address.header.type) == 0)
466 && (ntohs(ori.pce_info.pce_cap_flag.header.type) == 0))
467 return rc;
468
469 rc = 1;
470
471 return rc;
472 }
473
474 /*------------------------------------------------------------------------*
475 * Followings are callback functions against generic Opaque-LSAs handling.
476 *------------------------------------------------------------------------*/
477 static void ospf_router_info_ism_change(struct ospf_interface *oi,
478 int old_state)
479 {
480 /* So far, nothing to do here. */
481 return;
482 }
483
484 static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr,
485 int old_state)
486 {
487 /* So far, nothing to do here. */
488 return;
489 }
490
491 /*------------------------------------------------------------------------*
492 * Followings are OSPF protocol processing functions for ROUTER INFORMATION
493 *------------------------------------------------------------------------*/
494
495 static void build_tlv_header(struct stream *s, struct tlv_header *tlvh)
496 {
497
498 stream_put(s, tlvh, sizeof(struct tlv_header));
499 return;
500 }
501
502 static void build_tlv(struct stream *s, struct tlv_header *tlvh)
503 {
504
505 if (ntohs(tlvh->type) != 0) {
506 build_tlv_header(s, tlvh);
507 stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
508 }
509 return;
510 }
511
512 static void ospf_router_info_lsa_body_set(struct stream *s)
513 {
514
515 struct listnode *node;
516 struct ri_pce_subtlv_domain *domain;
517 struct ri_pce_subtlv_neighbor *neighbor;
518
519 /* Build Router Information TLV */
520 build_tlv(s, &OspfRI.router_cap.header);
521
522 /* Compute PCE Info header first */
523 set_pce_header (&OspfRI.pce_info);
524
525 /* Add RI PCE TLV if it is set */
526 if (OspfRI.pce_info.enabled) {
527
528 /* Build PCE TLV */
529 build_tlv_header(s, &OspfRI.pce_info.pce_header.header);
530
531 /* Build PCE address sub-tlv */
532 build_tlv(s, &OspfRI.pce_info.pce_address.header);
533
534 /* Build PCE path scope sub-tlv */
535 build_tlv(s, &OspfRI.pce_info.pce_scope.header);
536
537 /* Build PCE domain sub-tlv */
538 for (ALL_LIST_ELEMENTS_RO(OspfRI.pce_info.pce_domain, node,
539 domain))
540 build_tlv(s, &domain->header);
541
542 /* Build PCE neighbor sub-tlv */
543 for (ALL_LIST_ELEMENTS_RO(OspfRI.pce_info.pce_neighbor, node,
544 neighbor))
545 build_tlv(s, &neighbor->header);
546
547 /* Build PCE cap flag sub-tlv */
548 build_tlv(s, &OspfRI.pce_info.pce_cap_flag.header);
549 }
550
551 return;
552 }
553
554 /* Create new opaque-LSA. */
555 static struct ospf_lsa *ospf_router_info_lsa_new()
556 {
557 struct ospf *top;
558 struct stream *s;
559 struct lsa_header *lsah;
560 struct ospf_lsa *new = NULL;
561 u_char options, lsa_type;
562 struct in_addr lsa_id;
563 u_int32_t tmp;
564 u_int16_t length;
565
566 /* Create a stream for LSA. */
567 if ((s = stream_new(OSPF_MAX_LSA_SIZE)) == NULL) {
568 zlog_warn("ospf_router_info_lsa_new: stream_new() ?");
569 return NULL;
570 }
571 lsah = (struct lsa_header *)STREAM_DATA(s);
572
573 options = OSPF_OPTION_E; /* Enable AS external as we flood RI with
574 Opaque Type 11 */
575 options |= OSPF_OPTION_O; /* Don't forget this :-) */
576
577 lsa_type = OspfRI.scope;
578 /* LSA ID == 0 for Router Information see RFC 4970 */
579 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0);
580 lsa_id.s_addr = htonl(tmp);
581
582 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
583 zlog_debug(
584 "LSA[Type%d:%s]: Create an Opaque-LSA/ROUTER INFORMATION instance",
585 lsa_type, inet_ntoa(lsa_id));
586
587 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
588
589 /* Set opaque-LSA header fields. */
590 lsa_header_set(s, options, lsa_type, lsa_id, top->router_id);
591
592 /* Set opaque-LSA body fields. */
593 ospf_router_info_lsa_body_set(s);
594
595 /* Set length. */
596 length = stream_get_endp(s);
597 lsah->length = htons(length);
598
599 /* Now, create an OSPF LSA instance. */
600 if ((new = ospf_lsa_new()) == NULL) {
601 zlog_warn("ospf_router_info_lsa_new: ospf_lsa_new() ?");
602 stream_free(s);
603 return NULL;
604 }
605 if ((new->data = ospf_lsa_data_new(length)) == NULL) {
606 zlog_warn("ospf_router_info_lsa_new: ospf_lsa_data_new() ?");
607 ospf_lsa_unlock(&new);
608 new = NULL;
609 stream_free(s);
610 return new;
611 }
612
613 new->area = OspfRI.area; /* Area must be null if the Opaque type is AS
614 scope, fulfill otherwise */
615
616 if (new->area && new->area->ospf)
617 new->vrf_id = new->area->ospf->vrf_id;
618 else
619 new->vrf_id = VRF_DEFAULT;
620
621 SET_FLAG(new->flags, OSPF_LSA_SELF);
622 memcpy(new->data, lsah, length);
623 stream_free(s);
624
625 return new;
626 }
627
628 static int ospf_router_info_lsa_originate1(void *arg)
629 {
630 struct ospf_lsa *new;
631 struct ospf *top;
632 struct ospf_area *area;
633 int rc = -1;
634 vrf_id_t vrf_id = VRF_DEFAULT;
635
636 /* First check if the area is known if flooding scope is Area */
637 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
638 area = (struct ospf_area *)arg;
639 if (area->area_id.s_addr != OspfRI.area_id.s_addr) {
640 zlog_debug(
641 "RI -> This is not the Router Information Area. Stop processing");
642 return rc;
643 }
644 OspfRI.area = area;
645 if (area->ospf)
646 vrf_id = area->ospf->vrf_id;
647 }
648
649 /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
650 if ((new = ospf_router_info_lsa_new()) == NULL) {
651 zlog_warn(
652 "ospf_router_info_lsa_originate1: ospf_router_info_lsa_new() ?");
653 return rc;
654 }
655 new->vrf_id = vrf_id;
656
657 /* Get ospf info */
658 top = ospf_lookup_by_vrf_id(vrf_id);
659 if (top == NULL) {
660 zlog_debug("%s: ospf instance not found for vrf id %u",
661 __PRETTY_FUNCTION__, vrf_id);
662 ospf_lsa_unlock(&new);
663 return rc;
664 }
665
666 /* Install this LSA into LSDB. */
667 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
668 zlog_warn(
669 "ospf_router_info_lsa_originate1: ospf_lsa_install() ?");
670 ospf_lsa_unlock(&new);
671 return rc;
672 }
673
674 /* Now this Router Info parameter entry has associated LSA. */
675 SET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
676
677 /* Update new LSA origination count. */
678 top->lsa_originate_count++;
679
680 /* Flood new LSA through AS. */
681 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
682 ospf_flood_through_as(top, NULL /*nbr */, new);
683 else
684 ospf_flood_through_area(OspfRI.area, NULL /*nbr */, new);
685
686 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
687 zlog_debug(
688 "LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION",
689 new->data->type, inet_ntoa(new->data->id));
690 ospf_lsa_header_dump(new->data);
691 }
692
693 rc = 0;
694 return rc;
695 }
696
697 static int ospf_router_info_lsa_originate(void *arg)
698 {
699
700 int rc = -1;
701
702 if (!OspfRI.enabled) {
703 zlog_info(
704 "ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now.");
705 rc = 0; /* This is not an error case. */
706 return rc;
707 }
708
709 /* Check if Router Information LSA is already engaged */
710 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) {
711 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH)) {
712 UNSET_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH);
713 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
714 }
715 } else {
716 if (!is_mandated_params_set(OspfRI))
717 zlog_warn(
718 "ospf_router_info_lsa_originate: lacks mandated ROUTER INFORMATION parameters");
719
720 /* Ok, let's try to originate an LSA */
721 if (ospf_router_info_lsa_originate1(arg) != 0)
722 return rc;
723 }
724
725 rc = 0;
726 return rc;
727 }
728
729 static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
730 {
731 struct ospf_lsa *new = NULL;
732 struct ospf *top;
733
734 if (!OspfRI.enabled) {
735 /*
736 * This LSA must have flushed before due to ROUTER INFORMATION
737 * status change.
738 * It seems a slip among routers in the routing domain.
739 */
740 zlog_info(
741 "ospf_router_info_lsa_refresh: ROUTER INFORMATION is disabled now.");
742 lsa->data->ls_age =
743 htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */
744 }
745
746 /* Verify that the Router Information ID is supported */
747 if (GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)) != 0) {
748 zlog_warn(
749 "ospf_router_info_lsa_refresh: Unsupported Router Information ID");
750 return NULL;
751 }
752
753 /* If the lsa's age reached to MaxAge, start flushing procedure. */
754 if (IS_LSA_MAXAGE(lsa)) {
755 UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
756 ospf_opaque_lsa_flush_schedule(lsa);
757 return NULL;
758 }
759
760 /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
761 if ((new = ospf_router_info_lsa_new()) == NULL) {
762 zlog_warn(
763 "ospf_router_info_lsa_refresh: ospf_router_info_lsa_new() ?");
764 return NULL;
765 }
766 new->data->ls_seqnum = lsa_seqnum_increment(lsa);
767 new->vrf_id = lsa->vrf_id;
768
769 /* Install this LSA into LSDB. */
770 /* Given "lsa" will be freed in the next function. */
771 top = ospf_lookup_by_vrf_id(lsa->vrf_id);
772 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
773 zlog_warn("ospf_router_info_lsa_refresh: ospf_lsa_install() ?");
774 ospf_lsa_unlock(&new);
775 return new;
776 }
777
778 /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */
779 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
780 ospf_flood_through_as(top, NULL /*nbr */, new);
781 else
782 ospf_flood_through_area(OspfRI.area, NULL /*nbr */, new);
783
784 /* Debug logging. */
785 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
786 zlog_debug(
787 "LSA[Type%d:%s]: Refresh Opaque-LSA/ROUTER INFORMATION",
788 new->data->type, inet_ntoa(new->data->id));
789 ospf_lsa_header_dump(new->data);
790 }
791
792 return new;
793 }
794
795 static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode)
796 {
797 struct ospf_lsa lsa;
798 struct lsa_header lsah;
799 struct ospf *top;
800 u_int32_t tmp;
801
802 memset(&lsa, 0, sizeof(lsa));
803 memset(&lsah, 0, sizeof(lsah));
804
805 zlog_debug("RI-> LSA schedule %s%s%s",
806 opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
807 opcode == REFRESH_THIS_LSA ? "Refresh" : "",
808 opcode == FLUSH_THIS_LSA ? "Flush" : "");
809
810 /* Check LSA flags state coherence */
811 if (!CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) && (opcode != REORIGINATE_THIS_LSA))
812 return;
813
814 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) && (opcode == REORIGINATE_THIS_LSA))
815 opcode = REFRESH_THIS_LSA;
816
817 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
818 if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) {
819 zlog_warn(
820 "ospf_router_info_lsa_schedule(): Router Info is Area scope flooding but area is not set");
821 OspfRI.area = ospf_area_lookup_by_area_id(top, OspfRI.area_id);
822 }
823 lsa.area = OspfRI.area;
824 lsa.data = &lsah;
825 lsah.type = OspfRI.scope;
826
827 /* LSA ID is set to 0 for the Router Information. See RFC 4970 */
828 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0);
829 lsah.id.s_addr = htonl(tmp);
830
831 switch (opcode) {
832 case REORIGINATE_THIS_LSA:
833 if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA)
834 ospf_opaque_lsa_reoriginate_schedule(
835 (void *)OspfRI.area, OSPF_OPAQUE_AREA_LSA,
836 OPAQUE_TYPE_ROUTER_INFORMATION_LSA);
837 else
838 ospf_opaque_lsa_reoriginate_schedule(
839 (void *)top, OSPF_OPAQUE_AS_LSA,
840 OPAQUE_TYPE_ROUTER_INFORMATION_LSA);
841 break;
842 case REFRESH_THIS_LSA:
843 ospf_opaque_lsa_refresh_schedule(&lsa);
844 break;
845 case FLUSH_THIS_LSA:
846 UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
847 ospf_opaque_lsa_flush_schedule(&lsa);
848 break;
849 default:
850 zlog_warn("ospf_router_info_lsa_schedule: Unknown opcode (%u)",
851 opcode);
852 break;
853 }
854
855 return;
856 }
857
858 /*------------------------------------------------------------------------*
859 * Followings are vty session control functions.
860 *------------------------------------------------------------------------*/
861
862 static u_int16_t show_vty_router_cap(struct vty *vty,
863 struct tlv_header *tlvh)
864 {
865 struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh;
866
867 if (vty != NULL)
868 vty_out(vty, " Router Capabilities: 0x%x\n",
869 ntohl(top->value));
870 else
871 zlog_debug(" Router Capabilities: 0x%x", ntohl(top->value));
872
873 return TLV_SIZE(tlvh);
874 }
875
876 static u_int16_t show_vty_pce_subtlv_address(struct vty *vty,
877 struct tlv_header *tlvh)
878 {
879 struct ri_pce_subtlv_address *top =
880 (struct ri_pce_subtlv_address *)tlvh;
881
882 if (ntohs(top->address.type) == PCE_ADDRESS_TYPE_IPV4) {
883 if (vty != NULL)
884 vty_out(vty, " PCE Address: %s\n",
885 inet_ntoa(top->address.value));
886 else
887 zlog_debug(" PCE Address: %s",
888 inet_ntoa(top->address.value));
889 } else {
890 /* TODO: Add support to IPv6 with inet_ntop() */
891 if (vty != NULL)
892 vty_out(vty, " PCE Address: 0x%x\n",
893 ntohl(top->address.value.s_addr));
894 else
895 zlog_debug(" PCE Address: 0x%x",
896 ntohl(top->address.value.s_addr));
897 }
898
899 return TLV_SIZE(tlvh);
900 }
901
902 static u_int16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
903 struct tlv_header *tlvh)
904 {
905 struct ri_pce_subtlv_path_scope *top =
906 (struct ri_pce_subtlv_path_scope *)tlvh;
907
908 if (vty != NULL)
909 vty_out(vty, " PCE Path Scope: 0x%x\n", ntohl(top->value));
910 else
911 zlog_debug(" PCE Path Scope: 0x%x", ntohl(top->value));
912
913 return TLV_SIZE(tlvh);
914 }
915
916 static u_int16_t show_vty_pce_subtlv_domain(struct vty *vty,
917 struct tlv_header *tlvh)
918 {
919 struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh;
920 struct in_addr tmp;
921
922 if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
923 tmp.s_addr = top->value;
924 if (vty != NULL)
925 vty_out(vty, " PCE domain Area: %s\n", inet_ntoa(tmp));
926 else
927 zlog_debug(" PCE domain Area: %s", inet_ntoa(tmp));
928 } else {
929 if (vty != NULL)
930 vty_out(vty, " PCE domain AS: %d\n",
931 ntohl(top->value));
932 else
933 zlog_debug(" PCE domain AS: %d", ntohl(top->value));
934 }
935 return TLV_SIZE(tlvh);
936 }
937
938 static u_int16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
939 struct tlv_header *tlvh)
940 {
941
942 struct ri_pce_subtlv_neighbor *top =
943 (struct ri_pce_subtlv_neighbor *)tlvh;
944 struct in_addr tmp;
945
946 if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
947 tmp.s_addr = top->value;
948 if (vty != NULL)
949 vty_out(vty, " PCE neighbor Area: %s\n",
950 inet_ntoa(tmp));
951 else
952 zlog_debug(" PCE neighbor Area: %s", inet_ntoa(tmp));
953 } else {
954 if (vty != NULL)
955 vty_out(vty, " PCE neighbor AS: %d\n",
956 ntohl(top->value));
957 else
958 zlog_debug(" PCE neighbor AS: %d",
959 ntohl(top->value));
960 }
961 return TLV_SIZE(tlvh);
962 }
963
964 static u_int16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
965 struct tlv_header *tlvh)
966 {
967 struct ri_pce_subtlv_cap_flag *top =
968 (struct ri_pce_subtlv_cap_flag *)tlvh;
969
970 if (vty != NULL)
971 vty_out(vty, " PCE Capabilities Flag: 0x%x\n",
972 ntohl(top->value));
973 else
974 zlog_debug(" PCE Capabilities Flag: 0x%x",
975 ntohl(top->value));
976
977 return TLV_SIZE(tlvh);
978 }
979
980 static u_int16_t show_vty_unknown_tlv(struct vty *vty,
981 struct tlv_header *tlvh)
982 {
983 if (vty != NULL)
984 vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
985 ntohs(tlvh->type), ntohs(tlvh->length));
986 else
987 zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]",
988 ntohs(tlvh->type), ntohs(tlvh->length));
989
990 return TLV_SIZE(tlvh);
991 }
992
993 static u_int16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
994 uint32_t total)
995 {
996 struct tlv_header *tlvh;
997 u_int16_t sum = 0;
998
999 for (tlvh = ri; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) {
1000 switch (ntohs(tlvh->type)) {
1001 case RI_PCE_SUBTLV_ADDRESS:
1002 sum += show_vty_pce_subtlv_address(vty, tlvh);
1003 break;
1004 case RI_PCE_SUBTLV_PATH_SCOPE:
1005 sum += show_vty_pce_subtlv_path_scope(vty, tlvh);
1006 break;
1007 case RI_PCE_SUBTLV_DOMAIN:
1008 sum += show_vty_pce_subtlv_domain(vty, tlvh);
1009 break;
1010 case RI_PCE_SUBTLV_NEIGHBOR:
1011 sum += show_vty_pce_subtlv_neighbor(vty, tlvh);
1012 break;
1013 case RI_PCE_SUBTLV_CAP_FLAG:
1014 sum += show_vty_pce_subtlv_cap_flag(vty, tlvh);
1015 break;
1016 default:
1017 sum += show_vty_unknown_tlv(vty, tlvh);
1018 break;
1019 }
1020 }
1021 return sum;
1022 }
1023
1024 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
1025 {
1026 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1027 struct tlv_header *tlvh;
1028 u_int16_t length = 0, sum = 0;
1029
1030 /* Initialize TLV browsing */
1031 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
1032
1033 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
1034 tlvh = TLV_HDR_NEXT(tlvh)) {
1035 switch (ntohs(tlvh->type)) {
1036 case RI_TLV_CAPABILITIES:
1037 sum += show_vty_router_cap(vty, tlvh);
1038 break;
1039 case RI_TLV_PCE:
1040 tlvh++;
1041 sum += TLV_HDR_SIZE;
1042 sum += show_vty_pce_info(vty, tlvh, length - sum);
1043 break;
1044 default:
1045 sum += show_vty_unknown_tlv(vty, tlvh);
1046 break;
1047 }
1048 }
1049
1050 return;
1051 }
1052
1053 static void ospf_router_info_config_write_router(struct vty *vty)
1054 {
1055 struct ospf_pce_info *pce = &OspfRI.pce_info;
1056 struct listnode *node;
1057 struct ri_pce_subtlv_domain *domain;
1058 struct ri_pce_subtlv_neighbor *neighbor;
1059 struct in_addr tmp;
1060
1061 if (OspfRI.enabled) {
1062 if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
1063 vty_out(vty, " router-info as\n");
1064 else
1065 vty_out(vty, " router-info area %s\n",
1066 inet_ntoa(OspfRI.area_id));
1067
1068 if (OspfRI.pce_info.enabled) {
1069
1070 if (pce->pce_address.header.type != 0)
1071 vty_out(vty, " pce address %s\n",
1072 inet_ntoa(pce->pce_address.address.value));
1073
1074 if (pce->pce_cap_flag.header.type != 0)
1075 vty_out(vty, " pce flag 0x%x\n",
1076 ntohl(pce->pce_cap_flag.value));
1077
1078 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
1079 if (domain->header.type != 0) {
1080 if (domain->type == PCE_DOMAIN_TYPE_AREA) {
1081 tmp.s_addr = domain->value;
1082 vty_out(vty, " pce domain area %s\n",
1083 inet_ntoa(tmp));
1084 } else {
1085 vty_out(vty, " pce domain as %d\n",
1086 ntohl(domain->value));
1087 }
1088 }
1089 }
1090
1091 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
1092 if (neighbor->header.type != 0) {
1093 if (neighbor->type == PCE_DOMAIN_TYPE_AREA) {
1094 tmp.s_addr = neighbor->value;
1095 vty_out(vty, " pce neighbor area %s\n",
1096 inet_ntoa(tmp));
1097 } else {
1098 vty_out(vty, " pce neighbor as %d\n",
1099 ntohl(neighbor->value));
1100 }
1101 }
1102 }
1103
1104 if (pce->pce_scope.header.type != 0)
1105 vty_out(vty, " pce scope 0x%x\n",
1106 ntohl(OspfRI.pce_info.pce_scope.value));
1107 }
1108 }
1109 return;
1110 }
1111
1112 /*------------------------------------------------------------------------*
1113 * Followings are vty command functions.
1114 *------------------------------------------------------------------------*/
1115
1116 DEFUN (router_info,
1117 router_info_area_cmd,
1118 "router-info <as|area A.B.C.D>",
1119 OSPF_RI_STR
1120 "Enable the Router Information functionality with AS flooding scope\n"
1121 "Enable the Router Information functionality with Area flooding scope\n"
1122 "OSPF area ID in IP format\n")
1123 {
1124 int idx_ipv4 = 2;
1125 char *area = (argc == 3) ? argv[idx_ipv4]->arg : NULL;
1126
1127 u_int8_t scope;
1128
1129 if (OspfRI.enabled)
1130 return CMD_SUCCESS;
1131
1132 /* Check and get Area value if present */
1133 if (area) {
1134 if (!inet_aton(area, &OspfRI.area_id)) {
1135 vty_out(vty, "%% specified Area ID %s is invalid\n",
1136 area);
1137 return CMD_WARNING_CONFIG_FAILED;
1138 }
1139 scope = OSPF_OPAQUE_AREA_LSA;
1140 } else {
1141 OspfRI.area_id.s_addr = 0;
1142 scope = OSPF_OPAQUE_AS_LSA;
1143 }
1144
1145 /* First start to register Router Information callbacks */
1146 if ((ospf_router_info_register(scope)) != 0) {
1147 zlog_warn(
1148 "Unable to register Router Information callbacks. Abort!");
1149 return CMD_WARNING_CONFIG_FAILED;
1150 }
1151
1152 OspfRI.enabled = true;
1153
1154 if (IS_DEBUG_OSPF_EVENT)
1155 zlog_debug("RI-> Router Information (%s flooding): OFF -> ON",
1156 OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area"
1157 : "AS");
1158
1159 /*
1160 * Following code is intended to handle two cases;
1161 *
1162 * 1) Router Information was disabled at startup time, but now become
1163 * enabled.
1164 * 2) Router Information was once enabled then disabled, and now enabled
1165 * again.
1166 */
1167
1168 initialize_params(&OspfRI);
1169
1170 /* Refresh RI LSA if already engaged */
1171 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) {
1172 zlog_debug ("RI-> Refresh LSA following configuration");
1173 ospf_router_info_lsa_schedule (REFRESH_THIS_LSA);
1174 } else {
1175 zlog_debug("RI-> Initial origination following configuration");
1176 ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA);
1177 }
1178 return CMD_SUCCESS;
1179 }
1180
1181
1182 DEFUN (no_router_info,
1183 no_router_info_cmd,
1184 "no router-info",
1185 NO_STR
1186 "Disable the Router Information functionality\n")
1187 {
1188
1189 if (!OspfRI.enabled)
1190 return CMD_SUCCESS;
1191
1192 if (IS_DEBUG_OSPF_EVENT)
1193 zlog_debug("RI-> Router Information: ON -> OFF");
1194
1195 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1196 ospf_router_info_lsa_schedule(FLUSH_THIS_LSA);
1197
1198 /* Unregister the callbacks */
1199 ospf_router_info_unregister();
1200
1201 OspfRI.enabled = false;
1202
1203 return CMD_SUCCESS;
1204 }
1205
1206 static int ospf_ri_enabled(struct vty *vty)
1207 {
1208 if (OspfRI.enabled)
1209 return 1;
1210
1211 if (vty)
1212 vty_out(vty, "%% OSPF RI is not turned on\n");
1213
1214 return 0;
1215 }
1216
1217 DEFUN (pce_address,
1218 pce_address_cmd,
1219 "pce address A.B.C.D",
1220 PCE_STR
1221 "Stable IP address of the PCE\n"
1222 "PCE address in IPv4 address format\n")
1223 {
1224 int idx_ipv4 = 2;
1225 struct in_addr value;
1226 struct ospf_pce_info *pi = &OspfRI.pce_info;
1227
1228 if (!ospf_ri_enabled(vty))
1229 return CMD_WARNING_CONFIG_FAILED;
1230
1231 if (!inet_aton(argv[idx_ipv4]->arg, &value)) {
1232 vty_out(vty, "Please specify PCE Address by A.B.C.D\n");
1233 return CMD_WARNING_CONFIG_FAILED;
1234 }
1235
1236 if (ntohs(pi->pce_address.header.type) == 0
1237 || ntohl(pi->pce_address.address.value.s_addr)
1238 != ntohl(value.s_addr)) {
1239
1240 set_pce_address(value, pi);
1241
1242 /* Refresh RI LSA if already engaged */
1243 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1244 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1245 }
1246
1247 return CMD_SUCCESS;
1248 }
1249
1250 DEFUN (no_pce_address,
1251 no_pce_address_cmd,
1252 "no pce address [A.B.C.D]",
1253 NO_STR
1254 PCE_STR
1255 "Disable PCE address\n"
1256 "PCE address in IPv4 address format\n")
1257 {
1258
1259 unset_param(&OspfRI.pce_info.pce_address.header);
1260
1261 /* Refresh RI LSA if already engaged */
1262 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1263 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1264
1265 return CMD_SUCCESS;
1266 }
1267
1268 DEFUN (pce_path_scope,
1269 pce_path_scope_cmd,
1270 "pce scope BITPATTERN",
1271 PCE_STR
1272 "Path scope visibilities of the PCE for path computation\n"
1273 "32-bit Hexadecimal value\n")
1274 {
1275 int idx_bitpattern = 2;
1276 uint32_t scope;
1277 struct ospf_pce_info *pi = &OspfRI.pce_info;
1278
1279 if (!ospf_ri_enabled(vty))
1280 return CMD_WARNING_CONFIG_FAILED;
1281
1282 if (sscanf(argv[idx_bitpattern]->arg, "0x%x", &scope) != 1) {
1283 vty_out(vty, "pce_path_scope: fscanf: %s\n",
1284 safe_strerror(errno));
1285 return CMD_WARNING_CONFIG_FAILED;
1286 }
1287
1288 if (ntohl(pi->pce_scope.header.type) == 0
1289 || scope != pi->pce_scope.value) {
1290 set_pce_path_scope(scope, pi);
1291
1292 /* Refresh RI LSA if already engaged */
1293 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1294 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1295 }
1296
1297 return CMD_SUCCESS;
1298 }
1299
1300 DEFUN (no_pce_path_scope,
1301 no_pce_path_scope_cmd,
1302 "no pce scope [BITPATTERN]",
1303 NO_STR
1304 PCE_STR
1305 "Disable PCE path scope\n"
1306 "32-bit Hexadecimal value\n")
1307 {
1308
1309 unset_param(&OspfRI.pce_info.pce_address.header);
1310
1311 /* Refresh RI LSA if already engaged */
1312 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1313 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1314
1315 return CMD_SUCCESS;
1316 }
1317
1318 DEFUN (pce_domain,
1319 pce_domain_cmd,
1320 "pce domain as (0-65535)",
1321 PCE_STR
1322 "Configure PCE domain AS number\n"
1323 "AS number where the PCE as visibilities for path computation\n"
1324 "AS number in decimal <0-65535>\n")
1325 {
1326 int idx_number = 3;
1327
1328 uint32_t as;
1329 struct ospf_pce_info *pce = &OspfRI.pce_info;
1330 struct listnode *node;
1331 struct ri_pce_subtlv_domain *domain;
1332
1333 if (!ospf_ri_enabled(vty))
1334 return CMD_WARNING_CONFIG_FAILED;
1335
1336 if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
1337 vty_out(vty, "pce_domain: fscanf: %s\n", safe_strerror(errno));
1338 return CMD_WARNING_CONFIG_FAILED;
1339 }
1340
1341 /* Check if the domain is not already in the domain list */
1342 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
1343 if (ntohl(domain->header.type) == 0 && as == domain->value)
1344 return CMD_SUCCESS;
1345 }
1346
1347 /* Create new domain if not found */
1348 set_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
1349
1350 /* Refresh RI LSA if already engaged */
1351 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1352 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1353
1354 return CMD_SUCCESS;
1355 }
1356
1357 DEFUN (no_pce_domain,
1358 no_pce_domain_cmd,
1359 "no pce domain as (0-65535)",
1360 NO_STR
1361 PCE_STR
1362 "Disable PCE domain AS number\n"
1363 "AS number where the PCE as visibilities for path computation\n"
1364 "AS number in decimal <0-65535>\n")
1365 {
1366 int idx_number = 4;
1367
1368 uint32_t as;
1369 struct ospf_pce_info *pce = &OspfRI.pce_info;
1370
1371 if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
1372 vty_out(vty, "no_pce_domain: fscanf: %s\n",
1373 safe_strerror(errno));
1374 return CMD_WARNING_CONFIG_FAILED;
1375 }
1376
1377 /* Unset corresponding PCE domain */
1378 unset_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
1379
1380 /* Refresh RI LSA if already engaged */
1381 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1382 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1383
1384 return CMD_SUCCESS;
1385 }
1386
1387 DEFUN (pce_neigbhor,
1388 pce_neighbor_cmd,
1389 "pce neighbor as (0-65535)",
1390 PCE_STR
1391 "Configure PCE neighbor domain AS number\n"
1392 "AS number of PCE neighbors\n"
1393 "AS number in decimal <0-65535>\n")
1394 {
1395 int idx_number = 3;
1396
1397 uint32_t as;
1398 struct ospf_pce_info *pce = &OspfRI.pce_info;
1399 struct listnode *node;
1400 struct ri_pce_subtlv_neighbor *neighbor;
1401
1402 if (!ospf_ri_enabled(vty))
1403 return CMD_WARNING_CONFIG_FAILED;
1404
1405 if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
1406 vty_out(vty, "pce_neighbor: fscanf: %s\n",
1407 safe_strerror(errno));
1408 return CMD_WARNING_CONFIG_FAILED;
1409 }
1410
1411 /* Check if the domain is not already in the domain list */
1412 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
1413 if (ntohl(neighbor->header.type) == 0 && as == neighbor->value)
1414 return CMD_SUCCESS;
1415 }
1416
1417 /* Create new domain if not found */
1418 set_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
1419
1420 /* Refresh RI LSA if already engaged */
1421 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1422 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1423
1424 return CMD_SUCCESS;
1425 }
1426
1427 DEFUN (no_pce_neighbor,
1428 no_pce_neighbor_cmd,
1429 "no pce neighbor as (0-65535)",
1430 NO_STR
1431 PCE_STR
1432 "Disable PCE neighbor AS number\n"
1433 "AS number of PCE neighbor\n"
1434 "AS number in decimal <0-65535>\n")
1435 {
1436 int idx_number = 4;
1437
1438 uint32_t as;
1439 struct ospf_pce_info *pce = &OspfRI.pce_info;
1440
1441 if (sscanf(argv[idx_number]->arg, "%d", &as) != 1) {
1442 vty_out(vty, "no_pce_neighbor: fscanf: %s\n",
1443 safe_strerror(errno));
1444 return CMD_WARNING_CONFIG_FAILED;
1445 }
1446
1447 /* Unset corresponding PCE domain */
1448 unset_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
1449
1450 /* Refresh RI LSA if already engaged */
1451 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1452 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1453
1454 return CMD_SUCCESS;
1455 }
1456
1457 DEFUN (pce_cap_flag,
1458 pce_cap_flag_cmd,
1459 "pce flag BITPATTERN",
1460 PCE_STR
1461 "Capabilities of the PCE for path computation\n"
1462 "32-bit Hexadecimal value\n")
1463 {
1464 int idx_bitpattern = 2;
1465
1466 uint32_t cap;
1467 struct ospf_pce_info *pce = &OspfRI.pce_info;
1468
1469 if (!ospf_ri_enabled(vty))
1470 return CMD_WARNING_CONFIG_FAILED;
1471
1472 if (sscanf(argv[idx_bitpattern]->arg, "0x%x", &cap) != 1) {
1473 vty_out(vty, "pce_cap_flag: fscanf: %s\n",
1474 safe_strerror(errno));
1475 return CMD_WARNING_CONFIG_FAILED;
1476 }
1477
1478 if (ntohl(pce->pce_cap_flag.header.type) == 0
1479 || cap != pce->pce_cap_flag.value) {
1480 set_pce_cap_flag(cap, pce);
1481
1482 /* Refresh RI LSA if already engaged */
1483 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1484 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1485 }
1486
1487 return CMD_SUCCESS;
1488 }
1489
1490 DEFUN (no_pce_cap_flag,
1491 no_pce_cap_flag_cmd,
1492 "no pce flag",
1493 NO_STR
1494 PCE_STR
1495 "Disable PCE capabilities\n")
1496 {
1497
1498 unset_param(&OspfRI.pce_info.pce_cap_flag.header);
1499
1500 /* Refresh RI LSA if already engaged */
1501 if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
1502 ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
1503
1504 return CMD_SUCCESS;
1505 }
1506
1507 DEFUN (show_ip_ospf_router_info,
1508 show_ip_ospf_router_info_cmd,
1509 "show ip ospf router-info",
1510 SHOW_STR
1511 IP_STR
1512 OSPF_STR
1513 "Router Information\n")
1514 {
1515
1516 if (OspfRI.enabled) {
1517 vty_out(vty, "--- Router Information parameters ---\n");
1518 show_vty_router_cap(vty, &OspfRI.router_cap.header);
1519 } else {
1520 if (vty != NULL)
1521 vty_out(vty,
1522 " Router Information is disabled on this router\n");
1523 }
1524 return CMD_SUCCESS;
1525 }
1526
1527 DEFUN (show_ip_opsf_router_info_pce,
1528 show_ip_ospf_router_info_pce_cmd,
1529 "show ip ospf router-info pce",
1530 SHOW_STR
1531 IP_STR
1532 OSPF_STR
1533 "Router Information\n"
1534 "PCE information\n")
1535 {
1536
1537 struct ospf_pce_info *pce = &OspfRI.pce_info;
1538 struct listnode *node;
1539 struct ri_pce_subtlv_domain *domain;
1540 struct ri_pce_subtlv_neighbor *neighbor;
1541
1542 if (OspfRI.enabled) {
1543 vty_out(vty, "--- PCE parameters ---\n");
1544
1545 if (pce->pce_address.header.type != 0)
1546 show_vty_pce_subtlv_address(vty,
1547 &pce->pce_address.header);
1548
1549 if (pce->pce_scope.header.type != 0)
1550 show_vty_pce_subtlv_path_scope(vty,
1551 &pce->pce_scope.header);
1552
1553 for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
1554 if (domain->header.type != 0)
1555 show_vty_pce_subtlv_domain(vty,
1556 &domain->header);
1557 }
1558
1559 for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
1560 if (neighbor->header.type != 0)
1561 show_vty_pce_subtlv_neighbor(vty,
1562 &neighbor->header);
1563 }
1564
1565 if (pce->pce_cap_flag.header.type != 0)
1566 show_vty_pce_subtlv_cap_flag(vty,
1567 &pce->pce_cap_flag.header);
1568
1569 } else {
1570 vty_out(vty,
1571 " Router Information is disabled on this router\n");
1572 }
1573
1574 return CMD_SUCCESS;
1575 }
1576
1577 /* Install new CLI commands */
1578 static void ospf_router_info_register_vty(void)
1579 {
1580 install_element(VIEW_NODE, &show_ip_ospf_router_info_cmd);
1581 install_element(VIEW_NODE, &show_ip_ospf_router_info_pce_cmd);
1582
1583 install_element(OSPF_NODE, &router_info_area_cmd);
1584 install_element(OSPF_NODE, &no_router_info_cmd);
1585 install_element(OSPF_NODE, &pce_address_cmd);
1586 install_element(OSPF_NODE, &no_pce_address_cmd);
1587 install_element(OSPF_NODE, &pce_path_scope_cmd);
1588 install_element(OSPF_NODE, &no_pce_path_scope_cmd);
1589 install_element(OSPF_NODE, &pce_domain_cmd);
1590 install_element(OSPF_NODE, &no_pce_domain_cmd);
1591 install_element(OSPF_NODE, &pce_neighbor_cmd);
1592 install_element(OSPF_NODE, &no_pce_neighbor_cmd);
1593 install_element(OSPF_NODE, &pce_cap_flag_cmd);
1594 install_element(OSPF_NODE, &no_pce_cap_flag_cmd);
1595
1596 return;
1597 }