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