blob: 1a9946d40bacfd25631dad8e88804b7390c97bf4 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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. */
pauld4a53d52003-07-12 21:30:57 +0000417 if ((nbr = ospf_nbr_lookup_ptop (oi))
418 && nbr->state == NSM_Full)
paul718e3742002-12-13 20:15:29 +0000419 {
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))
pauld4a53d52003-07-12 21:30:57 +0000432 && ospf_nbr_count (oi, NSM_Full) > 0))
paul718e3742002-12-13 20:15:29 +0000433 {
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 }
pauld4a53d52003-07-12 21:30:57 +0000631 if (oi->area == NULL || oi->area->ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000632 {
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);
pauld4a53d52003-07-12 21:30:57 +0000881 options |= LSA_OPTIONS_NSSA_GET (area);
paul718e3742002-12-13 20:15:29 +0000882 options |= OSPF_OPTION_O; /* Don't forget this :-) */
883
884 lsa_type = OSPF_OPAQUE_AREA_LSA;
885 tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance);
886 lsa_id.s_addr = htonl (tmp);
887
888 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
889 zlog_info ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id));
890
891 /* Set opaque-LSA header fields. */
pauld4a53d52003-07-12 21:30:57 +0000892 lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id);
paul718e3742002-12-13 20:15:29 +0000893
894 /* Set opaque-LSA body fields. */
895 ospf_mpls_te_lsa_body_set (s, lp);
896
897 /* Set length. */
898 length = stream_get_endp (s);
899 lsah->length = htons (length);
900
901 /* Now, create an OSPF LSA instance. */
902 if ((new = ospf_lsa_new ()) == NULL)
903 {
904 zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?");
905 stream_free (s);
906 goto out;
907 }
908 if ((new->data = ospf_lsa_data_new (length)) == NULL)
909 {
910 zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?");
911 ospf_lsa_free (new);
912 new = NULL;
913 stream_free (s);
914 goto out;
915 }
916
917 new->area = area;
918 SET_FLAG (new->flags, OSPF_LSA_SELF);
919 memcpy (new->data, lsah, length);
920 stream_free (s);
921
922out:
923 return new;
924}
925
926static int
927ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp)
928{
929 struct ospf_lsa *new;
930 int rc = -1;
931
932 /* Create new Opaque-LSA/MPLS-TE instance. */
933 if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
934 {
935 zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?");
936 goto out;
937 }
938
939 /* Install this LSA into LSDB. */
pauld4a53d52003-07-12 21:30:57 +0000940 if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL)
paul718e3742002-12-13 20:15:29 +0000941 {
942 zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?");
943 ospf_lsa_free (new);
944 goto out;
945 }
946
947 /* Now this linkparameter entry has associated LSA. */
948 lp->flags |= LPFLG_LSA_ENGAGED;
949
950 /* Update new LSA origination count. */
pauld4a53d52003-07-12 21:30:57 +0000951 area->ospf->lsa_originate_count++;
paul718e3742002-12-13 20:15:29 +0000952
953 /* Flood new LSA through area. */
954 ospf_flood_through_area (area, NULL/*nbr*/, new);
955
956 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
957 {
958 char area_id[INET_ADDRSTRLEN];
959 strcpy (area_id, inet_ntoa (area->area_id));
960 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);
961 ospf_lsa_header_dump (new->data);
962 }
963
964 rc = 0;
965out:
966 return rc;
967}
968
969static int
970ospf_mpls_te_lsa_originate (void *arg)
971{
972 struct ospf_area *area = (struct ospf_area *) arg;
973 listnode node;
974 struct mpls_te_link *lp;
975 int rc = -1;
976
977 if (OspfMplsTE.status == disabled)
978 {
979 zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now.");
980 rc = 0; /* This is not an error case. */
981 goto out;
982 }
983
984 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
985 {
986 if ((lp = getdata (node)) == NULL)
987 continue;
988 if (lp->area == NULL)
989 continue;
990 if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id))
991 continue;
992
993 if (lp->flags & LPFLG_LSA_ENGAGED)
994 {
995 if (lp->flags & LPFLG_LSA_FORCED_REFRESH)
996 {
997 lp->flags &= ~LPFLG_LSA_FORCED_REFRESH;
998 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
999 }
1000 continue;
1001 }
1002 if (! is_mandated_params_set (lp))
1003 {
1004 zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?");
1005 continue;
1006 }
1007
1008 /* Ok, let's try to originate an LSA for this area and Link. */
1009 if (ospf_mpls_te_lsa_originate1 (area, lp) != 0)
1010 goto out;
1011 }
1012
1013 rc = 0;
1014out:
1015 return rc;
1016}
1017
1018static void
1019ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa)
1020{
1021 struct mpls_te_link *lp;
1022 struct ospf_area *area = lsa->area;
1023 struct ospf_lsa *new = NULL;
1024
1025 if (OspfMplsTE.status == disabled)
1026 {
1027 /*
1028 * This LSA must have flushed before due to MPLS-TE status change.
1029 * It seems a slip among routers in the routing domain.
1030 */
1031 zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now.");
1032 lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
1033 }
1034
1035 /* At first, resolve lsa/lp relationship. */
1036 if ((lp = lookup_linkparams_by_instance (lsa)) == NULL)
1037 {
1038 zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?");
1039 lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
1040 }
1041
1042 /* If the lsa's age reached to MaxAge, start flushing procedure. */
1043 if (IS_LSA_MAXAGE (lsa))
1044 {
1045 lp->flags &= ~LPFLG_LSA_ENGAGED;
1046 ospf_opaque_lsa_flush_schedule (lsa);
1047 goto out;
1048 }
1049
1050 /* Create new Opaque-LSA/MPLS-TE instance. */
1051 if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
1052 {
1053 zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?");
1054 goto out;
1055 }
1056 new->data->ls_seqnum = lsa_seqnum_increment (lsa);
1057
1058 /* Install this LSA into LSDB. */
1059 /* Given "lsa" will be freed in the next function. */
pauld4a53d52003-07-12 21:30:57 +00001060 if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL)
paul718e3742002-12-13 20:15:29 +00001061 {
1062 zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?");
1063 ospf_lsa_free (new);
1064 goto out;
1065 }
1066
1067 /* Flood updated LSA through area. */
1068 ospf_flood_through_area (area, NULL/*nbr*/, new);
1069
1070 /* Debug logging. */
1071 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
1072 {
1073 zlog_info ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE",
1074 new->data->type, inet_ntoa (new->data->id));
1075 ospf_lsa_header_dump (new->data);
1076 }
1077
1078out:
1079 return;
1080}
1081
1082static void
1083ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp,
1084 enum sched_opcode opcode)
1085{
1086 struct ospf_lsa lsa;
1087 struct lsa_header lsah;
1088 u_int32_t tmp;
1089
1090 memset (&lsa, 0, sizeof (lsa));
1091 memset (&lsah, 0, sizeof (lsah));
1092
1093 lsa.area = lp->area;
1094 lsa.data = &lsah;
1095 lsah.type = OSPF_OPAQUE_AREA_LSA;
1096 tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance);
1097 lsah.id.s_addr = htonl (tmp);
1098
1099 switch (opcode)
1100 {
1101 case REORIGINATE_PER_AREA:
1102 ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area,
1103 OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
1104 break;
1105 case REFRESH_THIS_LSA:
1106 ospf_opaque_lsa_refresh_schedule (&lsa);
1107 break;
1108 case FLUSH_THIS_LSA:
1109 lp->flags &= ~LPFLG_LSA_ENGAGED;
1110 ospf_opaque_lsa_flush_schedule (&lsa);
1111 break;
1112 default:
1113 zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode);
1114 break;
1115 }
1116
1117 return;
1118}
1119
1120/*------------------------------------------------------------------------*
1121 * Followings are vty session control functions.
1122 *------------------------------------------------------------------------*/
1123
1124static u_int16_t
1125show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh)
1126{
1127 struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh;
1128
1129 if (vty != NULL)
1130 vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
1131 else
1132 zlog_info (" Router-Address: %s", inet_ntoa (top->value));
1133
1134 return TLV_SIZE (tlvh);
1135}
1136
1137static u_int16_t
1138show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh)
1139{
1140 struct te_tlv_link *top = (struct te_tlv_link *) tlvh;
1141
1142 if (vty != NULL)
1143 vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE);
1144 else
1145 zlog_info (" Link: %u octets of data", ntohs (top->header.length));
1146
1147 return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */
1148}
1149
1150static u_int16_t
1151show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh)
1152{
1153 struct te_link_subtlv_link_type *top;
1154 const char *cp = "Unknown";
1155
1156 top = (struct te_link_subtlv_link_type *) tlvh;
1157 switch (top->link_type.value)
1158 {
1159 case LINK_TYPE_SUBTLV_VALUE_PTP:
1160 cp = "Point-to-point";
1161 break;
1162 case LINK_TYPE_SUBTLV_VALUE_MA:
1163 cp = "Multiaccess";
1164 break;
1165 default:
1166 break;
1167 }
1168
1169 if (vty != NULL)
1170 vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE);
1171 else
1172 zlog_info (" Link-Type: %s (%u)", cp, top->link_type.value);
1173
1174 return TLV_SIZE (tlvh);
1175}
1176
1177static u_int16_t
1178show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh)
1179{
1180 struct te_link_subtlv_link_id *top;
1181
1182 top = (struct te_link_subtlv_link_id *) tlvh;
1183 if (vty != NULL)
1184 vty_out (vty, " Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
1185 else
1186 zlog_info (" Link-ID: %s", inet_ntoa (top->value));
1187
1188 return TLV_SIZE (tlvh);
1189}
1190
1191static u_int16_t
1192show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
1193{
1194 struct te_link_subtlv_lclif_ipaddr *top;
1195 int i, n;
1196
1197 top = (struct te_link_subtlv_lclif_ipaddr *) tlvh;
1198 n = ntohs (tlvh->length) / sizeof (top->value[0]);
1199
1200 if (vty != NULL)
1201 vty_out (vty, " Local Interface IP Address(es): %d%s", n, VTY_NEWLINE);
1202 else
1203 zlog_info (" Local Interface IP Address(es): %d", n);
1204
1205 for (i = 0; i < n; i++)
1206 {
1207 if (vty != NULL)
1208 vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
1209 else
1210 zlog_info (" #%d: %s", i, inet_ntoa (top->value[i]));
1211 }
1212 return TLV_SIZE (tlvh);
1213}
1214
1215static u_int16_t
1216show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
1217{
1218 struct te_link_subtlv_rmtif_ipaddr *top;
1219 int i, n;
1220
1221 top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh;
1222 n = ntohs (tlvh->length) / sizeof (top->value[0]);
1223 if (vty != NULL)
1224 vty_out (vty, " Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE);
1225 else
1226 zlog_info (" Remote Interface IP Address(es): %d", n);
1227
1228 for (i = 0; i < n; i++)
1229 {
1230 if (vty != NULL)
1231 vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
1232 else
1233 zlog_info (" #%d: %s", i, inet_ntoa (top->value[i]));
1234 }
1235 return TLV_SIZE (tlvh);
1236}
1237
1238static u_int16_t
1239show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh)
1240{
1241 struct te_link_subtlv_te_metric *top;
1242
1243 top = (struct te_link_subtlv_te_metric *) tlvh;
1244 if (vty != NULL)
1245 vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
1246 else
1247 zlog_info (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value));
1248
1249 return TLV_SIZE (tlvh);
1250}
1251
1252static u_int16_t
1253show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh)
1254{
1255 struct te_link_subtlv_max_bw *top;
1256 float fval;
1257
1258 top = (struct te_link_subtlv_max_bw *) tlvh;
1259 ntohf (&top->value, &fval);
1260
1261 if (vty != NULL)
1262 vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
1263 else
1264 zlog_info (" Maximum Bandwidth: %g (Bytes/sec)", fval);
1265
1266 return TLV_SIZE (tlvh);
1267}
1268
1269static u_int16_t
1270show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
1271{
1272 struct te_link_subtlv_max_rsv_bw *top;
1273 float fval;
1274
1275 top = (struct te_link_subtlv_max_rsv_bw *) tlvh;
1276 ntohf (&top->value, &fval);
1277
1278 if (vty != NULL)
1279 vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
1280 else
1281 zlog_info (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval);
1282
1283 return TLV_SIZE (tlvh);
1284}
1285
1286static u_int16_t
1287show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
1288{
1289 struct te_link_subtlv_unrsv_bw *top;
1290 float fval;
1291 int i;
1292
1293 top = (struct te_link_subtlv_unrsv_bw *) tlvh;
1294 for (i = 0; i < 8; i++)
1295 {
1296 ntohf (&top->value[i], &fval);
1297 if (vty != NULL)
1298 vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE);
1299 else
1300 zlog_info (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval);
1301 }
1302
1303 return TLV_SIZE (tlvh);
1304}
1305
1306static u_int16_t
1307show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh)
1308{
1309 struct te_link_subtlv_rsc_clsclr *top;
1310
1311 top = (struct te_link_subtlv_rsc_clsclr *) tlvh;
1312 if (vty != NULL)
1313 vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
1314 else
1315 zlog_info (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value));
1316
1317 return TLV_SIZE (tlvh);
1318}
1319
1320static u_int16_t
1321show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh)
1322{
1323 if (vty != NULL)
1324 vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE);
1325 else
1326 zlog_info (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length));
1327
1328 return TLV_SIZE (tlvh);
1329}
1330
1331static u_int16_t
1332ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0,
1333 u_int16_t subtotal, u_int16_t total)
1334{
1335 struct te_tlv_header *tlvh, *next;
1336 u_int16_t sum = subtotal;
1337
1338 for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
1339 {
1340 next = NULL;
1341 switch (ntohs (tlvh->type))
1342 {
1343 case TE_LINK_SUBTLV_LINK_TYPE:
1344 sum += show_vty_link_subtlv_link_type (vty, tlvh);
1345 break;
1346 case TE_LINK_SUBTLV_LINK_ID:
1347 sum += show_vty_link_subtlv_link_id (vty, tlvh);
1348 break;
1349 case TE_LINK_SUBTLV_LCLIF_IPADDR:
1350 sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
1351 break;
1352 case TE_LINK_SUBTLV_RMTIF_IPADDR:
1353 sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
1354 break;
1355 case TE_LINK_SUBTLV_TE_METRIC:
1356 sum += show_vty_link_subtlv_te_metric (vty, tlvh);
1357 break;
1358 case TE_LINK_SUBTLV_MAX_BW:
1359 sum += show_vty_link_subtlv_max_bw (vty, tlvh);
1360 break;
1361 case TE_LINK_SUBTLV_MAX_RSV_BW:
1362 sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh);
1363 break;
1364 case TE_LINK_SUBTLV_UNRSV_BW:
1365 sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh);
1366 break;
1367 case TE_LINK_SUBTLV_RSC_CLSCLR:
1368 sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh);
1369 break;
1370 default:
1371 sum += show_vty_unknown_tlv (vty, tlvh);
1372 break;
1373 }
1374 }
1375 return sum;
1376}
1377
1378static void
1379ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa)
1380{
1381 struct lsa_header *lsah = (struct lsa_header *) lsa->data;
1382 struct te_tlv_header *tlvh, *next;
1383 u_int16_t sum, total;
1384 u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh,
1385 u_int16_t subtotal, u_int16_t total) = NULL;
1386
1387 sum = 0;
1388 total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE;
1389
1390 for (tlvh = TLV_HDR_TOP (lsah); sum < total;
1391 tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
1392 {
1393 if (subfunc != NULL)
1394 {
1395 sum = (* subfunc)(vty, tlvh, sum, total);
1396 next = (struct te_tlv_header *)((char *) tlvh + sum);
1397 subfunc = NULL;
1398 continue;
1399 }
1400
1401 next = NULL;
1402 switch (ntohs (tlvh->type))
1403 {
1404 case TE_TLV_ROUTER_ADDR:
1405 sum += show_vty_router_addr (vty, tlvh);
1406 break;
1407 case TE_TLV_LINK:
1408 sum += show_vty_link_header (vty, tlvh);
1409 subfunc = ospf_mpls_te_show_link_subtlv;
1410 next = tlvh + 1;
1411 break;
1412 default:
1413 sum += show_vty_unknown_tlv (vty, tlvh);
1414 break;
1415 }
1416 }
1417 return;
1418}
1419
1420static void
1421ospf_mpls_te_config_write_router (struct vty *vty)
1422{
1423 if (OspfMplsTE.status == enabled)
1424 {
1425 vty_out (vty, " mpls-te%s", VTY_NEWLINE);
1426 vty_out (vty, " mpls-te router-address %s%s",
1427 inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE);
1428 }
1429 return;
1430}
1431
1432static void
1433ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp)
1434{
1435 struct mpls_te_link *lp;
1436
1437 if ((OspfMplsTE.status == enabled)
1438 && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
1439 && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
1440 {
1441 float fval;
1442 int i;
1443
1444 vty_out (vty, " mpls-te link metric %u%s",
1445 (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE);
1446
1447 ntohf (&lp->max_bw.value, &fval);
1448 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
1449 vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE);
1450
1451 ntohf (&lp->max_rsv_bw.value, &fval);
1452 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
1453 vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE);
1454
1455 for (i = 0; i < 8; i++)
1456 {
1457 ntohf (&lp->unrsv_bw.value[i], &fval);
1458 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
1459 vty_out (vty, " mpls-te link unrsv-bw %d %g%s",
1460 i, fval, VTY_NEWLINE);
1461 }
1462
1463 vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s",
1464 (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE);
1465 }
1466 return;
1467}
1468
1469/*------------------------------------------------------------------------*
1470 * Followings are vty command functions.
1471 *------------------------------------------------------------------------*/
1472
1473DEFUN (mpls_te,
1474 mpls_te_cmd,
1475 "mpls-te",
1476 "Configure MPLS-TE parameters\n"
1477 "Enable the MPLS-TE functionality\n")
1478{
1479 listnode node;
1480 struct mpls_te_link *lp;
1481
1482 if (OspfMplsTE.status == enabled)
1483 return CMD_SUCCESS;
1484
1485 if (IS_DEBUG_OSPF_EVENT)
1486 zlog_info ("MPLS-TE: OFF -> ON");
1487
1488 OspfMplsTE.status = enabled;
1489
1490 /*
1491 * Following code is intended to handle two cases;
1492 *
1493 * 1) MPLS-TE was disabled at startup time, but now become enabled.
1494 * 2) MPLS-TE was once enabled then disabled, and now enabled again.
1495 */
1496 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
1497 if ((lp = getdata (node)) != NULL)
1498 initialize_linkparams (lp);
1499
1500 ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
1501
1502 return CMD_SUCCESS;
1503}
1504
1505ALIAS (mpls_te,
1506 mpls_te_on_cmd,
1507 "mpls-te on",
1508 "Configure MPLS-TE parameters\n"
1509 "Enable the MPLS-TE functionality\n")
1510
1511DEFUN (no_mpls_te,
1512 no_mpls_te_cmd,
1513 "no mpls-te",
1514 NO_STR
1515 "Configure MPLS-TE parameters\n"
1516 "Disable the MPLS-TE functionality\n")
1517{
1518 listnode node;
1519 struct mpls_te_link *lp;
1520
1521 if (OspfMplsTE.status == disabled)
1522 return CMD_SUCCESS;
1523
1524 if (IS_DEBUG_OSPF_EVENT)
1525 zlog_info ("MPLS-TE: ON -> OFF");
1526
1527 OspfMplsTE.status = disabled;
1528
1529 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
1530 if ((lp = getdata (node)) != NULL)
1531 if (lp->area != NULL)
1532 if (lp->flags & LPFLG_LSA_ENGAGED)
1533 ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
1534
1535 return CMD_SUCCESS;
1536}
1537
1538DEFUN (mpls_te_router_addr,
1539 mpls_te_router_addr_cmd,
1540 "mpls-te router-address A.B.C.D",
1541 "MPLS-TE specific commands\n"
1542 "Stable IP address of the advertising router\n"
1543 "MPLS-TE router address in IPv4 address format\n")
1544{
1545 struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr;
1546 struct in_addr value;
1547
1548 if (! inet_aton (argv[0], &value))
1549 {
1550 vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE);
1551 return CMD_WARNING;
1552 }
1553
1554 if (ntohs (ra->header.type) == 0
1555 || ntohl (ra->value.s_addr) != ntohl (value.s_addr))
1556 {
1557 listnode node;
1558 struct mpls_te_link *lp;
1559 int need_to_reoriginate = 0;
1560
1561 set_mpls_te_router_addr (value);
1562
1563 if (OspfMplsTE.status == disabled)
1564 goto out;
1565
1566 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
1567 {
1568 if ((lp = getdata (node)) == NULL)
1569 continue;
1570 if (lp->area == NULL)
1571 continue;
1572
1573 if ((lp->flags & LPFLG_LSA_ENGAGED) == 0)
1574 {
1575 need_to_reoriginate = 1;
1576 break;
1577 }
1578 }
1579 for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
1580 {
1581 if ((lp = getdata (node)) == NULL)
1582 continue;
1583 if (lp->area == NULL)
1584 continue;
1585
1586 if (need_to_reoriginate)
1587 lp->flags |= LPFLG_LSA_FORCED_REFRESH;
1588 else
1589 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1590 }
1591
1592 if (need_to_reoriginate)
1593 ospf_mpls_te_foreach_area (
1594 ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
1595 }
1596out:
1597 return CMD_SUCCESS;
1598}
1599
1600DEFUN (mpls_te_link_metric,
1601 mpls_te_link_metric_cmd,
1602 "mpls-te link metric <0-4294967295>",
1603 "MPLS-TE specific commands\n"
1604 "Configure MPLS-TE link parameters\n"
1605 "Link metric for MPLS-TE purpose\n"
1606 "Metric\n")
1607{
1608 struct interface *ifp = (struct interface *) vty->index;
1609 struct mpls_te_link *lp;
1610 u_int32_t value;
1611
1612 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1613 {
1614 vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE);
1615 return CMD_WARNING;
1616 }
1617
1618 value = strtoul (argv[0], NULL, 10);
1619
1620 if (ntohs (lp->te_metric.header.type) == 0
1621 || ntohl (lp->te_metric.value) != value)
1622 {
1623 set_linkparams_te_metric (lp, value);
1624
1625 if (OspfMplsTE.status == enabled)
1626 if (lp->area != NULL)
1627 {
1628 if (lp->flags & LPFLG_LSA_ENGAGED)
1629 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1630 else
1631 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1632 }
1633 }
1634 return CMD_SUCCESS;
1635}
1636
1637DEFUN (mpls_te_link_maxbw,
1638 mpls_te_link_maxbw_cmd,
1639 "mpls-te link max-bw BANDWIDTH",
1640 "MPLS-TE specific commands\n"
1641 "Configure MPLS-TE link parameters\n"
1642 "Maximum bandwidth that can be used\n"
1643 "Bytes/second (IEEE floating point format)\n")
1644{
1645 struct interface *ifp = (struct interface *) vty->index;
1646 struct mpls_te_link *lp;
1647 float f1, f2;
1648
1649 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1650 {
1651 vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE);
1652 return CMD_WARNING;
1653 }
1654
1655 ntohf (&lp->max_bw.value, &f1);
1656 if (sscanf (argv[0], "%g", &f2) != 1)
1657 {
1658 vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
1659 return CMD_WARNING;
1660 }
1661
1662 if (ntohs (lp->max_bw.header.type) == 0
1663 || f1 != f2)
1664 {
1665 set_linkparams_max_bw (lp, &f2);
1666
1667 if (OspfMplsTE.status == enabled)
1668 if (lp->area != NULL)
1669 {
1670 if (lp->flags & LPFLG_LSA_ENGAGED)
1671 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1672 else
1673 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1674 }
1675 }
1676 return CMD_SUCCESS;
1677}
1678
1679DEFUN (mpls_te_link_max_rsv_bw,
1680 mpls_te_link_max_rsv_bw_cmd,
1681 "mpls-te link max-rsv-bw BANDWIDTH",
1682 "MPLS-TE specific commands\n"
1683 "Configure MPLS-TE link parameters\n"
1684 "Maximum bandwidth that may be reserved\n"
1685 "Bytes/second (IEEE floating point format)\n")
1686{
1687 struct interface *ifp = (struct interface *) vty->index;
1688 struct mpls_te_link *lp;
1689 float f1, f2;
1690
1691 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1692 {
1693 vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE);
1694 return CMD_WARNING;
1695 }
1696
1697 ntohf (&lp->max_rsv_bw.value, &f1);
1698 if (sscanf (argv[0], "%g", &f2) != 1)
1699 {
1700 vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
1701 return CMD_WARNING;
1702 }
1703
1704 if (ntohs (lp->max_rsv_bw.header.type) == 0
1705 || f1 != f2)
1706 {
1707 set_linkparams_max_rsv_bw (lp, &f2);
1708
1709 if (OspfMplsTE.status == enabled)
1710 if (lp->area != NULL)
1711 {
1712 if (lp->flags & LPFLG_LSA_ENGAGED)
1713 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1714 else
1715 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1716 }
1717 }
1718 return CMD_SUCCESS;
1719}
1720
1721DEFUN (mpls_te_link_unrsv_bw,
1722 mpls_te_link_unrsv_bw_cmd,
1723 "mpls-te link unrsv-bw <0-7> BANDWIDTH",
1724 "MPLS-TE specific commands\n"
1725 "Configure MPLS-TE link parameters\n"
1726 "Unreserved bandwidth at each priority level\n"
1727 "Priority\n"
1728 "Bytes/second (IEEE floating point format)\n")
1729{
1730 struct interface *ifp = (struct interface *) vty->index;
1731 struct mpls_te_link *lp;
1732 int priority;
1733 float f1, f2;
1734
1735 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1736 {
1737 vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE);
1738 return CMD_WARNING;
1739 }
1740
1741 /* We don't have to consider about range check here. */
1742 if (sscanf (argv[0], "%d", &priority) != 1)
1743 {
1744 vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
1745 return CMD_WARNING;
1746 }
1747
1748 ntohf (&lp->unrsv_bw.value [priority], &f1);
1749 if (sscanf (argv[1], "%g", &f2) != 1)
1750 {
1751 vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
1752 return CMD_WARNING;
1753 }
1754
1755 if (ntohs (lp->unrsv_bw.header.type) == 0
1756 || f1 != f2)
1757 {
1758 set_linkparams_unrsv_bw (lp, priority, &f2);
1759
1760 if (OspfMplsTE.status == enabled)
1761 if (lp->area != NULL)
1762 {
1763 if (lp->flags & LPFLG_LSA_ENGAGED)
1764 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1765 else
1766 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1767 }
1768 }
1769 return CMD_SUCCESS;
1770}
1771
1772DEFUN (mpls_te_link_rsc_clsclr,
1773 mpls_te_link_rsc_clsclr_cmd,
1774 "mpls-te link rsc-clsclr BITPATTERN",
1775 "MPLS-TE specific commands\n"
1776 "Configure MPLS-TE link parameters\n"
1777 "Administrative group membership\n"
1778 "32-bit Hexadecimal value (ex. 0xa1)\n")
1779{
1780 struct interface *ifp = (struct interface *) vty->index;
1781 struct mpls_te_link *lp;
1782 unsigned long value;
1783
1784 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1785 {
1786 vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE);
1787 return CMD_WARNING;
1788 }
1789
1790 if (sscanf (argv[0], "0x%lx", &value) != 1)
1791 {
1792 vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
1793 return CMD_WARNING;
1794 }
1795
1796 if (ntohs (lp->rsc_clsclr.header.type) == 0
1797 || ntohl (lp->rsc_clsclr.value) != value)
1798 {
1799 set_linkparams_rsc_clsclr (lp, value);
1800
1801 if (OspfMplsTE.status == enabled)
1802 if (lp->area != NULL)
1803 {
1804 if (lp->flags & LPFLG_LSA_ENGAGED)
1805 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1806 else
1807 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1808 }
1809 }
1810 return CMD_SUCCESS;
1811}
1812
1813DEFUN (show_mpls_te_router,
1814 show_mpls_te_router_cmd,
1815 "show mpls-te router",
1816 SHOW_STR
1817 "MPLS-TE information\n"
1818 "Router information\n")
1819{
1820 if (OspfMplsTE.status == enabled)
1821 {
1822 vty_out (vty, "--- MPLS-TE router parameters ---%s",
1823 VTY_NEWLINE);
1824
1825 if (ntohs (OspfMplsTE.router_addr.header.type) != 0)
1826 show_vty_router_addr (vty, &OspfMplsTE.router_addr.header);
1827 else if (vty != NULL)
1828 vty_out (vty, " N/A%s", VTY_NEWLINE);
1829 }
1830 return CMD_SUCCESS;
1831}
1832
1833static void
1834show_mpls_te_link_sub (struct vty *vty, struct interface *ifp)
1835{
1836 struct mpls_te_link *lp;
1837 struct te_tlv_header *tlvh;
1838
1839 if ((OspfMplsTE.status == enabled)
1840 && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
1841 && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
1842 {
1843 vty_out (vty, "-- MPLS-TE link parameters for %s --%s",
1844 ifp->name, VTY_NEWLINE);
1845
1846 show_vty_link_subtlv_link_type (vty, &lp->link_type.header);
1847 show_vty_link_subtlv_link_id (vty, &lp->link_id.header);
1848
1849 if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL)
1850 show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
1851 if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL)
1852 show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
1853
1854 show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header);
1855
1856 show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header);
1857 show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header);
1858 show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header);
1859 show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header);
1860 }
1861 else
1862 {
1863 vty_out (vty, " %s: MPLS-TE is disabled on this interface%s",
1864 ifp->name, VTY_NEWLINE);
1865 }
1866
1867 return;
1868}
1869
1870DEFUN (show_mpls_te_link,
1871 show_mpls_te_link_cmd,
1872 "show mpls-te interface [INTERFACE]",
1873 SHOW_STR
1874 "MPLS-TE information\n"
1875 "Interface information\n"
1876 "Interface name\n")
1877{
1878 struct interface *ifp;
1879 listnode node;
1880
1881 /* Show All Interfaces. */
1882 if (argc == 0)
1883 for (node = listhead (iflist); node; nextnode (node))
1884 show_mpls_te_link_sub (vty, node->data);
1885 /* Interface name is specified. */
1886 else
1887 {
1888 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
1889 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
1890 else
1891 show_mpls_te_link_sub (vty, ifp);
1892 }
1893
1894 return CMD_SUCCESS;
1895}
1896
1897static void
1898ospf_mpls_te_register_vty (void)
1899{
1900 install_element (VIEW_NODE, &show_mpls_te_router_cmd);
1901 install_element (VIEW_NODE, &show_mpls_te_link_cmd);
1902 install_element (ENABLE_NODE, &show_mpls_te_router_cmd);
1903 install_element (ENABLE_NODE, &show_mpls_te_link_cmd);
1904
1905 install_element (OSPF_NODE, &mpls_te_cmd);
1906 install_element (OSPF_NODE, &no_mpls_te_cmd);
1907 install_element (OSPF_NODE, &mpls_te_on_cmd);
1908 install_element (OSPF_NODE, &mpls_te_router_addr_cmd);
1909
1910 install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd);
1911 install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd);
1912 install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd);
1913 install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd);
1914 install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd);
1915
1916 return;
1917}
1918
1919#endif /* HAVE_OSPF_TE */