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