blob: f093208e9556ea237995072058fc97041627f3f6 [file] [log] [blame]
Olivier Dugeon48198692016-04-19 19:21:17 +02001/*
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
62struct 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. */
75struct 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 */
103static struct ospf_router_info OspfRI;
104
105/*------------------------------------------------------------------------------*
106 * Followings are initialize/terminate functions for Router Information handling.
107 *------------------------------------------------------------------------------*/
108
109static void ospf_router_info_ism_change (struct ospf_interface *oi,
110 int old_status);
111static void ospf_router_info_nsm_change (struct ospf_neighbor *nbr,
112 int old_status);
113static void ospf_router_info_config_write_router (struct vty *vty);
114static void ospf_router_info_show_info (struct vty *vty,
115 struct ospf_lsa *lsa);
116static int ospf_router_info_lsa_originate (void *arg);
117static struct ospf_lsa *ospf_router_info_lsa_refresh (struct ospf_lsa *lsa);
118static void ospf_router_info_lsa_schedule (opcode_t opcode);
119static void ospf_router_info_register_vty (void);
120static void del_pce_info (void *val);
121
122int
123ospf_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
143static int
144ospf_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
179static int
180ospf_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
198void
199ospf_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
214static void
215del_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
225static void
226set_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
234static int
235set_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
282static void
283set_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
297static void
298set_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
311static void
312set_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
336static void
337unset_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
367static void
368set_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
392static void
393unset_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
424static void
425set_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
439static void
440unset_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
451static void
452initialize_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
497static int
498is_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
512out:
513 return rc;
514}
515
516/*------------------------------------------------------------------------*
517 * Followings are callback functions against generic Opaque-LSAs handling.
518 *------------------------------------------------------------------------*/
519static void
520ospf_router_info_ism_change (struct ospf_interface *oi, int old_state)
521{
522 /* So far, nothing to do here. */
523 return;
524
525}
526
527static void
528ospf_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
539static void
540build_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
547static void
548build_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
559static void
560ospf_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. */
601static struct ospf_lsa *
602ospf_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
668out:return new;
669}
670
671static int
672ospf_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;
731out:return rc;
732}
733
734static int
735ospf_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;
769out:return rc;
770}
771
772static struct ospf_lsa *
773ospf_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
838out:return new;
839}
840
841static void
842ospf_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
904static u_int16_t
905show_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
918static u_int16_t
919show_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
945static u_int16_t
946show_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
960static u_int16_t
961show_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
986static u_int16_t
987show_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
1013static u_int16_t
1014show_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
1027static u_int16_t
1028show_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
1040static u_int16_t
1041show_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
1073static void
1074ospf_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
1105static void
1106ospf_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
1177DEFUN (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
1239ALIAS (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
1245DEFUN (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
1269DEFUN (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
1299DEFUN (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
1316DEFUN (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
1345DEFUN (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
1362DEFUN (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
1397out:return CMD_SUCCESS;
1398}
1399
1400DEFUN (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
1430DEFUN (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
1465out:return CMD_SUCCESS;
1466}
1467
1468DEFUN (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
1498DEFUN (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
1529DEFUN (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
1546DEFUN (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
1568DEFUN (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 */
1619static void
1620ospf_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);
Olivier Dugeon48198692016-04-19 19:21:17 +02001624
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}