[ripd] bug #278: remove gratuitous use of mid-function declaration
[jleu-quagga.git] / ospfd / ospf_te.c
bloba3ebe62e3a12d0de4e12bf2d6aa725dfe7fa8c1e
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/
6 * This file is part of GNU Zebra.
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.
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.
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.
24 /***** MTYPE definition is not reflected to "memory.h" yet. *****/
25 #define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0
27 #include <zebra.h>
29 #ifdef HAVE_OSPF_TE
30 #ifndef HAVE_OPAQUE_LSA
31 #error "Wrong configure option"
32 #endif /* HAVE_OPAQUE_LSA */
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() */
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"
64 /* Following structure are internal use only. */
65 struct ospf_mpls_te
67 enum { disabled, enabled } status;
69 /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */
70 struct list *iflist;
72 /* Store Router-TLV in network byte order. */
73 struct te_tlv_router_addr router_addr;
76 struct mpls_te_link
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.
83 u_int32_t instance;
85 /* Reference pointer to a Zebra-interface. */
86 struct interface *ifp;
88 /* Area info in which this MPLS-TE link belongs to. */
89 struct ospf_area *area;
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
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;
111 * Global variable to manage Opaque-LSA/MPLS-TE on this node.
112 * Note that all parameter values are stored in network byte order.
114 static struct ospf_mpls_te OspfMplsTE;
116 enum oifstate {
117 OI_ANY, OI_DOWN, OI_UP
120 enum sched_opcode {
121 REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA
124 /*------------------------------------------------------------------------*
125 * Followings are initialize/terminate functions for MPLS-TE handling.
126 *------------------------------------------------------------------------*/
128 static int ospf_mpls_te_new_if (struct interface *ifp);
129 static int ospf_mpls_te_del_if (struct interface *ifp);
130 static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status);
131 static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status);
132 static void ospf_mpls_te_config_write_router (struct vty *vty);
133 static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp);
134 static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa);
135 static int ospf_mpls_te_lsa_originate (void *arg);
136 static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
137 static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode);
139 static void del_mpls_te_link (void *val);
140 static void ospf_mpls_te_register_vty (void);
143 ospf_mpls_te_init (void)
145 int rc;
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)
164 zlog_warn ("ospf_mpls_te_init: Failed to register functions");
165 goto out;
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;
173 ospf_mpls_te_register_vty ();
175 out:
176 return rc;
179 void
180 ospf_mpls_te_term (void)
182 list_delete (OspfMplsTE.iflist);
184 OspfMplsTE.iflist = NULL;
185 OspfMplsTE.status = disabled;
187 ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA,
188 OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
189 return;
192 /*------------------------------------------------------------------------*
193 * Followings are control functions for MPLS-TE parameters management.
194 *------------------------------------------------------------------------*/
196 static void
197 del_mpls_te_link (void *val)
199 XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val);
200 return;
203 static u_int32_t
204 get_mpls_te_instance_value (void)
206 static u_int32_t seqno = 0;
208 if (LEGAL_TE_INSTANCE_RANGE (seqno + 1))
209 seqno += 1;
210 else
211 seqno = 1; /* Avoid zero. */
213 return seqno;
216 static struct ospf_interface *
217 lookup_oi_by_ifp (struct interface *ifp,
218 struct ospf_area *area, enum oifstate oifstate)
220 struct ospf_interface *oi = NULL;
221 struct route_node *rn;
223 for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
225 if ((oi = rn->info) == NULL)
226 continue;
228 switch (oifstate)
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;
245 if (area == NULL || oi->area == area)
246 return oi;
248 out:
249 return NULL;
252 static struct mpls_te_link *
253 lookup_linkparams_by_ifp (struct interface *ifp)
255 struct listnode *node, *nnode;
256 struct mpls_te_link *lp;
258 for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp))
259 if (lp->ifp == ifp)
260 return lp;
262 return NULL;
265 static struct mpls_te_link *
266 lookup_linkparams_by_instance (struct ospf_lsa *lsa)
268 struct listnode *node;
269 struct mpls_te_link *lp;
270 unsigned int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr));
272 for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp))
273 if (lp->instance == key)
274 return lp;
276 zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key);
277 return NULL;
280 static void
281 ospf_mpls_te_foreach_area (
282 void (*func)(struct mpls_te_link *lp, enum sched_opcode),
283 enum sched_opcode sched_opcode)
285 struct listnode *node, *nnode;
286 struct listnode *node2;
287 struct mpls_te_link *lp;
288 struct ospf_area *area;
290 for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp))
292 if ((area = lp->area) == NULL)
293 continue;
294 if (lp->flags & LPFLG_LOOKUP_DONE)
295 continue;
297 if (func != NULL)
298 (* func)(lp, sched_opcode);
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;
307 for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp))
308 if (lp->area != NULL)
309 lp->flags &= ~LPFLG_LOOKUP_DONE;
311 return;
314 static void
315 set_mpls_te_router_addr (struct in_addr ipv4)
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;
323 static void
324 set_linkparams_link_header (struct mpls_te_link *lp)
326 struct te_tlv_header *tlvh;
327 u_int16_t length = 0;
329 /* TE_LINK_SUBTLV_LINK_TYPE */
330 if (ntohs (lp->link_type.header.type) != 0)
331 length += TLV_SIZE (&lp->link_type.header);
333 /* TE_LINK_SUBTLV_LINK_ID */
334 if (ntohs (lp->link_id.header.type) != 0)
335 length += TLV_SIZE (&lp->link_id.header);
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);
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);
347 /* TE_LINK_SUBTLV_TE_METRIC */
348 if (ntohs (lp->te_metric.header.type) != 0)
349 length += TLV_SIZE (&lp->te_metric.header);
351 /* TE_LINK_SUBTLV_MAX_BW */
352 if (ntohs (lp->max_bw.header.type) != 0)
353 length += TLV_SIZE (&lp->max_bw.header);
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);
359 /* TE_LINK_SUBTLV_UNRSV_BW */
360 if (ntohs (lp->unrsv_bw.header.type) != 0)
361 length += TLV_SIZE (&lp->unrsv_bw.header);
363 /* TE_LINK_SUBTLV_RSC_CLSCLR */
364 if (ntohs (lp->rsc_clsclr.header.type) != 0)
365 length += TLV_SIZE (&lp->rsc_clsclr.header);
367 lp->link_header.header.type = htons (TE_TLV_LINK);
368 lp->link_header.header.length = htons (length);
370 return;
373 static void
374 set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp)
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));
379 switch (oi->type)
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;
393 return;
396 static void
397 set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp)
399 struct ospf_neighbor *nbr;
400 int done = 0;
402 lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID);
403 lp->link_id.header.length = htons (sizeof (lp->link_id.value));
406 * The Link ID is identical to the contents of the Link ID field
407 * in the Router LSA for these link types.
409 switch (oi->type)
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)
416 lp->link_id.value = nbr->router_id;
417 done = 1;
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;
426 if (nbr->state == NSM_Full
427 || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
428 && ospf_nbr_count (oi, NSM_Full) > 0))
430 lp->link_id.value = DR (oi);
431 done = 1;
433 break;
434 default:
435 /* Not supported yet. *//* XXX */
436 lp->link_id.header.type = htons (0);
437 break;
440 if (! done)
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;
446 return;
449 static void
450 set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric)
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;
458 static void
459 set_linkparams_max_bw (struct mpls_te_link *lp, float *fp)
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;
467 static void
468 set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp)
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;
476 static void
477 set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp)
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;
486 static void
487 set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor)
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;
495 static void
496 initialize_linkparams (struct mpls_te_link *lp)
498 struct interface *ifp = lp->ifp;
499 struct ospf_interface *oi;
500 float fval;
501 int i;
503 if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL)
504 return;
507 * Try to set initial values those can be derived from
508 * zebra-interface information.
510 set_linkparams_link_type (oi, lp);
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.
516 fval = (float)((ifp->bandwidth ? ifp->bandwidth
517 : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8);
519 set_linkparams_max_bw (lp, &fval);
520 set_linkparams_max_rsv_bw (lp, &fval);
522 for (i = 0; i < 8; i++)
523 set_linkparams_unrsv_bw (lp, i, &fval);
525 return;
528 static int
529 is_mandated_params_set (struct mpls_te_link *lp)
531 int rc = 0;
533 if (ntohs (OspfMplsTE.router_addr.header.type) == 0)
534 goto out;
536 if (ntohs (lp->link_type.header.type) == 0)
537 goto out;
539 if (ntohs (lp->link_id.header.type) == 0)
540 goto out;
542 rc = 1;
543 out:
544 return rc;
547 /*------------------------------------------------------------------------*
548 * Followings are callback functions against generic Opaque-LSAs handling.
549 *------------------------------------------------------------------------*/
551 static int
552 ospf_mpls_te_new_if (struct interface *ifp)
554 struct mpls_te_link *new;
555 int rc = -1;
557 if (lookup_linkparams_by_ifp (ifp) != NULL)
559 zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp);
560 rc = 0; /* Do nothing here. */
561 goto out;
564 if ((new = XMALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS,
565 sizeof (struct mpls_te_link))) == NULL)
567 zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", safe_strerror (errno));
568 goto out;
570 memset (new, 0, sizeof (struct mpls_te_link));
572 new->area = NULL;
573 new->flags = 0;
574 new->instance = get_mpls_te_instance_value ();
575 new->ifp = ifp;
577 initialize_linkparams (new);
579 listnode_add (OspfMplsTE.iflist, new);
581 /* Schedule Opaque-LSA refresh. *//* XXX */
583 rc = 0;
584 out:
585 return rc;
588 static int
589 ospf_mpls_te_del_if (struct interface *ifp)
591 struct mpls_te_link *lp;
592 int rc = -1;
594 if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)
596 struct list *iflist = OspfMplsTE.iflist;
598 /* Dequeue listnode entry from the list. */
599 listnode_delete (iflist, lp);
601 /* Avoid misjudgement in the next lookup. */
602 if (listcount (iflist) == 0)
603 iflist->head = iflist->tail = NULL;
605 XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp);
608 /* Schedule Opaque-LSA refresh. *//* XXX */
610 rc = 0;
611 /*out:*/
612 return rc;
615 static void
616 ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state)
618 struct te_link_subtlv_link_type old_type;
619 struct te_link_subtlv_link_id old_id;
620 struct mpls_te_link *lp;
622 if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL)
624 zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi));
625 goto out;
627 if (oi->area == NULL || oi->area->ospf == NULL)
629 zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?",
630 IF_NAME (oi));
631 goto out;
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))
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);
642 #endif
643 /* Keep Area information in conbination with linkparams. */
644 lp->area = oi->area;
646 switch (oi->state)
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;
655 set_linkparams_link_type (oi, lp);
656 set_linkparams_link_id (oi, lp);
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)))
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);
668 break;
669 default:
670 lp->link_type.header.type = htons (0);
671 lp->link_id.header.type = htons (0);
673 if (lp->flags & LPFLG_LSA_ENGAGED)
674 ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
675 break;
678 out:
679 return;
682 static void
683 ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state)
685 /* So far, nothing to do here. */
686 return;
689 /*------------------------------------------------------------------------*
690 * Followings are OSPF protocol processing functions for MPLS-TE.
691 *------------------------------------------------------------------------*/
693 static void
694 build_tlv_header (struct stream *s, struct te_tlv_header *tlvh)
696 stream_put (s, tlvh, sizeof (struct te_tlv_header));
697 return;
700 static void
701 build_router_tlv (struct stream *s)
703 struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header;
704 if (ntohs (tlvh->type) != 0)
706 build_tlv_header (s, tlvh);
707 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
709 return;
712 static void
713 build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp)
715 struct te_tlv_header *tlvh = &lp->link_type.header;
716 if (ntohs (tlvh->type) != 0)
718 build_tlv_header (s, tlvh);
719 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
721 return;
724 static void
725 build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp)
727 struct te_tlv_header *tlvh = &lp->link_id.header;
728 if (ntohs (tlvh->type) != 0)
730 build_tlv_header (s, tlvh);
731 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
733 return;
736 static void
737 build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp)
739 struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr;
740 if (tlvh != NULL && ntohs (tlvh->type) != 0)
742 build_tlv_header (s, tlvh);
743 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
745 return;
748 static void
749 build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp)
751 struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr;
752 if (tlvh != NULL && ntohs (tlvh->type) != 0)
754 build_tlv_header (s, tlvh);
755 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
757 return;
760 static void
761 build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp)
763 struct te_tlv_header *tlvh = &lp->te_metric.header;
764 if (ntohs (tlvh->type) != 0)
766 build_tlv_header (s, tlvh);
767 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
769 return;
772 static void
773 build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp)
775 struct te_tlv_header *tlvh = &lp->max_bw.header;
776 if (ntohs (tlvh->type) != 0)
778 build_tlv_header (s, tlvh);
779 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
781 return;
784 static void
785 build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp)
787 struct te_tlv_header *tlvh = &lp->max_rsv_bw.header;
788 if (ntohs (tlvh->type) != 0)
790 build_tlv_header (s, tlvh);
791 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
793 return;
796 static void
797 build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp)
799 struct te_tlv_header *tlvh = &lp->unrsv_bw.header;
800 if (ntohs (tlvh->type) != 0)
802 build_tlv_header (s, tlvh);
803 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
805 return;
808 static void
809 build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp)
811 struct te_tlv_header *tlvh = &lp->rsc_clsclr.header;
812 if (ntohs (tlvh->type) != 0)
814 build_tlv_header (s, tlvh);
815 stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
817 return;
820 static void
821 build_link_tlv (struct stream *s, struct mpls_te_link *lp)
823 set_linkparams_link_header (lp);
824 build_tlv_header (s, &lp->link_header.header);
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;
838 static void
839 ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp)
842 * The router address TLV is type 1, and ...
843 * It must appear in exactly one
844 * Traffic Engineering LSA originated by a router.
846 build_router_tlv (s);
849 * Only one Link TLV shall be carried in each LSA, allowing for fine
850 * granularity changes in topology.
852 build_link_tlv (s, lp);
853 return;
856 /* Create new opaque-LSA. */
857 static struct ospf_lsa *
858 ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp)
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;
868 /* Create a stream for LSA. */
869 if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL)
871 zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?");
872 goto out;
874 lsah = (struct lsa_header *) STREAM_DATA (s);
876 options = LSA_OPTIONS_GET (area);
877 options |= LSA_OPTIONS_NSSA_GET (area);
878 options |= OSPF_OPTION_O; /* Don't forget this :-) */
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);
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));
887 /* Set opaque-LSA header fields. */
888 lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id);
890 /* Set opaque-LSA body fields. */
891 ospf_mpls_te_lsa_body_set (s, lp);
893 /* Set length. */
894 length = stream_get_endp (s);
895 lsah->length = htons (length);
897 /* Now, create an OSPF LSA instance. */
898 if ((new = ospf_lsa_new ()) == NULL)
900 zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?");
901 stream_free (s);
902 goto out;
904 if ((new->data = ospf_lsa_data_new (length)) == NULL)
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;
913 new->area = area;
914 SET_FLAG (new->flags, OSPF_LSA_SELF);
915 memcpy (new->data, lsah, length);
916 stream_free (s);
918 out:
919 return new;
922 static int
923 ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp)
925 struct ospf_lsa *new;
926 int rc = -1;
928 /* Create new Opaque-LSA/MPLS-TE instance. */
929 if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
931 zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?");
932 goto out;
935 /* Install this LSA into LSDB. */
936 if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL)
938 zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?");
939 ospf_lsa_unlock (&new);
940 goto out;
943 /* Now this linkparameter entry has associated LSA. */
944 lp->flags |= LPFLG_LSA_ENGAGED;
946 /* Update new LSA origination count. */
947 area->ospf->lsa_originate_count++;
949 /* Flood new LSA through area. */
950 ospf_flood_through_area (area, NULL/*nbr*/, new);
952 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
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);
960 rc = 0;
961 out:
962 return rc;
965 static int
966 ospf_mpls_te_lsa_originate (void *arg)
968 struct ospf_area *area = (struct ospf_area *) arg;
969 struct listnode *node, *nnode;
970 struct mpls_te_link *lp;
971 int rc = -1;
973 if (OspfMplsTE.status == disabled)
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;
980 for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp))
982 if (lp->area == NULL)
983 continue;
984 if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id))
985 continue;
987 if (lp->flags & LPFLG_LSA_ENGAGED)
989 if (lp->flags & LPFLG_LSA_FORCED_REFRESH)
991 lp->flags &= ~LPFLG_LSA_FORCED_REFRESH;
992 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
994 continue;
996 if (! is_mandated_params_set (lp))
998 zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?");
999 continue;
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;
1007 rc = 0;
1008 out:
1009 return rc;
1012 static void
1013 ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa)
1015 struct mpls_te_link *lp;
1016 struct ospf_area *area = lsa->area;
1017 struct ospf_lsa *new = NULL;
1019 if (OspfMplsTE.status == disabled)
1022 * This LSA must have flushed before due to MPLS-TE status change.
1023 * It seems a slip among routers in the routing domain.
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. */
1029 /* At first, resolve lsa/lp relationship. */
1030 if ((lp = lookup_linkparams_by_instance (lsa)) == NULL)
1032 zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?");
1033 lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
1036 /* If the lsa's age reached to MaxAge, start flushing procedure. */
1037 if (IS_LSA_MAXAGE (lsa))
1039 lp->flags &= ~LPFLG_LSA_ENGAGED;
1040 ospf_opaque_lsa_flush_schedule (lsa);
1041 goto out;
1044 /* Create new Opaque-LSA/MPLS-TE instance. */
1045 if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
1047 zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?");
1048 goto out;
1050 new->data->ls_seqnum = lsa_seqnum_increment (lsa);
1052 /* Install this LSA into LSDB. */
1053 /* Given "lsa" will be freed in the next function. */
1054 if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL)
1056 zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?");
1057 ospf_lsa_unlock (&new);
1058 goto out;
1061 /* Flood updated LSA through area. */
1062 ospf_flood_through_area (area, NULL/*nbr*/, new);
1064 /* Debug logging. */
1065 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
1067 zlog_debug ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE",
1068 new->data->type, inet_ntoa (new->data->id));
1069 ospf_lsa_header_dump (new->data);
1072 out:
1073 return;
1076 static void
1077 ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp,
1078 enum sched_opcode opcode)
1080 struct ospf_lsa lsa;
1081 struct lsa_header lsah;
1082 u_int32_t tmp;
1084 memset (&lsa, 0, sizeof (lsa));
1085 memset (&lsah, 0, sizeof (lsah));
1087 lsa.area = lp->area;
1088 lsa.data = &lsah;
1089 lsah.type = OSPF_OPAQUE_AREA_LSA;
1090 tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance);
1091 lsah.id.s_addr = htonl (tmp);
1093 switch (opcode)
1095 case REORIGINATE_PER_AREA:
1096 ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area,
1097 OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
1098 break;
1099 case REFRESH_THIS_LSA:
1100 ospf_opaque_lsa_refresh_schedule (&lsa);
1101 break;
1102 case FLUSH_THIS_LSA:
1103 lp->flags &= ~LPFLG_LSA_ENGAGED;
1104 ospf_opaque_lsa_flush_schedule (&lsa);
1105 break;
1106 default:
1107 zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode);
1108 break;
1111 return;
1114 /*------------------------------------------------------------------------*
1115 * Followings are vty session control functions.
1116 *------------------------------------------------------------------------*/
1118 static u_int16_t
1119 show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh)
1121 struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh;
1123 if (vty != NULL)
1124 vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
1125 else
1126 zlog_debug (" Router-Address: %s", inet_ntoa (top->value));
1128 return TLV_SIZE (tlvh);
1131 static u_int16_t
1132 show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh)
1134 struct te_tlv_link *top = (struct te_tlv_link *) tlvh;
1136 if (vty != NULL)
1137 vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE);
1138 else
1139 zlog_debug (" Link: %u octets of data", ntohs (top->header.length));
1141 return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */
1144 static u_int16_t
1145 show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh)
1147 struct te_link_subtlv_link_type *top;
1148 const char *cp = "Unknown";
1150 top = (struct te_link_subtlv_link_type *) tlvh;
1151 switch (top->link_type.value)
1153 case LINK_TYPE_SUBTLV_VALUE_PTP:
1154 cp = "Point-to-point";
1155 break;
1156 case LINK_TYPE_SUBTLV_VALUE_MA:
1157 cp = "Multiaccess";
1158 break;
1159 default:
1160 break;
1163 if (vty != NULL)
1164 vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE);
1165 else
1166 zlog_debug (" Link-Type: %s (%u)", cp, top->link_type.value);
1168 return TLV_SIZE (tlvh);
1171 static u_int16_t
1172 show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh)
1174 struct te_link_subtlv_link_id *top;
1176 top = (struct te_link_subtlv_link_id *) tlvh;
1177 if (vty != NULL)
1178 vty_out (vty, " Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
1179 else
1180 zlog_debug (" Link-ID: %s", inet_ntoa (top->value));
1182 return TLV_SIZE (tlvh);
1185 static u_int16_t
1186 show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
1188 struct te_link_subtlv_lclif_ipaddr *top;
1189 int i, n;
1191 top = (struct te_link_subtlv_lclif_ipaddr *) tlvh;
1192 n = ntohs (tlvh->length) / sizeof (top->value[0]);
1194 if (vty != NULL)
1195 vty_out (vty, " Local Interface IP Address(es): %d%s", n, VTY_NEWLINE);
1196 else
1197 zlog_debug (" Local Interface IP Address(es): %d", n);
1199 for (i = 0; i < n; i++)
1201 if (vty != NULL)
1202 vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
1203 else
1204 zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i]));
1206 return TLV_SIZE (tlvh);
1209 static u_int16_t
1210 show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
1212 struct te_link_subtlv_rmtif_ipaddr *top;
1213 int i, n;
1215 top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh;
1216 n = ntohs (tlvh->length) / sizeof (top->value[0]);
1217 if (vty != NULL)
1218 vty_out (vty, " Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE);
1219 else
1220 zlog_debug (" Remote Interface IP Address(es): %d", n);
1222 for (i = 0; i < n; i++)
1224 if (vty != NULL)
1225 vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
1226 else
1227 zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i]));
1229 return TLV_SIZE (tlvh);
1232 static u_int16_t
1233 show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh)
1235 struct te_link_subtlv_te_metric *top;
1237 top = (struct te_link_subtlv_te_metric *) tlvh;
1238 if (vty != NULL)
1239 vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
1240 else
1241 zlog_debug (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value));
1243 return TLV_SIZE (tlvh);
1246 static u_int16_t
1247 show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh)
1249 struct te_link_subtlv_max_bw *top;
1250 float fval;
1252 top = (struct te_link_subtlv_max_bw *) tlvh;
1253 ntohf (&top->value, &fval);
1255 if (vty != NULL)
1256 vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
1257 else
1258 zlog_debug (" Maximum Bandwidth: %g (Bytes/sec)", fval);
1260 return TLV_SIZE (tlvh);
1263 static u_int16_t
1264 show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
1266 struct te_link_subtlv_max_rsv_bw *top;
1267 float fval;
1269 top = (struct te_link_subtlv_max_rsv_bw *) tlvh;
1270 ntohf (&top->value, &fval);
1272 if (vty != NULL)
1273 vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
1274 else
1275 zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval);
1277 return TLV_SIZE (tlvh);
1280 static u_int16_t
1281 show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
1283 struct te_link_subtlv_unrsv_bw *top;
1284 float fval;
1285 int i;
1287 top = (struct te_link_subtlv_unrsv_bw *) tlvh;
1288 for (i = 0; i < 8; i++)
1290 ntohf (&top->value[i], &fval);
1291 if (vty != NULL)
1292 vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE);
1293 else
1294 zlog_debug (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval);
1297 return TLV_SIZE (tlvh);
1300 static u_int16_t
1301 show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh)
1303 struct te_link_subtlv_rsc_clsclr *top;
1305 top = (struct te_link_subtlv_rsc_clsclr *) tlvh;
1306 if (vty != NULL)
1307 vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
1308 else
1309 zlog_debug (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value));
1311 return TLV_SIZE (tlvh);
1314 static u_int16_t
1315 show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh)
1317 if (vty != NULL)
1318 vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE);
1319 else
1320 zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length));
1322 return TLV_SIZE (tlvh);
1325 static u_int16_t
1326 ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0,
1327 u_int16_t subtotal, u_int16_t total)
1329 struct te_tlv_header *tlvh, *next;
1330 u_int16_t sum = subtotal;
1332 for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
1334 next = NULL;
1335 switch (ntohs (tlvh->type))
1337 case TE_LINK_SUBTLV_LINK_TYPE:
1338 sum += show_vty_link_subtlv_link_type (vty, tlvh);
1339 break;
1340 case TE_LINK_SUBTLV_LINK_ID:
1341 sum += show_vty_link_subtlv_link_id (vty, tlvh);
1342 break;
1343 case TE_LINK_SUBTLV_LCLIF_IPADDR:
1344 sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
1345 break;
1346 case TE_LINK_SUBTLV_RMTIF_IPADDR:
1347 sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
1348 break;
1349 case TE_LINK_SUBTLV_TE_METRIC:
1350 sum += show_vty_link_subtlv_te_metric (vty, tlvh);
1351 break;
1352 case TE_LINK_SUBTLV_MAX_BW:
1353 sum += show_vty_link_subtlv_max_bw (vty, tlvh);
1354 break;
1355 case TE_LINK_SUBTLV_MAX_RSV_BW:
1356 sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh);
1357 break;
1358 case TE_LINK_SUBTLV_UNRSV_BW:
1359 sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh);
1360 break;
1361 case TE_LINK_SUBTLV_RSC_CLSCLR:
1362 sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh);
1363 break;
1364 default:
1365 sum += show_vty_unknown_tlv (vty, tlvh);
1366 break;
1369 return sum;
1372 static void
1373 ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa)
1375 struct lsa_header *lsah = (struct lsa_header *) lsa->data;
1376 struct te_tlv_header *tlvh, *next;
1377 u_int16_t sum, total;
1378 u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh,
1379 u_int16_t subtotal, u_int16_t total) = NULL;
1381 sum = 0;
1382 total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE;
1384 for (tlvh = TLV_HDR_TOP (lsah); sum < total;
1385 tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
1387 if (subfunc != NULL)
1389 sum = (* subfunc)(vty, tlvh, sum, total);
1390 next = (struct te_tlv_header *)((char *) tlvh + sum);
1391 subfunc = NULL;
1392 continue;
1395 next = NULL;
1396 switch (ntohs (tlvh->type))
1398 case TE_TLV_ROUTER_ADDR:
1399 sum += show_vty_router_addr (vty, tlvh);
1400 break;
1401 case TE_TLV_LINK:
1402 sum += show_vty_link_header (vty, tlvh);
1403 subfunc = ospf_mpls_te_show_link_subtlv;
1404 next = tlvh + 1;
1405 break;
1406 default:
1407 sum += show_vty_unknown_tlv (vty, tlvh);
1408 break;
1411 return;
1414 static void
1415 ospf_mpls_te_config_write_router (struct vty *vty)
1417 if (OspfMplsTE.status == enabled)
1419 vty_out (vty, " mpls-te%s", VTY_NEWLINE);
1420 vty_out (vty, " mpls-te router-address %s%s",
1421 inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE);
1423 return;
1426 static void
1427 ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp)
1429 struct mpls_te_link *lp;
1431 if ((OspfMplsTE.status == enabled)
1432 && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
1433 && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
1435 float fval;
1436 int i;
1438 vty_out (vty, " mpls-te link metric %u%s",
1439 (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE);
1441 ntohf (&lp->max_bw.value, &fval);
1442 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
1443 vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE);
1445 ntohf (&lp->max_rsv_bw.value, &fval);
1446 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
1447 vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE);
1449 for (i = 0; i < 8; i++)
1451 ntohf (&lp->unrsv_bw.value[i], &fval);
1452 if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
1453 vty_out (vty, " mpls-te link unrsv-bw %d %g%s",
1454 i, fval, VTY_NEWLINE);
1457 vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s",
1458 (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE);
1460 return;
1463 /*------------------------------------------------------------------------*
1464 * Followings are vty command functions.
1465 *------------------------------------------------------------------------*/
1467 DEFUN (mpls_te,
1468 mpls_te_cmd,
1469 "mpls-te",
1470 "Configure MPLS-TE parameters\n"
1471 "Enable the MPLS-TE functionality\n")
1473 struct listnode *node, *nnode;
1474 struct mpls_te_link *lp;
1476 if (OspfMplsTE.status == enabled)
1477 return CMD_SUCCESS;
1479 if (IS_DEBUG_OSPF_EVENT)
1480 zlog_debug ("MPLS-TE: OFF -> ON");
1482 OspfMplsTE.status = enabled;
1485 * Following code is intended to handle two cases;
1487 * 1) MPLS-TE was disabled at startup time, but now become enabled.
1488 * 2) MPLS-TE was once enabled then disabled, and now enabled again.
1490 for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp))
1491 initialize_linkparams (lp);
1493 ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
1495 return CMD_SUCCESS;
1498 ALIAS (mpls_te,
1499 mpls_te_on_cmd,
1500 "mpls-te on",
1501 "Configure MPLS-TE parameters\n"
1502 "Enable the MPLS-TE functionality\n")
1504 DEFUN (no_mpls_te,
1505 no_mpls_te_cmd,
1506 "no mpls-te",
1507 NO_STR
1508 "Configure MPLS-TE parameters\n"
1509 "Disable the MPLS-TE functionality\n")
1511 struct listnode *node, *nnode;
1512 struct mpls_te_link *lp;
1514 if (OspfMplsTE.status == disabled)
1515 return CMD_SUCCESS;
1517 if (IS_DEBUG_OSPF_EVENT)
1518 zlog_debug ("MPLS-TE: ON -> OFF");
1520 OspfMplsTE.status = disabled;
1522 for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp))
1523 if (lp->area != NULL)
1524 if (lp->flags & LPFLG_LSA_ENGAGED)
1525 ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
1527 return CMD_SUCCESS;
1530 DEFUN (mpls_te_router_addr,
1531 mpls_te_router_addr_cmd,
1532 "mpls-te router-address A.B.C.D",
1533 "MPLS-TE specific commands\n"
1534 "Stable IP address of the advertising router\n"
1535 "MPLS-TE router address in IPv4 address format\n")
1537 struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr;
1538 struct in_addr value;
1540 if (! inet_aton (argv[0], &value))
1542 vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE);
1543 return CMD_WARNING;
1546 if (ntohs (ra->header.type) == 0
1547 || ntohl (ra->value.s_addr) != ntohl (value.s_addr))
1549 struct listnode *node, *nnode;
1550 struct mpls_te_link *lp;
1551 int need_to_reoriginate = 0;
1553 set_mpls_te_router_addr (value);
1555 if (OspfMplsTE.status == disabled)
1556 goto out;
1558 for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp))
1560 if (lp->area == NULL)
1561 continue;
1563 if ((lp->flags & LPFLG_LSA_ENGAGED) == 0)
1565 need_to_reoriginate = 1;
1566 break;
1570 for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp))
1572 if (lp->area == NULL)
1573 continue;
1575 if (need_to_reoriginate)
1576 lp->flags |= LPFLG_LSA_FORCED_REFRESH;
1577 else
1578 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1581 if (need_to_reoriginate)
1582 ospf_mpls_te_foreach_area (
1583 ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
1585 out:
1586 return CMD_SUCCESS;
1589 DEFUN (mpls_te_link_metric,
1590 mpls_te_link_metric_cmd,
1591 "mpls-te link metric <0-4294967295>",
1592 "MPLS-TE specific commands\n"
1593 "Configure MPLS-TE link parameters\n"
1594 "Link metric for MPLS-TE purpose\n"
1595 "Metric\n")
1597 struct interface *ifp = (struct interface *) vty->index;
1598 struct mpls_te_link *lp;
1599 u_int32_t value;
1601 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1603 vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE);
1604 return CMD_WARNING;
1607 value = strtoul (argv[0], NULL, 10);
1609 if (ntohs (lp->te_metric.header.type) == 0
1610 || ntohl (lp->te_metric.value) != value)
1612 set_linkparams_te_metric (lp, value);
1614 if (OspfMplsTE.status == enabled)
1615 if (lp->area != NULL)
1617 if (lp->flags & LPFLG_LSA_ENGAGED)
1618 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1619 else
1620 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1623 return CMD_SUCCESS;
1626 DEFUN (mpls_te_link_maxbw,
1627 mpls_te_link_maxbw_cmd,
1628 "mpls-te link max-bw BANDWIDTH",
1629 "MPLS-TE specific commands\n"
1630 "Configure MPLS-TE link parameters\n"
1631 "Maximum bandwidth that can be used\n"
1632 "Bytes/second (IEEE floating point format)\n")
1634 struct interface *ifp = (struct interface *) vty->index;
1635 struct mpls_te_link *lp;
1636 float f1, f2;
1638 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1640 vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE);
1641 return CMD_WARNING;
1644 ntohf (&lp->max_bw.value, &f1);
1645 if (sscanf (argv[0], "%g", &f2) != 1)
1647 vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE);
1648 return CMD_WARNING;
1651 if (ntohs (lp->max_bw.header.type) == 0
1652 || f1 != f2)
1654 set_linkparams_max_bw (lp, &f2);
1656 if (OspfMplsTE.status == enabled)
1657 if (lp->area != NULL)
1659 if (lp->flags & LPFLG_LSA_ENGAGED)
1660 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1661 else
1662 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1665 return CMD_SUCCESS;
1668 DEFUN (mpls_te_link_max_rsv_bw,
1669 mpls_te_link_max_rsv_bw_cmd,
1670 "mpls-te link max-rsv-bw BANDWIDTH",
1671 "MPLS-TE specific commands\n"
1672 "Configure MPLS-TE link parameters\n"
1673 "Maximum bandwidth that may be reserved\n"
1674 "Bytes/second (IEEE floating point format)\n")
1676 struct interface *ifp = (struct interface *) vty->index;
1677 struct mpls_te_link *lp;
1678 float f1, f2;
1680 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1682 vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE);
1683 return CMD_WARNING;
1686 ntohf (&lp->max_rsv_bw.value, &f1);
1687 if (sscanf (argv[0], "%g", &f2) != 1)
1689 vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE);
1690 return CMD_WARNING;
1693 if (ntohs (lp->max_rsv_bw.header.type) == 0
1694 || f1 != f2)
1696 set_linkparams_max_rsv_bw (lp, &f2);
1698 if (OspfMplsTE.status == enabled)
1699 if (lp->area != NULL)
1701 if (lp->flags & LPFLG_LSA_ENGAGED)
1702 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1703 else
1704 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1707 return CMD_SUCCESS;
1710 DEFUN (mpls_te_link_unrsv_bw,
1711 mpls_te_link_unrsv_bw_cmd,
1712 "mpls-te link unrsv-bw <0-7> BANDWIDTH",
1713 "MPLS-TE specific commands\n"
1714 "Configure MPLS-TE link parameters\n"
1715 "Unreserved bandwidth at each priority level\n"
1716 "Priority\n"
1717 "Bytes/second (IEEE floating point format)\n")
1719 struct interface *ifp = (struct interface *) vty->index;
1720 struct mpls_te_link *lp;
1721 int priority;
1722 float f1, f2;
1724 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1726 vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE);
1727 return CMD_WARNING;
1730 /* We don't have to consider about range check here. */
1731 if (sscanf (argv[0], "%d", &priority) != 1)
1733 vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE);
1734 return CMD_WARNING;
1737 ntohf (&lp->unrsv_bw.value [priority], &f1);
1738 if (sscanf (argv[1], "%g", &f2) != 1)
1740 vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE);
1741 return CMD_WARNING;
1744 if (ntohs (lp->unrsv_bw.header.type) == 0
1745 || f1 != f2)
1747 set_linkparams_unrsv_bw (lp, priority, &f2);
1749 if (OspfMplsTE.status == enabled)
1750 if (lp->area != NULL)
1752 if (lp->flags & LPFLG_LSA_ENGAGED)
1753 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1754 else
1755 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1758 return CMD_SUCCESS;
1761 DEFUN (mpls_te_link_rsc_clsclr,
1762 mpls_te_link_rsc_clsclr_cmd,
1763 "mpls-te link rsc-clsclr BITPATTERN",
1764 "MPLS-TE specific commands\n"
1765 "Configure MPLS-TE link parameters\n"
1766 "Administrative group membership\n"
1767 "32-bit Hexadecimal value (ex. 0xa1)\n")
1769 struct interface *ifp = (struct interface *) vty->index;
1770 struct mpls_te_link *lp;
1771 unsigned long value;
1773 if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
1775 vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE);
1776 return CMD_WARNING;
1779 if (sscanf (argv[0], "0x%lx", &value) != 1)
1781 vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE);
1782 return CMD_WARNING;
1785 if (ntohs (lp->rsc_clsclr.header.type) == 0
1786 || ntohl (lp->rsc_clsclr.value) != value)
1788 set_linkparams_rsc_clsclr (lp, value);
1790 if (OspfMplsTE.status == enabled)
1791 if (lp->area != NULL)
1793 if (lp->flags & LPFLG_LSA_ENGAGED)
1794 ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
1795 else
1796 ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
1799 return CMD_SUCCESS;
1802 DEFUN (show_mpls_te_router,
1803 show_mpls_te_router_cmd,
1804 "show mpls-te router",
1805 SHOW_STR
1806 "MPLS-TE information\n"
1807 "Router information\n")
1809 if (OspfMplsTE.status == enabled)
1811 vty_out (vty, "--- MPLS-TE router parameters ---%s",
1812 VTY_NEWLINE);
1814 if (ntohs (OspfMplsTE.router_addr.header.type) != 0)
1815 show_vty_router_addr (vty, &OspfMplsTE.router_addr.header);
1816 else if (vty != NULL)
1817 vty_out (vty, " N/A%s", VTY_NEWLINE);
1819 return CMD_SUCCESS;
1822 static void
1823 show_mpls_te_link_sub (struct vty *vty, struct interface *ifp)
1825 struct mpls_te_link *lp;
1826 struct te_tlv_header *tlvh;
1828 if ((OspfMplsTE.status == enabled)
1829 && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
1830 && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
1832 vty_out (vty, "-- MPLS-TE link parameters for %s --%s",
1833 ifp->name, VTY_NEWLINE);
1835 show_vty_link_subtlv_link_type (vty, &lp->link_type.header);
1836 show_vty_link_subtlv_link_id (vty, &lp->link_id.header);
1838 if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL)
1839 show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
1840 if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL)
1841 show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
1843 show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header);
1845 show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header);
1846 show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header);
1847 show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header);
1848 show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header);
1850 else
1852 vty_out (vty, " %s: MPLS-TE is disabled on this interface%s",
1853 ifp->name, VTY_NEWLINE);
1856 return;
1859 DEFUN (show_mpls_te_link,
1860 show_mpls_te_link_cmd,
1861 "show mpls-te interface [INTERFACE]",
1862 SHOW_STR
1863 "MPLS-TE information\n"
1864 "Interface information\n"
1865 "Interface name\n")
1867 struct interface *ifp;
1868 struct listnode *node, *nnode;
1870 /* Show All Interfaces. */
1871 if (argc == 0)
1873 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
1874 show_mpls_te_link_sub (vty, ifp);
1876 /* Interface name is specified. */
1877 else
1879 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
1880 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
1881 else
1882 show_mpls_te_link_sub (vty, ifp);
1885 return CMD_SUCCESS;
1888 static void
1889 ospf_mpls_te_register_vty (void)
1891 install_element (VIEW_NODE, &show_mpls_te_router_cmd);
1892 install_element (VIEW_NODE, &show_mpls_te_link_cmd);
1893 install_element (ENABLE_NODE, &show_mpls_te_router_cmd);
1894 install_element (ENABLE_NODE, &show_mpls_te_link_cmd);
1896 install_element (OSPF_NODE, &mpls_te_cmd);
1897 install_element (OSPF_NODE, &no_mpls_te_cmd);
1898 install_element (OSPF_NODE, &mpls_te_on_cmd);
1899 install_element (OSPF_NODE, &mpls_te_router_addr_cmd);
1901 install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd);
1902 install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd);
1903 install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd);
1904 install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd);
1905 install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd);
1907 return;
1910 #endif /* HAVE_OSPF_TE */