1/* 2 * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt 3 * Copyright (C) 2001 KDD R&D Laboratories, Inc. 4 * http://www.kddlabs.co.jp/ 5 * 6 * This file is part of GNU Zebra. 7 * 8 * GNU Zebra is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2, or (at your option) any 11 * later version. 12 * 13 * GNU Zebra is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with GNU Zebra; see the file COPYING. If not, write to the Free 20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 21 * 02111-1307, USA. 22 */ 23 24/***** MTYPE definition is not reflected to "memory.h" yet. *****/ 25#define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 26 27#include <zebra.h> 28 29#ifdef HAVE_OSPF_TE 30#ifndef HAVE_OPAQUE_LSA 31#error "Wrong configure option" 32#endif /* HAVE_OPAQUE_LSA */ 33 34#include "linklist.h" 35#include "prefix.h" 36#include "if.h" 37#include "table.h" 38#include "memory.h" 39#include "command.h" 40#include "vty.h" 41#include "stream.h" 42#include "log.h" 43#include "thread.h" 44#include "hash.h" 45#include "sockunion.h" /* for inet_aton() */ 46 47#include "ospfd/ospfd.h" 48#include "ospfd/ospf_interface.h" 49#include "ospfd/ospf_ism.h" 50#include "ospfd/ospf_asbr.h" 51#include "ospfd/ospf_lsa.h" 52#include "ospfd/ospf_lsdb.h" 53#include "ospfd/ospf_neighbor.h" 54#include "ospfd/ospf_nsm.h" 55#include "ospfd/ospf_flood.h" 56#include "ospfd/ospf_packet.h" 57#include "ospfd/ospf_spf.h" 58#include "ospfd/ospf_dump.h" 59#include "ospfd/ospf_route.h" 60#include "ospfd/ospf_ase.h" 61#include "ospfd/ospf_zebra.h" 62#include "ospfd/ospf_te.h" 63 64/* Following structure are internal use only. */ 65struct ospf_mpls_te 66{ 67 enum { disabled, enabled } status; 68 69 /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ 70 list iflist; 71 72 /* Store Router-TLV in network byte order. */ 73 struct te_tlv_router_addr router_addr; 74}; 75 76struct mpls_te_link 77{ 78 /* 79 * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field 80 * is subdivided into 8-bit "unused" field and 16-bit "instance" field. 81 * In this implementation, each Link-TLV has its own instance. 82 */ 83 u_int32_t instance; 84 85 /* Reference pointer to a Zebra-interface. */ 86 struct interface *ifp; 87 88 /* Area info in which this MPLS-TE link belongs to. */ 89 struct ospf_area *area; 90 91 /* Flags to manage this link parameters. */ 92 u_int32_t flags; 93#define LPFLG_LOOKUP_DONE 0x1 94#define LPFLG_LSA_ENGAGED 0x2 95#define LPFLG_LSA_FORCED_REFRESH 0x4 96 97 /* Store Link-TLV in network byte order. */ 98 struct te_tlv_link link_header; 99 struct te_link_subtlv_link_type link_type; 100 struct te_link_subtlv_link_id link_id; 101 struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; 102 struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; 103 struct te_link_subtlv_te_metric te_metric; 104 struct te_link_subtlv_max_bw max_bw; 105 struct te_link_subtlv_max_rsv_bw max_rsv_bw; 106 struct te_link_subtlv_unrsv_bw unrsv_bw; 107 struct te_link_subtlv_rsc_clsclr rsc_clsclr; 108}; 109 110/* 111 * Global variable to manage Opaque-LSA/MPLS-TE on this node. 112 * Note that all parameter values are stored in network byte order. 113 */ 114static struct ospf_mpls_te OspfMplsTE; 115 116enum oifstate { 117 OI_ANY, OI_DOWN, OI_UP 118}; 119 120enum sched_opcode { 121 REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA 122}; 123 124/*------------------------------------------------------------------------* 125 * Followings are initialize/terminate functions for MPLS-TE handling. 126 *------------------------------------------------------------------------*/ 127 128static int ospf_mpls_te_new_if (struct interface *ifp); 129static int ospf_mpls_te_del_if (struct interface *ifp); 130static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); 131static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); 132static void ospf_mpls_te_config_write_router (struct vty *vty); 133static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); 134static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); 135static int ospf_mpls_te_lsa_originate (void *arg); 136static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); 137static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); 138 139static void del_mpls_te_link (void *val); 140static void ospf_mpls_te_register_vty (void); 141 142int 143ospf_mpls_te_init (void) 144{ 145 int rc; 146 147 rc = ospf_register_opaque_functab ( 148 OSPF_OPAQUE_AREA_LSA, 149 OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, 150 ospf_mpls_te_new_if, 151 ospf_mpls_te_del_if, 152 ospf_mpls_te_ism_change, 153 ospf_mpls_te_nsm_change, 154 ospf_mpls_te_config_write_router, 155 ospf_mpls_te_config_write_if, 156 NULL,/* ospf_mpls_te_config_write_debug */ 157 ospf_mpls_te_show_info, 158 ospf_mpls_te_lsa_originate, 159 ospf_mpls_te_lsa_refresh, 160 NULL,/* ospf_mpls_te_new_lsa_hook */ 161 NULL /* ospf_mpls_te_del_lsa_hook */); 162 if (rc != 0) 163 { 164 zlog_warn ("ospf_mpls_te_init: Failed to register functions"); 165 goto out; 166 } 167 168 memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); 169 OspfMplsTE.status = disabled; 170 OspfMplsTE.iflist = list_new (); 171 OspfMplsTE.iflist->del = del_mpls_te_link; 172 173 ospf_mpls_te_register_vty (); 174 175out: 176 return rc; 177} 178 179void 180ospf_mpls_te_term (void) 181{ 182 list_delete (OspfMplsTE.iflist); 183 184 OspfMplsTE.iflist = NULL; 185 OspfMplsTE.status = disabled; 186 187 ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, 188 OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); 189 return; 190} 191 192/*------------------------------------------------------------------------* 193 * Followings are control functions for MPLS-TE parameters management. 194 *------------------------------------------------------------------------*/ 195 196static void 197del_mpls_te_link (void *val) 198{ 199 XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); 200 return; 201} 202 203static u_int32_t 204get_mpls_te_instance_value () 205{ 206 static u_int32_t seqno = 0; 207 208 if (LEGAL_TE_INSTANCE_RANGE (seqno + 1)) 209 seqno += 1; 210 else 211 seqno = 1; /* Avoid zero. */ 212 213 return seqno; 214} 215 216static struct ospf_interface * 217lookup_oi_by_ifp (struct interface *ifp, 218 struct ospf_area *area, enum oifstate oifstate) 219{ 220 struct ospf_interface *oi = NULL; 221 struct route_node *rn; 222 223 for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) 224 { 225 if ((oi = rn->info) == NULL) 226 continue; 227 228 switch (oifstate) 229 { 230 case OI_ANY: 231 break; 232 case OI_DOWN: 233 if (ospf_if_is_enable (oi)) 234 continue; 235 break; 236 case OI_UP: 237 if (! ospf_if_is_enable (oi)) 238 continue; 239 break; 240 default: 241 zlog_warn ("lookup_oi_by_ifp: Unknown oifstate: %x", oifstate); 242 goto out; 243 } 244 245 if (area == NULL || oi->area == area) 246 return oi; 247 } 248out: 249 return NULL; 250} 251 252static struct mpls_te_link * 253lookup_linkparams_by_ifp (struct interface *ifp) 254{ 255 listnode node; 256 struct mpls_te_link *lp; 257 258 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 259 if ((lp = getdata (node)) != NULL) 260 if (lp->ifp == ifp) 261 return lp; 262 263 return NULL; 264} 265 266static struct mpls_te_link * 267lookup_linkparams_by_instance (struct ospf_lsa *lsa) 268{ 269 listnode node; 270 struct mpls_te_link *lp; 271 int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); 272 273 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 274 if ((lp = getdata (node)) != NULL) 275 if (lp->instance == key) 276 return lp; 277 278 zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key); 279 return NULL; 280} 281 282static void 283ospf_mpls_te_foreach_area ( 284 void (*func)(struct mpls_te_link *lp, enum sched_opcode), 285 enum sched_opcode sched_opcode) 286{ 287 listnode node, node2; 288 struct mpls_te_link *lp; 289 struct ospf_area *area; 290 291 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 292 { 293 if ((lp = getdata (node)) == NULL) 294 continue; 295 if ((area = lp->area) == NULL) 296 continue; 297 if (lp->flags & LPFLG_LOOKUP_DONE) 298 continue; 299 300 if (func != NULL) 301 (* func)(lp, sched_opcode); 302 303 for (node2 = nextnode (node); node2; nextnode (node2)) 304 if ((lp = getdata (node2)) != NULL) 305 if (lp->area != NULL) 306 if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) 307 lp->flags |= LPFLG_LOOKUP_DONE; 308 } 309 310 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 311 if ((lp = getdata (node)) != NULL) 312 if (lp->area != NULL) 313 lp->flags &= ~LPFLG_LOOKUP_DONE; 314 315 return; 316} 317 318static void 319set_mpls_te_router_addr (struct in_addr ipv4) 320{ 321 OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); 322 OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); 323 OspfMplsTE.router_addr.value = ipv4; 324 return; 325} 326 327static void 328set_linkparams_link_header (struct mpls_te_link *lp) 329{ 330 struct te_tlv_header *tlvh; 331 u_int16_t length = 0; 332 333 /* TE_LINK_SUBTLV_LINK_TYPE */ 334 if (ntohs (lp->link_type.header.type) != 0) 335 length += TLV_SIZE (&lp->link_type.header); 336 337 /* TE_LINK_SUBTLV_LINK_ID */ 338 if (ntohs (lp->link_id.header.type) != 0) 339 length += TLV_SIZE (&lp->link_id.header); 340 341 /* TE_LINK_SUBTLV_LCLIF_IPADDR */ 342 if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL 343 && ntohs (tlvh->type) != 0) 344 length += TLV_SIZE (tlvh); 345 346 /* TE_LINK_SUBTLV_RMTIF_IPADDR */ 347 if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL 348 && ntohs (tlvh->type) != 0) 349 length += TLV_SIZE (tlvh); 350 351 /* TE_LINK_SUBTLV_TE_METRIC */ 352 if (ntohs (lp->te_metric.header.type) != 0) 353 length += TLV_SIZE (&lp->te_metric.header); 354 355 /* TE_LINK_SUBTLV_MAX_BW */ 356 if (ntohs (lp->max_bw.header.type) != 0) 357 length += TLV_SIZE (&lp->max_bw.header); 358 359 /* TE_LINK_SUBTLV_MAX_RSV_BW */ 360 if (ntohs (lp->max_rsv_bw.header.type) != 0) 361 length += TLV_SIZE (&lp->max_rsv_bw.header); 362 363 /* TE_LINK_SUBTLV_UNRSV_BW */ 364 if (ntohs (lp->unrsv_bw.header.type) != 0) 365 length += TLV_SIZE (&lp->unrsv_bw.header); 366 367 /* TE_LINK_SUBTLV_RSC_CLSCLR */ 368 if (ntohs (lp->rsc_clsclr.header.type) != 0) 369 length += TLV_SIZE (&lp->rsc_clsclr.header); 370 371 lp->link_header.header.type = htons (TE_TLV_LINK); 372 lp->link_header.header.length = htons (length); 373 374 return; 375} 376 377static void 378set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) 379{ 380 lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); 381 lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); 382 383 switch (oi->type) 384 { 385 case OSPF_IFTYPE_POINTOPOINT: 386 lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; 387 break; 388 case OSPF_IFTYPE_BROADCAST: 389 case OSPF_IFTYPE_NBMA: 390 lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; 391 break; 392 default: 393 /* Not supported yet. *//* XXX */ 394 lp->link_type.header.type = htons (0); 395 break; 396 } 397 return; 398} 399 400static void 401set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) 402{ 403 struct ospf_neighbor *nbr; 404 int done = 0; 405 406 lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); 407 lp->link_id.header.length = htons (sizeof (lp->link_id.value)); 408 409 /* 410 * The Link ID is identical to the contents of the Link ID field 411 * in the Router LSA for these link types. 412 */ 413 switch (oi->type) 414 { 415 case OSPF_IFTYPE_POINTOPOINT: 416 /* Take the router ID of the neighbor. */ 417 if (((nbr = ospf_nbr_lookup_ptop (oi->nbrs, oi->area->top->router_id))) 418 && (nbr->state == NSM_Full)) 419 { 420 lp->link_id.value = nbr->router_id; 421 done = 1; 422 } 423 break; 424 case OSPF_IFTYPE_BROADCAST: 425 case OSPF_IFTYPE_NBMA: 426 /* Take the interface address of the designated router. */ 427 if ((nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi))) == NULL) 428 break; 429 430 if (nbr->state == NSM_Full 431 || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) 432 && ospf_nbr_count (oi->nbrs, NSM_Full) > 0)) 433 { 434 lp->link_id.value = DR (oi); 435 done = 1; 436 } 437 break; 438 default: 439 /* Not supported yet. *//* XXX */ 440 lp->link_id.header.type = htons (0); 441 break; 442 } 443 444 if (! done) 445 { 446 struct in_addr mask; 447 masklen2ip (oi->address->prefixlen, &mask); 448 lp->link_id.value.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; 449 } 450 return; 451} 452 453static void 454set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) 455{ 456 lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC); 457 lp->te_metric.header.length = htons (sizeof (lp->te_metric.value)); 458 lp->te_metric.value = htonl (te_metric); 459 return; 460} 461 462static void 463set_linkparams_max_bw (struct mpls_te_link *lp, float *fp) 464{ 465 lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); 466 lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); 467 htonf (fp, &lp->max_bw.value); 468 return; 469} 470 471static void 472set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp) 473{ 474 lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); 475 lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); 476 htonf (fp, &lp->max_rsv_bw.value); 477 return; 478} 479 480static void 481set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp) 482{ 483 /* Note that TLV-length field is the size of array. */ 484 lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); 485 lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); 486 htonf (fp, &lp->unrsv_bw.value [priority]); 487 return; 488} 489 490static void 491set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor) 492{ 493 lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR); 494 lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value)); 495 lp->rsc_clsclr.value = htonl (classcolor); 496 return; 497} 498 499static void 500initialize_linkparams (struct mpls_te_link *lp) 501{ 502 struct interface *ifp = lp->ifp; 503 struct ospf_interface *oi; 504 float fval; 505 int i; 506 507 if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) 508 return; 509 510 /* 511 * Try to set initial values those can be derived from 512 * zebra-interface information. 513 */ 514 set_linkparams_link_type (oi, lp); 515 516 /* 517 * Linux and *BSD kernel holds bandwidth parameter as an "int" type. 518 * We may have to reconsider, if "ifp->bandwidth" type changes to float. 519 */ 520 fval = (float)((ifp->bandwidth ? ifp->bandwidth 521 : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); 522 523 set_linkparams_max_bw (lp, &fval); 524 set_linkparams_max_rsv_bw (lp, &fval); 525 526 for (i = 0; i < 8; i++) 527 set_linkparams_unrsv_bw (lp, i, &fval); 528 529 return; 530} 531 532static int 533is_mandated_params_set (struct mpls_te_link *lp) 534{ 535 int rc = 0; 536 537 if (ntohs (OspfMplsTE.router_addr.header.type) == 0) 538 goto out; 539 540 if (ntohs (lp->link_type.header.type) == 0) 541 goto out; 542 543 if (ntohs (lp->link_id.header.type) == 0) 544 goto out; 545 546 rc = 1; 547out: 548 return rc; 549} 550 551/*------------------------------------------------------------------------* 552 * Followings are callback functions against generic Opaque-LSAs handling. 553 *------------------------------------------------------------------------*/ 554 555static int 556ospf_mpls_te_new_if (struct interface *ifp) 557{ 558 struct mpls_te_link *new; 559 int rc = -1; 560 561 if (lookup_linkparams_by_ifp (ifp) != NULL) 562 { 563 zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp); 564 rc = 0; /* Do nothing here. */ 565 goto out; 566 } 567 568 if ((new = XMALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS, 569 sizeof (struct mpls_te_link))) == NULL) 570 { 571 zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", strerror (errno)); 572 goto out; 573 } 574 memset (new, 0, sizeof (struct mpls_te_link)); 575 576 new->area = NULL; 577 new->flags = 0; 578 new->instance = get_mpls_te_instance_value (); 579 new->ifp = ifp; 580 581 initialize_linkparams (new); 582 583 listnode_add (OspfMplsTE.iflist, new); 584 585 /* Schedule Opaque-LSA refresh. *//* XXX */ 586 587 rc = 0; 588out: 589 return rc; 590} 591 592static int 593ospf_mpls_te_del_if (struct interface *ifp) 594{ 595 struct mpls_te_link *lp; 596 int rc = -1; 597 598 if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL) 599 { 600 list iflist = OspfMplsTE.iflist; 601 602 /* Dequeue listnode entry from the list. */ 603 listnode_delete (iflist, lp); 604 605 /* Avoid misjudgement in the next lookup. */ 606 if (listcount (iflist) == 0) 607 iflist->head = iflist->tail = NULL; 608 609 XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp); 610 } 611 612 /* Schedule Opaque-LSA refresh. *//* XXX */ 613 614 rc = 0; 615/*out:*/ 616 return rc; 617} 618 619static void 620ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) 621{ 622 struct te_link_subtlv_link_type old_type; 623 struct te_link_subtlv_link_id old_id; 624 struct mpls_te_link *lp; 625 626 if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL) 627 { 628 zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi)); 629 goto out; 630 } 631 if (oi->area == NULL || oi->area->top == NULL) 632 { 633 zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", 634IF_NAME (oi)); 635 goto out; 636 } 637#ifdef notyet 638 if ((lp->area != NULL 639 && ! IPV4_ADDR_SAME (&lp->area->area_id, &oi->area->area_id)) 640 || (lp->area != NULL && oi->area == NULL)) 641 { 642 /* How should we consider this case? */ 643 zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); 644 ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); 645 } 646#endif 647 /* Keep Area information in conbination with linkparams. */ 648 lp->area = oi->area; 649 650 switch (oi->state) 651 { 652 case ISM_PointToPoint: 653 case ISM_DROther: 654 case ISM_Backup: 655 case ISM_DR: 656 old_type = lp->link_type; 657 old_id = lp->link_id; 658 659 set_linkparams_link_type (oi, lp); 660 set_linkparams_link_id (oi, lp); 661 662 if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type) 663 || old_type.link_type.value != lp->link_type.link_type.value) 664 || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type) 665 || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr))) 666 { 667 if (lp->flags & LPFLG_LSA_ENGAGED) 668 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 669 else 670 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); 671 } 672 break; 673 default: 674 lp->link_type.header.type = htons (0); 675 lp->link_id.header.type = htons (0); 676 677 if (lp->flags & LPFLG_LSA_ENGAGED) 678 ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); 679 break; 680 } 681 682out: 683 return; 684} 685 686static void 687ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state) 688{ 689 /* So far, nothing to do here. */ 690 return; 691} 692 693/*------------------------------------------------------------------------* 694 * Followings are OSPF protocol processing functions for MPLS-TE. 695 *------------------------------------------------------------------------*/ 696 697static void 698build_tlv_header (struct stream *s, struct te_tlv_header *tlvh) 699{ 700 stream_put (s, tlvh, sizeof (struct te_tlv_header)); 701 return; 702} 703 704static void 705build_router_tlv (struct stream *s) 706{ 707 struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header; 708 if (ntohs (tlvh->type) != 0) 709 { 710 build_tlv_header (s, tlvh); 711 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 712 } 713 return; 714} 715 716static void 717build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp) 718{ 719 struct te_tlv_header *tlvh = &lp->link_type.header; 720 if (ntohs (tlvh->type) != 0) 721 { 722 build_tlv_header (s, tlvh); 723 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 724 } 725 return; 726} 727 728static void 729build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) 730{ 731 struct te_tlv_header *tlvh = &lp->link_id.header; 732 if (ntohs (tlvh->type) != 0) 733 { 734 build_tlv_header (s, tlvh); 735 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 736 } 737 return; 738} 739 740static void 741build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp) 742{ 743 struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr; 744 if (tlvh != NULL && ntohs (tlvh->type) != 0) 745 { 746 build_tlv_header (s, tlvh); 747 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 748 } 749 return; 750} 751 752static void 753build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp) 754{ 755 struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr; 756 if (tlvh != NULL && ntohs (tlvh->type) != 0) 757 { 758 build_tlv_header (s, tlvh); 759 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 760 } 761 return; 762} 763 764static void 765build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp) 766{ 767 struct te_tlv_header *tlvh = &lp->te_metric.header; 768 if (ntohs (tlvh->type) != 0) 769 { 770 build_tlv_header (s, tlvh); 771 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 772 } 773 return; 774} 775 776static void 777build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp) 778{ 779 struct te_tlv_header *tlvh = &lp->max_bw.header; 780 if (ntohs (tlvh->type) != 0) 781 { 782 build_tlv_header (s, tlvh); 783 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 784 } 785 return; 786} 787 788static void 789build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp) 790{ 791 struct te_tlv_header *tlvh = &lp->max_rsv_bw.header; 792 if (ntohs (tlvh->type) != 0) 793 { 794 build_tlv_header (s, tlvh); 795 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 796 } 797 return; 798} 799 800static void 801build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp) 802{ 803 struct te_tlv_header *tlvh = &lp->unrsv_bw.header; 804 if (ntohs (tlvh->type) != 0) 805 { 806 build_tlv_header (s, tlvh); 807 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 808 } 809 return; 810} 811 812static void 813build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp) 814{ 815 struct te_tlv_header *tlvh = &lp->rsc_clsclr.header; 816 if (ntohs (tlvh->type) != 0) 817 { 818 build_tlv_header (s, tlvh); 819 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); 820 } 821 return; 822} 823 824static void 825build_link_tlv (struct stream *s, struct mpls_te_link *lp) 826{ 827 set_linkparams_link_header (lp); 828 build_tlv_header (s, &lp->link_header.header); 829 830 build_link_subtlv_link_type (s, lp); 831 build_link_subtlv_link_id (s, lp); 832 build_link_subtlv_lclif_ipaddr (s, lp); 833 build_link_subtlv_rmtif_ipaddr (s, lp); 834 build_link_subtlv_te_metric (s, lp); 835 build_link_subtlv_max_bw (s, lp); 836 build_link_subtlv_max_rsv_bw (s, lp); 837 build_link_subtlv_unrsv_bw (s, lp); 838 build_link_subtlv_rsc_clsclr (s, lp); 839 return; 840} 841 842static void 843ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp) 844{ 845 /* 846 * The router address TLV is type 1, and ... 847 * It must appear in exactly one 848 * Traffic Engineering LSA originated by a router. 849 */ 850 build_router_tlv (s); 851 852 /* 853 * Only one Link TLV shall be carried in each LSA, allowing for fine 854 * granularity changes in topology. 855 */ 856 build_link_tlv (s, lp); 857 return; 858} 859 860/* Create new opaque-LSA. */ 861static struct ospf_lsa * 862ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) 863{ 864 struct stream *s; 865 struct lsa_header *lsah; 866 struct ospf_lsa *new = NULL; 867 u_char options, lsa_type; 868 struct in_addr lsa_id; 869 u_int32_t tmp; 870 u_int16_t length; 871 872 /* Create a stream for LSA. */ 873 if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) 874 { 875 zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?"); 876 goto out; 877 } 878 lsah = (struct lsa_header *) STREAM_DATA (s); 879 880 options = LSA_OPTIONS_GET (area); 881#ifdef HAVE_NSSA 882 options |= LSA_NSSA_GET (area); 883#endif /* HAVE_NSSA */ 884 options |= OSPF_OPTION_O; /* Don't forget this :-) */ 885 886 lsa_type = OSPF_OPAQUE_AREA_LSA; 887 tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); 888 lsa_id.s_addr = htonl (tmp); 889 890 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) 891 zlog_info ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id)); 892 893 /* Set opaque-LSA header fields. */ 894 lsa_header_set (s, options, lsa_type, lsa_id); 895 896 /* Set opaque-LSA body fields. */ 897 ospf_mpls_te_lsa_body_set (s, lp); 898 899 /* Set length. */ 900 length = stream_get_endp (s); 901 lsah->length = htons (length); 902 903 /* Now, create an OSPF LSA instance. */ 904 if ((new = ospf_lsa_new ()) == NULL) 905 { 906 zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?"); 907 stream_free (s); 908 goto out; 909 } 910 if ((new->data = ospf_lsa_data_new (length)) == NULL) 911 { 912 zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?"); 913 ospf_lsa_free (new); 914 new = NULL; 915 stream_free (s); 916 goto out; 917 } 918 919 new->area = area; 920 SET_FLAG (new->flags, OSPF_LSA_SELF); 921 memcpy (new->data, lsah, length); 922 stream_free (s); 923 924out: 925 return new; 926} 927 928static int 929ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) 930{ 931 struct ospf_lsa *new; 932 int rc = -1; 933 934 /* Create new Opaque-LSA/MPLS-TE instance. */ 935 if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) 936 { 937 zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?"); 938 goto out; 939 } 940 941 /* Install this LSA into LSDB. */ 942 if (ospf_lsa_install (NULL/*oi*/, new) == NULL) 943 { 944 zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?"); 945 ospf_lsa_free (new); 946 goto out; 947 } 948 949 /* Now this linkparameter entry has associated LSA. */ 950 lp->flags |= LPFLG_LSA_ENGAGED; 951 952 /* Update new LSA origination count. */ 953 area->top->lsa_originate_count++; 954 955 /* Flood new LSA through area. */ 956 ospf_flood_through_area (area, NULL/*nbr*/, new); 957 958 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) 959 { 960 char area_id[INET_ADDRSTRLEN]; 961 strcpy (area_id, inet_ntoa (area->area_id)); 962 zlog_info ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); 963 ospf_lsa_header_dump (new->data); 964 } 965 966 rc = 0; 967out: 968 return rc; 969} 970 971static int 972ospf_mpls_te_lsa_originate (void *arg) 973{ 974 struct ospf_area *area = (struct ospf_area *) arg; 975 listnode node; 976 struct mpls_te_link *lp; 977 int rc = -1; 978 979 if (OspfMplsTE.status == disabled) 980 { 981 zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now."); 982 rc = 0; /* This is not an error case. */ 983 goto out; 984 } 985 986 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 987 { 988 if ((lp = getdata (node)) == NULL) 989 continue; 990 if (lp->area == NULL) 991 continue; 992 if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) 993 continue; 994 995 if (lp->flags & LPFLG_LSA_ENGAGED) 996 { 997 if (lp->flags & LPFLG_LSA_FORCED_REFRESH) 998 { 999 lp->flags &= ~LPFLG_LSA_FORCED_REFRESH; 1000 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 1001 } 1002 continue; 1003 } 1004 if (! is_mandated_params_set (lp)) 1005 { 1006 zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); 1007 continue; 1008 } 1009 1010 /* Ok, let's try to originate an LSA for this area and Link. */ 1011 if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) 1012 goto out; 1013 } 1014 1015 rc = 0; 1016out: 1017 return rc; 1018} 1019 1020static void 1021ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) 1022{ 1023 struct mpls_te_link *lp; 1024 struct ospf_area *area = lsa->area; 1025 struct ospf_lsa *new = NULL; 1026 1027 if (OspfMplsTE.status == disabled) 1028 { 1029 /* 1030 * This LSA must have flushed before due to MPLS-TE status change. 1031 * It seems a slip among routers in the routing domain. 1032 */ 1033 zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now."); 1034 lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ 1035 } 1036 1037 /* At first, resolve lsa/lp relationship. */ 1038 if ((lp = lookup_linkparams_by_instance (lsa)) == NULL) 1039 { 1040 zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?"); 1041 lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ 1042 } 1043 1044 /* If the lsa's age reached to MaxAge, start flushing procedure. */ 1045 if (IS_LSA_MAXAGE (lsa)) 1046 { 1047 lp->flags &= ~LPFLG_LSA_ENGAGED; 1048 ospf_opaque_lsa_flush_schedule (lsa); 1049 goto out; 1050 } 1051 1052 /* Create new Opaque-LSA/MPLS-TE instance. */ 1053 if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) 1054 { 1055 zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); 1056 goto out; 1057 } 1058 new->data->ls_seqnum = lsa_seqnum_increment (lsa); 1059 1060 /* Install this LSA into LSDB. */ 1061 /* Given "lsa" will be freed in the next function. */ 1062 if (ospf_lsa_install (NULL/*oi*/, new) == NULL) 1063 { 1064 zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); 1065 ospf_lsa_free (new); 1066 goto out; 1067 } 1068 1069 /* Flood updated LSA through area. */ 1070 ospf_flood_through_area (area, NULL/*nbr*/, new); 1071 1072 /* Debug logging. */ 1073 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) 1074 { 1075 zlog_info ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE", 1076 new->data->type, inet_ntoa (new->data->id)); 1077 ospf_lsa_header_dump (new->data); 1078 } 1079 1080out: 1081 return; 1082} 1083 1084static void 1085ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, 1086 enum sched_opcode opcode) 1087{ 1088 struct ospf_lsa lsa; 1089 struct lsa_header lsah; 1090 u_int32_t tmp; 1091 1092 memset (&lsa, 0, sizeof (lsa)); 1093 memset (&lsah, 0, sizeof (lsah)); 1094 1095 lsa.area = lp->area; 1096 lsa.data = &lsah; 1097 lsah.type = OSPF_OPAQUE_AREA_LSA; 1098 tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); 1099 lsah.id.s_addr = htonl (tmp); 1100 1101 switch (opcode) 1102 { 1103 case REORIGINATE_PER_AREA: 1104 ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, 1105 OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); 1106 break; 1107 case REFRESH_THIS_LSA: 1108 ospf_opaque_lsa_refresh_schedule (&lsa); 1109 break; 1110 case FLUSH_THIS_LSA: 1111 lp->flags &= ~LPFLG_LSA_ENGAGED; 1112 ospf_opaque_lsa_flush_schedule (&lsa); 1113 break; 1114 default: 1115 zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode); 1116 break; 1117 } 1118 1119 return; 1120} 1121 1122/*------------------------------------------------------------------------* 1123 * Followings are vty session control functions. 1124 *------------------------------------------------------------------------*/ 1125 1126static u_int16_t 1127show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh) 1128{ 1129 struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh; 1130 1131 if (vty != NULL) 1132 vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); 1133 else 1134 zlog_info (" Router-Address: %s", inet_ntoa (top->value)); 1135 1136 return TLV_SIZE (tlvh); 1137} 1138 1139static u_int16_t 1140show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh) 1141{ 1142 struct te_tlv_link *top = (struct te_tlv_link *) tlvh; 1143 1144 if (vty != NULL) 1145 vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE); 1146 else 1147 zlog_info (" Link: %u octets of data", ntohs (top->header.length)); 1148 1149 return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */ 1150} 1151 1152static u_int16_t 1153show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh) 1154{ 1155 struct te_link_subtlv_link_type *top; 1156 const char *cp = "Unknown"; 1157 1158 top = (struct te_link_subtlv_link_type *) tlvh; 1159 switch (top->link_type.value) 1160 { 1161 case LINK_TYPE_SUBTLV_VALUE_PTP: 1162 cp = "Point-to-point"; 1163 break; 1164 case LINK_TYPE_SUBTLV_VALUE_MA: 1165 cp = "Multiaccess"; 1166 break; 1167 default: 1168 break; 1169 } 1170 1171 if (vty != NULL) 1172 vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE); 1173 else 1174 zlog_info (" Link-Type: %s (%u)", cp, top->link_type.value); 1175 1176 return TLV_SIZE (tlvh); 1177} 1178 1179static u_int16_t 1180show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh) 1181{ 1182 struct te_link_subtlv_link_id *top; 1183 1184 top = (struct te_link_subtlv_link_id *) tlvh; 1185 if (vty != NULL) 1186 vty_out (vty, " Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE); 1187 else 1188 zlog_info (" Link-ID: %s", inet_ntoa (top->value)); 1189 1190 return TLV_SIZE (tlvh); 1191} 1192 1193static u_int16_t 1194show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) 1195{ 1196 struct te_link_subtlv_lclif_ipaddr *top; 1197 int i, n; 1198 1199 top = (struct te_link_subtlv_lclif_ipaddr *) tlvh; 1200 n = ntohs (tlvh->length) / sizeof (top->value[0]); 1201 1202 if (vty != NULL) 1203 vty_out (vty, " Local Interface IP Address(es): %d%s", n, VTY_NEWLINE); 1204 else 1205 zlog_info (" Local Interface IP Address(es): %d", n); 1206 1207 for (i = 0; i < n; i++) 1208 { 1209 if (vty != NULL) 1210 vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); 1211 else 1212 zlog_info (" #%d: %s", i, inet_ntoa (top->value[i])); 1213 } 1214 return TLV_SIZE (tlvh); 1215} 1216 1217static u_int16_t 1218show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) 1219{ 1220 struct te_link_subtlv_rmtif_ipaddr *top; 1221 int i, n; 1222 1223 top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh; 1224 n = ntohs (tlvh->length) / sizeof (top->value[0]); 1225 if (vty != NULL) 1226 vty_out (vty, " Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE); 1227 else 1228 zlog_info (" Remote Interface IP Address(es): %d", n); 1229 1230 for (i = 0; i < n; i++) 1231 { 1232 if (vty != NULL) 1233 vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); 1234 else 1235 zlog_info (" #%d: %s", i, inet_ntoa (top->value[i])); 1236 } 1237 return TLV_SIZE (tlvh); 1238} 1239 1240static u_int16_t 1241show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh) 1242{ 1243 struct te_link_subtlv_te_metric *top; 1244 1245 top = (struct te_link_subtlv_te_metric *) tlvh; 1246 if (vty != NULL) 1247 vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); 1248 else 1249 zlog_info (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value)); 1250 1251 return TLV_SIZE (tlvh); 1252} 1253 1254static u_int16_t 1255show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh) 1256{ 1257 struct te_link_subtlv_max_bw *top; 1258 float fval; 1259 1260 top = (struct te_link_subtlv_max_bw *) tlvh; 1261 ntohf (&top->value, &fval); 1262 1263 if (vty != NULL) 1264 vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); 1265 else 1266 zlog_info (" Maximum Bandwidth: %g (Bytes/sec)", fval); 1267 1268 return TLV_SIZE (tlvh); 1269} 1270 1271static u_int16_t 1272show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh) 1273{ 1274 struct te_link_subtlv_max_rsv_bw *top; 1275 float fval; 1276 1277 top = (struct te_link_subtlv_max_rsv_bw *) tlvh; 1278 ntohf (&top->value, &fval); 1279 1280 if (vty != NULL) 1281 vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); 1282 else 1283 zlog_info (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); 1284 1285 return TLV_SIZE (tlvh); 1286} 1287 1288static u_int16_t 1289show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh) 1290{ 1291 struct te_link_subtlv_unrsv_bw *top; 1292 float fval; 1293 int i; 1294 1295 top = (struct te_link_subtlv_unrsv_bw *) tlvh; 1296 for (i = 0; i < 8; i++) 1297 { 1298 ntohf (&top->value[i], &fval); 1299 if (vty != NULL) 1300 vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); 1301 else 1302 zlog_info (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval); 1303 } 1304 1305 return TLV_SIZE (tlvh); 1306} 1307 1308static u_int16_t 1309show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh) 1310{ 1311 struct te_link_subtlv_rsc_clsclr *top; 1312 1313 top = (struct te_link_subtlv_rsc_clsclr *) tlvh; 1314 if (vty != NULL) 1315 vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); 1316 else 1317 zlog_info (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); 1318 1319 return TLV_SIZE (tlvh); 1320} 1321 1322static u_int16_t 1323show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh) 1324{ 1325 if (vty != NULL) 1326 vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); 1327 else 1328 zlog_info (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length)); 1329 1330 return TLV_SIZE (tlvh); 1331} 1332 1333static u_int16_t 1334ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0, 1335 u_int16_t subtotal, u_int16_t total) 1336{ 1337 struct te_tlv_header *tlvh, *next; 1338 u_int16_t sum = subtotal; 1339 1340 for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) 1341 { 1342 next = NULL; 1343 switch (ntohs (tlvh->type)) 1344 { 1345 case TE_LINK_SUBTLV_LINK_TYPE: 1346 sum += show_vty_link_subtlv_link_type (vty, tlvh); 1347 break; 1348 case TE_LINK_SUBTLV_LINK_ID: 1349 sum += show_vty_link_subtlv_link_id (vty, tlvh); 1350 break; 1351 case TE_LINK_SUBTLV_LCLIF_IPADDR: 1352 sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); 1353 break; 1354 case TE_LINK_SUBTLV_RMTIF_IPADDR: 1355 sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); 1356 break; 1357 case TE_LINK_SUBTLV_TE_METRIC: 1358 sum += show_vty_link_subtlv_te_metric (vty, tlvh); 1359 break; 1360 case TE_LINK_SUBTLV_MAX_BW: 1361 sum += show_vty_link_subtlv_max_bw (vty, tlvh); 1362 break; 1363 case TE_LINK_SUBTLV_MAX_RSV_BW: 1364 sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh); 1365 break; 1366 case TE_LINK_SUBTLV_UNRSV_BW: 1367 sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh); 1368 break; 1369 case TE_LINK_SUBTLV_RSC_CLSCLR: 1370 sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh); 1371 break; 1372 default: 1373 sum += show_vty_unknown_tlv (vty, tlvh); 1374 break; 1375 } 1376 } 1377 return sum; 1378} 1379 1380static void 1381ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa) 1382{ 1383 struct lsa_header *lsah = (struct lsa_header *) lsa->data; 1384 struct te_tlv_header *tlvh, *next; 1385 u_int16_t sum, total; 1386 u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh, 1387 u_int16_t subtotal, u_int16_t total) = NULL; 1388 1389 sum = 0; 1390 total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; 1391 1392 for (tlvh = TLV_HDR_TOP (lsah); sum < total; 1393 tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) 1394 { 1395 if (subfunc != NULL) 1396 { 1397 sum = (* subfunc)(vty, tlvh, sum, total); 1398 next = (struct te_tlv_header *)((char *) tlvh + sum); 1399 subfunc = NULL; 1400 continue; 1401 } 1402 1403 next = NULL; 1404 switch (ntohs (tlvh->type)) 1405 { 1406 case TE_TLV_ROUTER_ADDR: 1407 sum += show_vty_router_addr (vty, tlvh); 1408 break; 1409 case TE_TLV_LINK: 1410 sum += show_vty_link_header (vty, tlvh); 1411 subfunc = ospf_mpls_te_show_link_subtlv; 1412 next = tlvh + 1; 1413 break; 1414 default: 1415 sum += show_vty_unknown_tlv (vty, tlvh); 1416 break; 1417 } 1418 } 1419 return; 1420} 1421 1422static void 1423ospf_mpls_te_config_write_router (struct vty *vty) 1424{ 1425 if (OspfMplsTE.status == enabled) 1426 { 1427 vty_out (vty, " mpls-te%s", VTY_NEWLINE); 1428 vty_out (vty, " mpls-te router-address %s%s", 1429 inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); 1430 } 1431 return; 1432} 1433 1434static void 1435ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) 1436{ 1437 struct mpls_te_link *lp; 1438 1439 if ((OspfMplsTE.status == enabled) 1440 && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) 1441 && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) 1442 { 1443 float fval; 1444 int i; 1445 1446 vty_out (vty, " mpls-te link metric %u%s", 1447 (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); 1448 1449 ntohf (&lp->max_bw.value, &fval); 1450 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) 1451 vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); 1452 1453 ntohf (&lp->max_rsv_bw.value, &fval); 1454 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) 1455 vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); 1456 1457 for (i = 0; i < 8; i++) 1458 { 1459 ntohf (&lp->unrsv_bw.value[i], &fval); 1460 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) 1461 vty_out (vty, " mpls-te link unrsv-bw %d %g%s", 1462 i, fval, VTY_NEWLINE); 1463 } 1464 1465 vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s", 1466 (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE); 1467 } 1468 return; 1469} 1470 1471/*------------------------------------------------------------------------* 1472 * Followings are vty command functions. 1473 *------------------------------------------------------------------------*/ 1474 1475DEFUN (mpls_te, 1476 mpls_te_cmd, 1477 "mpls-te", 1478 "Configure MPLS-TE parameters\n" 1479 "Enable the MPLS-TE functionality\n") 1480{ 1481 listnode node; 1482 struct mpls_te_link *lp; 1483 1484 if (OspfMplsTE.status == enabled) 1485 return CMD_SUCCESS; 1486 1487 if (IS_DEBUG_OSPF_EVENT) 1488 zlog_info ("MPLS-TE: OFF -> ON"); 1489 1490 OspfMplsTE.status = enabled; 1491 1492 /* 1493 * Following code is intended to handle two cases; 1494 * 1495 * 1) MPLS-TE was disabled at startup time, but now become enabled. 1496 * 2) MPLS-TE was once enabled then disabled, and now enabled again. 1497 */ 1498 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 1499 if ((lp = getdata (node)) != NULL) 1500 initialize_linkparams (lp); 1501 1502 ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); 1503 1504 return CMD_SUCCESS; 1505} 1506 1507ALIAS (mpls_te, 1508 mpls_te_on_cmd, 1509 "mpls-te on", 1510 "Configure MPLS-TE parameters\n" 1511 "Enable the MPLS-TE functionality\n") 1512 1513DEFUN (no_mpls_te, 1514 no_mpls_te_cmd, 1515 "no mpls-te", 1516 NO_STR 1517 "Configure MPLS-TE parameters\n" 1518 "Disable the MPLS-TE functionality\n") 1519{ 1520 listnode node; 1521 struct mpls_te_link *lp; 1522 1523 if (OspfMplsTE.status == disabled) 1524 return CMD_SUCCESS; 1525 1526 if (IS_DEBUG_OSPF_EVENT) 1527 zlog_info ("MPLS-TE: ON -> OFF"); 1528 1529 OspfMplsTE.status = disabled; 1530 1531 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 1532 if ((lp = getdata (node)) != NULL) 1533 if (lp->area != NULL) 1534 if (lp->flags & LPFLG_LSA_ENGAGED) 1535 ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); 1536 1537 return CMD_SUCCESS; 1538} 1539 1540DEFUN (mpls_te_router_addr, 1541 mpls_te_router_addr_cmd, 1542 "mpls-te router-address A.B.C.D", 1543 "MPLS-TE specific commands\n" 1544 "Stable IP address of the advertising router\n" 1545 "MPLS-TE router address in IPv4 address format\n") 1546{ 1547 struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; 1548 struct in_addr value; 1549 1550 if (! inet_aton (argv[0], &value)) 1551 { 1552 vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); 1553 return CMD_WARNING; 1554 } 1555 1556 if (ntohs (ra->header.type) == 0 1557 || ntohl (ra->value.s_addr) != ntohl (value.s_addr)) 1558 { 1559 listnode node; 1560 struct mpls_te_link *lp; 1561 int need_to_reoriginate = 0; 1562 1563 set_mpls_te_router_addr (value); 1564 1565 if (OspfMplsTE.status == disabled) 1566 goto out; 1567 1568 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 1569 { 1570 if ((lp = getdata (node)) == NULL) 1571 continue; 1572 if (lp->area == NULL) 1573 continue; 1574 1575 if ((lp->flags & LPFLG_LSA_ENGAGED) == 0) 1576 { 1577 need_to_reoriginate = 1; 1578 break; 1579 } 1580 } 1581 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) 1582 { 1583 if ((lp = getdata (node)) == NULL) 1584 continue; 1585 if (lp->area == NULL) 1586 continue; 1587 1588 if (need_to_reoriginate) 1589 lp->flags |= LPFLG_LSA_FORCED_REFRESH; 1590 else 1591 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 1592 } 1593 1594 if (need_to_reoriginate) 1595 ospf_mpls_te_foreach_area ( 1596 ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); 1597 } 1598out: 1599 return CMD_SUCCESS; 1600} 1601 1602DEFUN (mpls_te_link_metric, 1603 mpls_te_link_metric_cmd, 1604 "mpls-te link metric <0-4294967295>", 1605 "MPLS-TE specific commands\n" 1606 "Configure MPLS-TE link parameters\n" 1607 "Link metric for MPLS-TE purpose\n" 1608 "Metric\n") 1609{ 1610 struct interface *ifp = (struct interface *) vty->index; 1611 struct mpls_te_link *lp; 1612 u_int32_t value; 1613 1614 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) 1615 { 1616 vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE); 1617 return CMD_WARNING; 1618 } 1619 1620 value = strtoul (argv[0], NULL, 10); 1621 1622 if (ntohs (lp->te_metric.header.type) == 0 1623 || ntohl (lp->te_metric.value) != value) 1624 { 1625 set_linkparams_te_metric (lp, value); 1626 1627 if (OspfMplsTE.status == enabled) 1628 if (lp->area != NULL) 1629 { 1630 if (lp->flags & LPFLG_LSA_ENGAGED) 1631 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 1632 else 1633 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); 1634 } 1635 } 1636 return CMD_SUCCESS; 1637} 1638 1639DEFUN (mpls_te_link_maxbw, 1640 mpls_te_link_maxbw_cmd, 1641 "mpls-te link max-bw BANDWIDTH", 1642 "MPLS-TE specific commands\n" 1643 "Configure MPLS-TE link parameters\n" 1644 "Maximum bandwidth that can be used\n" 1645 "Bytes/second (IEEE floating point format)\n") 1646{ 1647 struct interface *ifp = (struct interface *) vty->index; 1648 struct mpls_te_link *lp; 1649 float f1, f2; 1650 1651 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) 1652 { 1653 vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE); 1654 return CMD_WARNING; 1655 } 1656 1657 ntohf (&lp->max_bw.value, &f1); 1658 if (sscanf (argv[0], "%g", &f2) != 1) 1659 { 1660 vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); 1661 return CMD_WARNING; 1662 } 1663 1664 if (ntohs (lp->max_bw.header.type) == 0 1665 || f1 != f2) 1666 { 1667 set_linkparams_max_bw (lp, &f2); 1668 1669 if (OspfMplsTE.status == enabled) 1670 if (lp->area != NULL) 1671 { 1672 if (lp->flags & LPFLG_LSA_ENGAGED) 1673 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 1674 else 1675 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); 1676 } 1677 } 1678 return CMD_SUCCESS; 1679} 1680 1681DEFUN (mpls_te_link_max_rsv_bw, 1682 mpls_te_link_max_rsv_bw_cmd, 1683 "mpls-te link max-rsv-bw BANDWIDTH", 1684 "MPLS-TE specific commands\n" 1685 "Configure MPLS-TE link parameters\n" 1686 "Maximum bandwidth that may be reserved\n" 1687 "Bytes/second (IEEE floating point format)\n") 1688{ 1689 struct interface *ifp = (struct interface *) vty->index; 1690 struct mpls_te_link *lp; 1691 float f1, f2; 1692 1693 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) 1694 { 1695 vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE); 1696 return CMD_WARNING; 1697 } 1698 1699 ntohf (&lp->max_rsv_bw.value, &f1); 1700 if (sscanf (argv[0], "%g", &f2) != 1) 1701 { 1702 vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); 1703 return CMD_WARNING; 1704 } 1705 1706 if (ntohs (lp->max_rsv_bw.header.type) == 0 1707 || f1 != f2) 1708 { 1709 set_linkparams_max_rsv_bw (lp, &f2); 1710 1711 if (OspfMplsTE.status == enabled) 1712 if (lp->area != NULL) 1713 { 1714 if (lp->flags & LPFLG_LSA_ENGAGED) 1715 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 1716 else 1717 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); 1718 } 1719 } 1720 return CMD_SUCCESS; 1721} 1722 1723DEFUN (mpls_te_link_unrsv_bw, 1724 mpls_te_link_unrsv_bw_cmd, 1725 "mpls-te link unrsv-bw <0-7> BANDWIDTH", 1726 "MPLS-TE specific commands\n" 1727 "Configure MPLS-TE link parameters\n" 1728 "Unreserved bandwidth at each priority level\n" 1729 "Priority\n" 1730 "Bytes/second (IEEE floating point format)\n") 1731{ 1732 struct interface *ifp = (struct interface *) vty->index; 1733 struct mpls_te_link *lp; 1734 int priority; 1735 float f1, f2; 1736 1737 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) 1738 { 1739 vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE); 1740 return CMD_WARNING; 1741 } 1742 1743 /* We don't have to consider about range check here. */ 1744 if (sscanf (argv[0], "%d", &priority) != 1) 1745 { 1746 vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); 1747 return CMD_WARNING; 1748 } 1749 1750 ntohf (&lp->unrsv_bw.value [priority], &f1); 1751 if (sscanf (argv[1], "%g", &f2) != 1) 1752 { 1753 vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); 1754 return CMD_WARNING; 1755 } 1756 1757 if (ntohs (lp->unrsv_bw.header.type) == 0 1758 || f1 != f2) 1759 { 1760 set_linkparams_unrsv_bw (lp, priority, &f2); 1761 1762 if (OspfMplsTE.status == enabled) 1763 if (lp->area != NULL) 1764 { 1765 if (lp->flags & LPFLG_LSA_ENGAGED) 1766 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 1767 else 1768 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); 1769 } 1770 } 1771 return CMD_SUCCESS; 1772} 1773 1774DEFUN (mpls_te_link_rsc_clsclr, 1775 mpls_te_link_rsc_clsclr_cmd, 1776 "mpls-te link rsc-clsclr BITPATTERN", 1777 "MPLS-TE specific commands\n" 1778 "Configure MPLS-TE link parameters\n" 1779 "Administrative group membership\n" 1780 "32-bit Hexadecimal value (ex. 0xa1)\n") 1781{ 1782 struct interface *ifp = (struct interface *) vty->index; 1783 struct mpls_te_link *lp; 1784 unsigned long value; 1785 1786 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) 1787 { 1788 vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE); 1789 return CMD_WARNING; 1790 } 1791 1792 if (sscanf (argv[0], "0x%lx", &value) != 1) 1793 { 1794 vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", strerror (errno), VTY_NEWLINE); 1795 return CMD_WARNING; 1796 } 1797 1798 if (ntohs (lp->rsc_clsclr.header.type) == 0 1799 || ntohl (lp->rsc_clsclr.value) != value) 1800 { 1801 set_linkparams_rsc_clsclr (lp, value); 1802 1803 if (OspfMplsTE.status == enabled) 1804 if (lp->area != NULL) 1805 { 1806 if (lp->flags & LPFLG_LSA_ENGAGED) 1807 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); 1808 else 1809 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); 1810 } 1811 } 1812 return CMD_SUCCESS; 1813} 1814 1815DEFUN (show_mpls_te_router, 1816 show_mpls_te_router_cmd, 1817 "show mpls-te router", 1818 SHOW_STR 1819 "MPLS-TE information\n" 1820 "Router information\n") 1821{ 1822 if (OspfMplsTE.status == enabled) 1823 { 1824 vty_out (vty, "--- MPLS-TE router parameters ---%s", 1825 VTY_NEWLINE); 1826 1827 if (ntohs (OspfMplsTE.router_addr.header.type) != 0) 1828 show_vty_router_addr (vty, &OspfMplsTE.router_addr.header); 1829 else if (vty != NULL) 1830 vty_out (vty, " N/A%s", VTY_NEWLINE); 1831 } 1832 return CMD_SUCCESS; 1833} 1834 1835static void 1836show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) 1837{ 1838 struct mpls_te_link *lp; 1839 struct te_tlv_header *tlvh; 1840 1841 if ((OspfMplsTE.status == enabled) 1842 && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) 1843 && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) 1844 { 1845 vty_out (vty, "-- MPLS-TE link parameters for %s --%s", 1846 ifp->name, VTY_NEWLINE); 1847 1848 show_vty_link_subtlv_link_type (vty, &lp->link_type.header); 1849 show_vty_link_subtlv_link_id (vty, &lp->link_id.header); 1850 1851 if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL) 1852 show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); 1853 if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL) 1854 show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); 1855 1856 show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); 1857 1858 show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); 1859 show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); 1860 show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); 1861 show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); 1862 } 1863 else 1864 { 1865 vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", 1866 ifp->name, VTY_NEWLINE); 1867 } 1868 1869 return; 1870} 1871 1872DEFUN (show_mpls_te_link, 1873 show_mpls_te_link_cmd, 1874 "show mpls-te interface [INTERFACE]", 1875 SHOW_STR 1876 "MPLS-TE information\n" 1877 "Interface information\n" 1878 "Interface name\n") 1879{ 1880 struct interface *ifp; 1881 listnode node; 1882 1883 /* Show All Interfaces. */ 1884 if (argc == 0) 1885 for (node = listhead (iflist); node; nextnode (node)) 1886 show_mpls_te_link_sub (vty, node->data); 1887 /* Interface name is specified. */ 1888 else 1889 { 1890 if ((ifp = if_lookup_by_name (argv[0])) == NULL) 1891 vty_out (vty, "No such interface name%s", VTY_NEWLINE); 1892 else 1893 show_mpls_te_link_sub (vty, ifp); 1894 } 1895 1896 return CMD_SUCCESS; 1897} 1898 1899static void 1900ospf_mpls_te_register_vty (void) 1901{ 1902 install_element (VIEW_NODE, &show_mpls_te_router_cmd); 1903 install_element (VIEW_NODE, &show_mpls_te_link_cmd); 1904 install_element (ENABLE_NODE, &show_mpls_te_router_cmd); 1905 install_element (ENABLE_NODE, &show_mpls_te_link_cmd); 1906 1907 install_element (OSPF_NODE, &mpls_te_cmd); 1908 install_element (OSPF_NODE, &no_mpls_te_cmd); 1909 install_element (OSPF_NODE, &mpls_te_on_cmd); 1910 install_element (OSPF_NODE, &mpls_te_router_addr_cmd); 1911 1912 install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd); 1913 install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd); 1914 install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd); 1915 install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd); 1916 install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd); 1917 1918 return; 1919} 1920 1921#endif /* HAVE_OSPF_TE */ 1922