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