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