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