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