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