]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_te.c
Initial revision
[mirror_frr.git] / ospfd / ospf_te.c
CommitLineData
718e3744 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 */