2 * This is an implementation of RFC3630
3 * Copyright (C) 2001 KDD R&D Laboratories, Inc.
4 * http://www.kddlabs.co.jp/
6 * Copyright (C) 2012 Orange Labs
7 * http://www.orange.com
9 * This file is part of GNU Zebra.
11 * GNU Zebra is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2, or (at your option) any
16 * GNU Zebra is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; see the file COPYING; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 /* Add support of RFC7471 */
27 /* Add support of RFC5392, RFC6827 */
44 #include "sockunion.h" /* for inet_aton() */
46 #include "link_state.h"
50 #include "ospfd/ospfd.h"
51 #include "ospfd/ospf_interface.h"
52 #include "ospfd/ospf_ism.h"
53 #include "ospfd/ospf_asbr.h"
54 #include "ospfd/ospf_lsa.h"
55 #include "ospfd/ospf_lsdb.h"
56 #include "ospfd/ospf_neighbor.h"
57 #include "ospfd/ospf_nsm.h"
58 #include "ospfd/ospf_flood.h"
59 #include "ospfd/ospf_packet.h"
60 #include "ospfd/ospf_spf.h"
61 #include "ospfd/ospf_dump.h"
62 #include "ospfd/ospf_route.h"
63 #include "ospfd/ospf_ase.h"
64 #include "ospfd/ospf_zebra.h"
65 #include "ospfd/ospf_te.h"
66 #include "ospfd/ospf_sr.h"
67 #include "ospfd/ospf_ri.h"
68 #include "ospfd/ospf_ext.h"
69 #include "ospfd/ospf_vty.h"
70 #include "ospfd/ospf_errors.h"
73 * Global variable to manage Opaque-LSA/MPLS-TE on this node.
74 * Note that all parameter values are stored in network byte order.
76 struct ospf_mpls_te OspfMplsTE
;
78 static const char *const mode2text
[] = {"Off", "AS", "Area"};
81 /*------------------------------------------------------------------------*
82 * Followings are initialize/terminate functions for MPLS-TE handling.
83 *------------------------------------------------------------------------*/
85 static int ospf_mpls_te_new_if(struct interface
*ifp
);
86 static int ospf_mpls_te_del_if(struct interface
*ifp
);
87 static void ospf_mpls_te_ism_change(struct ospf_interface
*oi
, int old_status
);
88 static void ospf_mpls_te_nsm_change(struct ospf_neighbor
*nbr
, int old_status
);
89 static void ospf_mpls_te_config_write_router(struct vty
*vty
);
90 static void ospf_mpls_te_show_info(struct vty
*vty
, struct json_object
*json
,
91 struct ospf_lsa
*lsa
);
92 static int ospf_mpls_te_lsa_originate_area(void *arg
);
93 static int ospf_mpls_te_lsa_inter_as_as(void *arg
);
94 static int ospf_mpls_te_lsa_inter_as_area(void *arg
);
95 static struct ospf_lsa
*ospf_mpls_te_lsa_refresh(struct ospf_lsa
*lsa
);
96 static int ospf_mpls_te_lsa_update(struct ospf_lsa
*lsa
);
97 static int ospf_mpls_te_lsa_delete(struct ospf_lsa
*lsa
);
99 static void del_mpls_te_link(void *val
);
100 static void ospf_mpls_te_register_vty(void);
102 int ospf_mpls_te_init(void)
106 /* Register Opaque AREA LSA Type 1 for Traffic Engineering */
107 rc
= ospf_register_opaque_functab(
108 OSPF_OPAQUE_AREA_LSA
,
109 OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
,
112 ospf_mpls_te_ism_change
,
113 ospf_mpls_te_nsm_change
,
114 ospf_mpls_te_config_write_router
,
115 NULL
, /* ospf_mpls_te_config_write_if */
116 NULL
, /* ospf_mpls_te_config_write_debug */
117 ospf_mpls_te_show_info
, ospf_mpls_te_lsa_originate_area
,
118 ospf_mpls_te_lsa_refresh
,
119 ospf_mpls_te_lsa_update
, /* ospf_mpls_te_new_lsa_hook */
120 ospf_mpls_te_lsa_delete
/* ospf_mpls_te_del_lsa_hook */);
123 EC_OSPF_OPAQUE_REGISTRATION
,
124 "MPLS-TE (%s): Failed to register Traffic Engineering functions",
130 * Wee need also to register Opaque LSA Type 6 i.e. Inter-AS RFC5392 for
131 * both AREA and AS at least to have the possibility to call the show()
132 * function when looking to the opaque LSA of the OSPF database.
134 rc
= ospf_register_opaque_functab(OSPF_OPAQUE_AREA_LSA
,
135 OPAQUE_TYPE_INTER_AS_LSA
, NULL
,
136 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
137 ospf_mpls_te_show_info
,
138 ospf_mpls_te_lsa_inter_as_area
,
139 ospf_mpls_te_lsa_refresh
, NULL
, NULL
);
142 EC_OSPF_OPAQUE_REGISTRATION
,
143 "MPLS-TE (%s): Failed to register Inter-AS with Area scope",
148 rc
= ospf_register_opaque_functab(OSPF_OPAQUE_AS_LSA
,
149 OPAQUE_TYPE_INTER_AS_LSA
, NULL
,
150 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
151 ospf_mpls_te_show_info
,
152 ospf_mpls_te_lsa_inter_as_as
,
153 ospf_mpls_te_lsa_refresh
, NULL
, NULL
);
156 EC_OSPF_OPAQUE_REGISTRATION
,
157 "MPLS-TE (%s): Failed to register Inter-AS with AS scope",
162 memset(&OspfMplsTE
, 0, sizeof(struct ospf_mpls_te
));
163 OspfMplsTE
.enabled
= false;
164 OspfMplsTE
.export
= false;
165 OspfMplsTE
.inter_as
= Off
;
166 OspfMplsTE
.iflist
= list_new();
167 OspfMplsTE
.iflist
->del
= del_mpls_te_link
;
169 ospf_mpls_te_register_vty();
174 void ospf_mpls_te_term(void)
176 list_delete(&OspfMplsTE
.iflist
);
178 ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA
,
179 OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
);
180 ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA
,
181 OPAQUE_TYPE_INTER_AS_LSA
);
182 ospf_delete_opaque_functab(OSPF_OPAQUE_AS_LSA
,
183 OPAQUE_TYPE_INTER_AS_LSA
);
185 OspfMplsTE
.enabled
= false;
186 OspfMplsTE
.inter_as
= Off
;
187 OspfMplsTE
.export
= false;
192 void ospf_mpls_te_finish(void)
194 OspfMplsTE
.enabled
= false;
195 OspfMplsTE
.inter_as
= Off
;
196 OspfMplsTE
.export
= false;
199 /*------------------------------------------------------------------------*
200 * Followings are control functions for MPLS-TE parameters management.
201 *------------------------------------------------------------------------*/
202 static void del_mpls_te_link(void *val
)
204 XFREE(MTYPE_OSPF_MPLS_TE
, val
);
208 static uint32_t get_mpls_te_instance_value(void)
210 static uint32_t seqno
= 0;
212 if (seqno
< MAX_LEGAL_TE_INSTANCE_NUM
)
215 seqno
= 1; /* Avoid zero. */
220 static struct mpls_te_link
*lookup_linkparams_by_ifp(struct interface
*ifp
)
222 struct listnode
*node
, *nnode
;
223 struct mpls_te_link
*lp
;
225 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
))
232 static struct mpls_te_link
*lookup_linkparams_by_instance(struct ospf_lsa
*lsa
)
234 struct listnode
*node
;
235 struct mpls_te_link
*lp
;
236 unsigned int key
= GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
));
238 for (ALL_LIST_ELEMENTS_RO(OspfMplsTE
.iflist
, node
, lp
))
239 if (lp
->instance
== key
)
242 ote_debug("MPLS-TE (%s): Entry not found: key(%x)", __func__
, key
);
246 static void ospf_mpls_te_foreach_area(
247 void (*func
)(struct mpls_te_link
*lp
, enum lsa_opcode sched_opcode
),
248 enum lsa_opcode sched_opcode
)
250 struct listnode
*node
, *nnode
;
251 struct listnode
*node2
;
252 struct mpls_te_link
*lp
;
253 struct ospf_area
*area
;
255 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
)) {
256 /* Skip Inter-AS TEv2 Links */
257 if (IS_INTER_AS(lp
->type
))
259 if ((area
= lp
->area
) == NULL
)
261 if (CHECK_FLAG(lp
->flags
, LPFLG_LOOKUP_DONE
))
265 (*func
)(lp
, sched_opcode
);
267 for (node2
= listnextnode(node
); node2
;
268 node2
= listnextnode(node2
))
269 if ((lp
= listgetdata(node2
)) != NULL
)
270 if (lp
->area
!= NULL
)
271 if (IPV4_ADDR_SAME(&lp
->area
->area_id
,
277 for (ALL_LIST_ELEMENTS_RO(OspfMplsTE
.iflist
, node
, lp
))
278 if (lp
->area
!= NULL
)
279 UNSET_FLAG(lp
->flags
, LPFLG_LOOKUP_DONE
);
284 static void set_mpls_te_router_addr(struct in_addr ipv4
)
286 OspfMplsTE
.router_addr
.header
.type
= htons(TE_TLV_ROUTER_ADDR
);
287 OspfMplsTE
.router_addr
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
288 OspfMplsTE
.router_addr
.value
= ipv4
;
292 static void set_linkparams_link_header(struct mpls_te_link
*lp
)
296 /* TE_LINK_SUBTLV_LINK_TYPE */
297 if (ntohs(lp
->link_type
.header
.type
) != 0)
298 length
+= TLV_SIZE(&lp
->link_type
.header
);
300 /* TE_LINK_SUBTLV_LINK_ID */
301 if (ntohs(lp
->link_id
.header
.type
) != 0)
302 length
+= TLV_SIZE(&lp
->link_id
.header
);
304 /* TE_LINK_SUBTLV_LCLIF_IPADDR */
305 if (lp
->lclif_ipaddr
.header
.type
!= 0)
306 length
+= TLV_SIZE(&lp
->lclif_ipaddr
.header
);
308 /* TE_LINK_SUBTLV_RMTIF_IPADDR */
309 if (lp
->rmtif_ipaddr
.header
.type
!= 0)
310 length
+= TLV_SIZE(&lp
->rmtif_ipaddr
.header
);
312 /* TE_LINK_SUBTLV_TE_METRIC */
313 if (ntohs(lp
->te_metric
.header
.type
) != 0)
314 length
+= TLV_SIZE(&lp
->te_metric
.header
);
316 /* TE_LINK_SUBTLV_MAX_BW */
317 if (ntohs(lp
->max_bw
.header
.type
) != 0)
318 length
+= TLV_SIZE(&lp
->max_bw
.header
);
320 /* TE_LINK_SUBTLV_MAX_RSV_BW */
321 if (ntohs(lp
->max_rsv_bw
.header
.type
) != 0)
322 length
+= TLV_SIZE(&lp
->max_rsv_bw
.header
);
324 /* TE_LINK_SUBTLV_UNRSV_BW */
325 if (ntohs(lp
->unrsv_bw
.header
.type
) != 0)
326 length
+= TLV_SIZE(&lp
->unrsv_bw
.header
);
328 /* TE_LINK_SUBTLV_RSC_CLSCLR */
329 if (ntohs(lp
->rsc_clsclr
.header
.type
) != 0)
330 length
+= TLV_SIZE(&lp
->rsc_clsclr
.header
);
332 /* TE_LINK_SUBTLV_LLRI */
333 if (ntohs(lp
->llri
.header
.type
) != 0)
334 length
+= TLV_SIZE(&lp
->llri
.header
);
336 /* TE_LINK_SUBTLV_RIP */
337 if (ntohs(lp
->rip
.header
.type
) != 0)
338 length
+= TLV_SIZE(&lp
->rip
.header
);
340 /* TE_LINK_SUBTLV_RAS */
341 if (ntohs(lp
->ras
.header
.type
) != 0)
342 length
+= TLV_SIZE(&lp
->ras
.header
);
344 /* TE_LINK_SUBTLV_LRRID */
345 if (ntohs(lp
->lrrid
.header
.type
) != 0)
346 length
+= TLV_SIZE(&lp
->lrrid
.header
);
348 /* TE_LINK_SUBTLV_AV_DELAY */
349 if (ntohs(lp
->av_delay
.header
.type
) != 0)
350 length
+= TLV_SIZE(&lp
->av_delay
.header
);
352 /* TE_LINK_SUBTLV_MM_DELAY */
353 if (ntohs(lp
->mm_delay
.header
.type
) != 0)
354 length
+= TLV_SIZE(&lp
->mm_delay
.header
);
356 /* TE_LINK_SUBTLV_DELAY_VAR */
357 if (ntohs(lp
->delay_var
.header
.type
) != 0)
358 length
+= TLV_SIZE(&lp
->delay_var
.header
);
360 /* TE_LINK_SUBTLV_PKT_LOSS */
361 if (ntohs(lp
->pkt_loss
.header
.type
) != 0)
362 length
+= TLV_SIZE(&lp
->pkt_loss
.header
);
364 /* TE_LINK_SUBTLV_RES_BW */
365 if (ntohs(lp
->res_bw
.header
.type
) != 0)
366 length
+= TLV_SIZE(&lp
->res_bw
.header
);
368 /* TE_LINK_SUBTLV_AVA_BW */
369 if (ntohs(lp
->ava_bw
.header
.type
) != 0)
370 length
+= TLV_SIZE(&lp
->ava_bw
.header
);
372 /* TE_LINK_SUBTLV_USE_BW */
373 if (ntohs(lp
->use_bw
.header
.type
) != 0)
374 length
+= TLV_SIZE(&lp
->use_bw
.header
);
376 lp
->link_header
.header
.type
= htons(TE_TLV_LINK
);
377 lp
->link_header
.header
.length
= htons(length
);
382 static void set_linkparams_link_type(struct ospf_interface
*oi
,
383 struct mpls_te_link
*lp
)
385 lp
->link_type
.header
.type
= htons(TE_LINK_SUBTLV_LINK_TYPE
);
386 lp
->link_type
.header
.length
= htons(TE_LINK_SUBTLV_TYPE_SIZE
);
389 case OSPF_IFTYPE_POINTOPOINT
:
390 lp
->link_type
.link_type
.value
= LINK_TYPE_SUBTLV_VALUE_PTP
;
392 case OSPF_IFTYPE_BROADCAST
:
393 case OSPF_IFTYPE_NBMA
:
394 lp
->link_type
.link_type
.value
= LINK_TYPE_SUBTLV_VALUE_MA
;
397 /* Not supported yet. */ /* XXX */
398 lp
->link_type
.header
.type
= htons(0);
404 static void set_linkparams_link_id(struct mpls_te_link
*lp
,
405 struct in_addr link_id
)
408 lp
->link_id
.header
.type
= htons(TE_LINK_SUBTLV_LINK_ID
);
409 lp
->link_id
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
410 lp
->link_id
.value
= link_id
;
414 static void set_linkparams_lclif_ipaddr(struct mpls_te_link
*lp
,
415 struct in_addr lclif
)
418 lp
->lclif_ipaddr
.header
.type
= htons(TE_LINK_SUBTLV_LCLIF_IPADDR
);
419 lp
->lclif_ipaddr
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
420 lp
->lclif_ipaddr
.value
[0] = lclif
;
424 static void set_linkparams_rmtif_ipaddr(struct mpls_te_link
*lp
,
425 struct in_addr rmtif
)
428 lp
->rmtif_ipaddr
.header
.type
= htons(TE_LINK_SUBTLV_RMTIF_IPADDR
);
429 lp
->rmtif_ipaddr
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
430 lp
->rmtif_ipaddr
.value
[0] = rmtif
;
434 static void set_linkparams_te_metric(struct mpls_te_link
*lp
,
437 lp
->te_metric
.header
.type
= htons(TE_LINK_SUBTLV_TE_METRIC
);
438 lp
->te_metric
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
439 lp
->te_metric
.value
= htonl(te_metric
);
443 static void set_linkparams_max_bw(struct mpls_te_link
*lp
, float fp
)
445 lp
->max_bw
.header
.type
= htons(TE_LINK_SUBTLV_MAX_BW
);
446 lp
->max_bw
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
447 lp
->max_bw
.value
= htonf(fp
);
451 static void set_linkparams_max_rsv_bw(struct mpls_te_link
*lp
, float fp
)
453 lp
->max_rsv_bw
.header
.type
= htons(TE_LINK_SUBTLV_MAX_RSV_BW
);
454 lp
->max_rsv_bw
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
455 lp
->max_rsv_bw
.value
= htonf(fp
);
459 static void set_linkparams_unrsv_bw(struct mpls_te_link
*lp
, int priority
,
462 /* Note that TLV-length field is the size of array. */
463 lp
->unrsv_bw
.header
.type
= htons(TE_LINK_SUBTLV_UNRSV_BW
);
464 lp
->unrsv_bw
.header
.length
= htons(TE_LINK_SUBTLV_UNRSV_SIZE
);
465 lp
->unrsv_bw
.value
[priority
] = htonf(fp
);
469 static void set_linkparams_rsc_clsclr(struct mpls_te_link
*lp
,
472 lp
->rsc_clsclr
.header
.type
= htons(TE_LINK_SUBTLV_RSC_CLSCLR
);
473 lp
->rsc_clsclr
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
474 lp
->rsc_clsclr
.value
= htonl(classcolor
);
478 static void set_linkparams_inter_as(struct mpls_te_link
*lp
,
479 struct in_addr addr
, uint32_t as
)
482 /* Set the Remote ASBR IP address and then the associated AS number */
483 lp
->rip
.header
.type
= htons(TE_LINK_SUBTLV_RIP
);
484 lp
->rip
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
485 lp
->rip
.value
= addr
;
487 lp
->ras
.header
.type
= htons(TE_LINK_SUBTLV_RAS
);
488 lp
->ras
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
489 lp
->ras
.value
= htonl(as
);
491 /* Set Type & Flooding flag accordingly */
493 if (OspfMplsTE
.inter_as
== AS
)
494 SET_FLAG(lp
->flags
, LPFLG_LSA_FLOOD_AS
);
496 UNSET_FLAG(lp
->flags
, LPFLG_LSA_FLOOD_AS
);
499 static void unset_linkparams_inter_as(struct mpls_te_link
*lp
)
502 /* Reset the Remote ASBR IP address and then the associated AS number */
503 lp
->rip
.header
.type
= htons(0);
504 lp
->rip
.header
.length
= htons(0);
505 lp
->rip
.value
.s_addr
= htonl(0);
507 lp
->ras
.header
.type
= htons(0);
508 lp
->ras
.header
.length
= htons(0);
509 lp
->ras
.value
= htonl(0);
511 /* Reset Type & Flooding flag accordingly */
513 UNSET_FLAG(lp
->flags
, LPFLG_LSA_FLOOD_AS
);
516 void set_linkparams_llri(struct mpls_te_link
*lp
, uint32_t local
,
520 lp
->llri
.header
.type
= htons(TE_LINK_SUBTLV_LLRI
);
521 lp
->llri
.header
.length
= htons(TE_LINK_SUBTLV_LLRI_SIZE
);
522 lp
->llri
.local
= htonl(local
);
523 lp
->llri
.remote
= htonl(remote
);
526 void set_linkparams_lrrid(struct mpls_te_link
*lp
, struct in_addr local
,
527 struct in_addr remote
)
530 lp
->lrrid
.header
.type
= htons(TE_LINK_SUBTLV_LRRID
);
531 lp
->lrrid
.header
.length
= htons(TE_LINK_SUBTLV_LRRID_SIZE
);
532 lp
->lrrid
.local
.s_addr
= local
.s_addr
;
533 lp
->lrrid
.remote
.s_addr
= remote
.s_addr
;
536 static void set_linkparams_av_delay(struct mpls_te_link
*lp
, uint32_t delay
,
540 /* Note that TLV-length field is the size of array. */
541 lp
->av_delay
.header
.type
= htons(TE_LINK_SUBTLV_AV_DELAY
);
542 lp
->av_delay
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
543 tmp
= delay
& TE_EXT_MASK
;
545 tmp
|= TE_EXT_ANORMAL
;
546 lp
->av_delay
.value
= htonl(tmp
);
550 static void set_linkparams_mm_delay(struct mpls_te_link
*lp
, uint32_t low
,
551 uint32_t high
, uint8_t anormal
)
554 /* Note that TLV-length field is the size of array. */
555 lp
->mm_delay
.header
.type
= htons(TE_LINK_SUBTLV_MM_DELAY
);
556 lp
->mm_delay
.header
.length
= htons(TE_LINK_SUBTLV_MM_DELAY_SIZE
);
557 tmp
= low
& TE_EXT_MASK
;
559 tmp
|= TE_EXT_ANORMAL
;
560 lp
->mm_delay
.low
= htonl(tmp
);
561 lp
->mm_delay
.high
= htonl(high
);
565 static void set_linkparams_delay_var(struct mpls_te_link
*lp
, uint32_t jitter
)
567 /* Note that TLV-length field is the size of array. */
568 lp
->delay_var
.header
.type
= htons(TE_LINK_SUBTLV_DELAY_VAR
);
569 lp
->delay_var
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
570 lp
->delay_var
.value
= htonl(jitter
& TE_EXT_MASK
);
574 static void set_linkparams_pkt_loss(struct mpls_te_link
*lp
, uint32_t loss
,
578 /* Note that TLV-length field is the size of array. */
579 lp
->pkt_loss
.header
.type
= htons(TE_LINK_SUBTLV_PKT_LOSS
);
580 lp
->pkt_loss
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
581 tmp
= loss
& TE_EXT_MASK
;
583 tmp
|= TE_EXT_ANORMAL
;
584 lp
->pkt_loss
.value
= htonl(tmp
);
588 static void set_linkparams_res_bw(struct mpls_te_link
*lp
, float fp
)
590 /* Note that TLV-length field is the size of array. */
591 lp
->res_bw
.header
.type
= htons(TE_LINK_SUBTLV_RES_BW
);
592 lp
->res_bw
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
593 lp
->res_bw
.value
= htonf(fp
);
597 static void set_linkparams_ava_bw(struct mpls_te_link
*lp
, float fp
)
599 /* Note that TLV-length field is the size of array. */
600 lp
->ava_bw
.header
.type
= htons(TE_LINK_SUBTLV_AVA_BW
);
601 lp
->ava_bw
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
602 lp
->ava_bw
.value
= htonf(fp
);
606 static void set_linkparams_use_bw(struct mpls_te_link
*lp
, float fp
)
608 /* Note that TLV-length field is the size of array. */
609 lp
->use_bw
.header
.type
= htons(TE_LINK_SUBTLV_USE_BW
);
610 lp
->use_bw
.header
.length
= htons(TE_LINK_SUBTLV_DEF_SIZE
);
611 lp
->use_bw
.value
= htonf(fp
);
615 /* Update TE parameters from Interface */
616 static void update_linkparams(struct mpls_te_link
*lp
)
619 struct interface
*ifp
;
621 /* Get the Interface structure */
622 if ((ifp
= lp
->ifp
) == NULL
) {
624 "MPLS-TE (%s): Abort update TE parameters: no interface associated to Link Parameters",
628 if (!HAS_LINK_PARAMS(ifp
)) {
630 "MPLS-TE (%s): Abort update TE parameters: no Link Parameters for interface",
635 /* RFC3630 metrics */
636 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
))
637 set_linkparams_rsc_clsclr(lp
, ifp
->link_params
->admin_grp
);
639 TLV_TYPE(lp
->rsc_clsclr
) = 0;
641 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
))
642 set_linkparams_max_bw(lp
, ifp
->link_params
->max_bw
);
644 TLV_TYPE(lp
->max_bw
) = 0;
646 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
))
647 set_linkparams_max_rsv_bw(lp
, ifp
->link_params
->max_rsv_bw
);
649 TLV_TYPE(lp
->max_rsv_bw
) = 0;
651 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
))
652 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
653 set_linkparams_unrsv_bw(lp
, i
,
654 ifp
->link_params
->unrsv_bw
[i
]);
656 TLV_TYPE(lp
->unrsv_bw
) = 0;
658 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
))
659 set_linkparams_te_metric(lp
, ifp
->link_params
->te_metric
);
661 TLV_TYPE(lp
->te_metric
) = 0;
663 /* TE metric Extensions */
664 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
))
665 set_linkparams_av_delay(lp
, ifp
->link_params
->av_delay
, 0);
667 TLV_TYPE(lp
->av_delay
) = 0;
669 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
))
670 set_linkparams_mm_delay(lp
, ifp
->link_params
->min_delay
,
671 ifp
->link_params
->max_delay
, 0);
673 TLV_TYPE(lp
->mm_delay
) = 0;
675 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
))
676 set_linkparams_delay_var(lp
, ifp
->link_params
->delay_var
);
678 TLV_TYPE(lp
->delay_var
) = 0;
680 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
))
681 set_linkparams_pkt_loss(lp
, ifp
->link_params
->pkt_loss
, 0);
683 TLV_TYPE(lp
->pkt_loss
) = 0;
685 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
))
686 set_linkparams_res_bw(lp
, ifp
->link_params
->res_bw
);
688 TLV_TYPE(lp
->res_bw
) = 0;
690 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
))
691 set_linkparams_ava_bw(lp
, ifp
->link_params
->ava_bw
);
693 TLV_TYPE(lp
->ava_bw
) = 0;
695 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
))
696 set_linkparams_use_bw(lp
, ifp
->link_params
->use_bw
);
698 TLV_TYPE(lp
->use_bw
) = 0;
701 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
702 /* Flush LSA if it engaged and was previously a STD_TE one */
703 if (IS_STD_TE(lp
->type
)
704 && CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
)) {
706 "MPLS-TE (%s): Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]",
707 __func__
, ifp
->name
, lp
->flags
, lp
->type
);
709 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
710 /* Then, switch it to INTER-AS */
711 if (OspfMplsTE
.inter_as
== AS
) {
713 SET_FLAG(lp
->flags
, LPFLG_LSA_FLOOD_AS
);
716 UNSET_FLAG(lp
->flags
, LPFLG_LSA_FLOOD_AS
);
717 lp
->area
= ospf_area_lookup_by_area_id(
718 ospf_lookup_by_vrf_id(VRF_DEFAULT
),
719 OspfMplsTE
.interas_areaid
);
722 set_linkparams_inter_as(lp
, ifp
->link_params
->rmt_ip
,
723 ifp
->link_params
->rmt_as
);
726 "MPLS-TE (%s): Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]",
727 __func__
, ifp
->name
, lp
->flags
, lp
->type
);
729 /* reset inter-as TE params */
730 /* Flush LSA if it engaged and was previously an INTER_AS one */
731 if (IS_INTER_AS(lp
->type
)
732 && CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
)) {
733 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
734 /* Then, switch it to Standard TE */
736 UNSET_FLAG(lp
->flags
, LPFLG_LSA_FLOOD_AS
);
738 unset_linkparams_inter_as(lp
);
742 static void initialize_linkparams(struct mpls_te_link
*lp
)
744 struct interface
*ifp
= lp
->ifp
;
745 struct ospf_interface
*oi
= NULL
;
746 struct route_node
*rn
;
748 ote_debug("MPLS-TE (%s): Initialize Link Parameters for interface %s",
749 __func__
, ifp
->name
);
751 /* Search OSPF Interface parameters for this interface */
752 for (rn
= route_top(IF_OIFS(ifp
)); rn
; rn
= route_next(rn
)) {
754 if ((oi
= rn
->info
) == NULL
)
761 if ((oi
== NULL
) || (oi
->ifp
!= ifp
)) {
763 "MPLS-TE (%s): Could not find corresponding OSPF Interface for %s",
764 __func__
, ifp
->name
);
769 * Try to set initial values those can be derived from
770 * zebra-interface information.
772 set_linkparams_link_type(oi
, lp
);
774 /* Set local IP addr */
775 set_linkparams_lclif_ipaddr(lp
, oi
->address
->u
.prefix4
);
777 /* Set Remote IP addr if Point to Point Interface */
778 if (oi
->type
== OSPF_IFTYPE_POINTOPOINT
) {
779 struct prefix
*pref
= CONNECTED_PREFIX(oi
->connected
);
781 set_linkparams_rmtif_ipaddr(lp
, pref
->u
.prefix4
);
784 /* Keep Area information in combination with link parameters. */
790 static int is_mandated_params_set(struct mpls_te_link
*lp
)
794 if (ntohs(OspfMplsTE
.router_addr
.header
.type
) == 0) {
795 flog_warn(EC_OSPF_TE_UNEXPECTED
,
796 "MPLS-TE (%s): Missing Router Address", __func__
);
800 if (ntohs(lp
->link_type
.header
.type
) == 0) {
801 flog_warn(EC_OSPF_TE_UNEXPECTED
,
802 "MPLS-TE (%s): Missing Link Type", __func__
);
806 if (!IS_INTER_AS(lp
->type
) && (ntohs(lp
->link_id
.header
.type
) == 0)) {
807 flog_warn(EC_OSPF_TE_UNEXPECTED
, "MPLS-TE (%s) Missing Link ID",
816 /*------------------------------------------------------------------------*
817 * Followings are callback functions against generic Opaque-LSAs handling.
818 *------------------------------------------------------------------------*/
820 static int ospf_mpls_te_new_if(struct interface
*ifp
)
822 struct mpls_te_link
*new;
824 ote_debug("MPLS-TE (%s): Add new %s interface %s to MPLS-TE list",
825 __func__
, ifp
->link_params
? "Active" : "Inactive",
828 if (lookup_linkparams_by_ifp(ifp
) != NULL
)
831 new = XCALLOC(MTYPE_OSPF_MPLS_TE
, sizeof(struct mpls_te_link
));
833 new->instance
= get_mpls_te_instance_value();
835 /* By default TE-Link is RFC3630 compatible flooding in Area and not
837 /* This default behavior will be adapted with call to
838 * ospf_mpls_te_update_if() */
840 new->flags
= LPFLG_LSA_INACTIVE
;
842 /* Initialize Link Parameters from Interface */
843 initialize_linkparams(new);
845 /* Set TE Parameters from Interface */
846 update_linkparams(new);
848 /* Add Link Parameters structure to the list */
849 listnode_add(OspfMplsTE
.iflist
, new);
851 ote_debug("MPLS-TE (%s): Add new LP context for %s[%d/%d]", __func__
,
852 ifp
->name
, new->flags
, new->type
);
854 /* Schedule Opaque-LSA refresh. */ /* XXX */
858 static int ospf_mpls_te_del_if(struct interface
*ifp
)
860 struct mpls_te_link
*lp
;
863 if ((lp
= lookup_linkparams_by_ifp(ifp
)) != NULL
) {
864 struct list
*iflist
= OspfMplsTE
.iflist
;
866 /* Dequeue listnode entry from the list. */
867 listnode_delete(iflist
, lp
);
869 XFREE(MTYPE_OSPF_MPLS_TE
, lp
);
872 /* Schedule Opaque-LSA refresh. */ /* XXX */
878 /* Main initialization / update function of the MPLS TE Link context */
880 /* Call when interface TE Link parameters are modified */
881 void ospf_mpls_te_update_if(struct interface
*ifp
)
883 struct mpls_te_link
*lp
;
885 ote_debug("MPLS-TE (%s): Update LSA parameters for interface %s [%s]",
886 __func__
, ifp
->name
, HAS_LINK_PARAMS(ifp
) ? "ON" : "OFF");
888 /* Get Link context from interface */
889 if ((lp
= lookup_linkparams_by_ifp(ifp
)) == NULL
) {
891 EC_OSPF_TE_UNEXPECTED
,
892 "MPLS-TE (%s): Did not find Link Parameters context for interface %s",
893 __func__
, ifp
->name
);
897 /* Fulfill MPLS-TE Link TLV from Interface TE Link parameters */
898 if (HAS_LINK_PARAMS(ifp
)) {
899 SET_FLAG(lp
->flags
, LPFLG_LSA_ACTIVE
);
901 /* Update TE parameters */
902 update_linkparams(lp
);
904 /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is
906 if (OspfMplsTE
.enabled
)
907 if (lp
->area
!= NULL
) {
908 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
))
909 ospf_mpls_te_lsa_schedule(
910 lp
, REFRESH_THIS_LSA
);
912 ospf_mpls_te_lsa_schedule(
913 lp
, REORIGINATE_THIS_LSA
);
916 /* If MPLS TE is disable on this interface, flush LSA if it is
918 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
))
919 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
921 /* Reset Activity flag */
922 lp
->flags
= LPFLG_LSA_INACTIVE
;
929 * Just add interface and set available information. Other information
930 * and flooding of LSA will be done later when adjacency will be up
931 * See ospf_mpls_te_nsm_change() after
933 static void ospf_mpls_te_ism_change(struct ospf_interface
*oi
, int old_state
)
936 struct mpls_te_link
*lp
;
938 lp
= lookup_linkparams_by_ifp(oi
->ifp
);
941 EC_OSPF_TE_UNEXPECTED
,
942 "MPLS-TE (%s): Cannot get linkparams from OI(%s)?",
943 __func__
, IF_NAME(oi
));
947 if (oi
->area
== NULL
|| oi
->area
->ospf
== NULL
) {
949 EC_OSPF_TE_UNEXPECTED
,
950 "MPLS-TE (%s): Cannot refer to OSPF from OI(%s)?",
951 __func__
, IF_NAME(oi
));
955 /* Keep Area information in combination with linkparams. */
959 case ISM_PointToPoint
:
963 /* Set Link type and Local IP addr */
964 set_linkparams_link_type(oi
, lp
);
965 set_linkparams_lclif_ipaddr(lp
, oi
->address
->u
.prefix4
);
969 /* Interface goes Down: Flush LSA if engaged */
970 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
)) {
972 "MPLS-TE (%s): Interface %s goes down: flush LSA",
973 __func__
, IF_NAME(oi
));
974 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
982 ote_debug("MPLS-TE (%s): Update Link parameters for interface %s",
983 __func__
, IF_NAME(oi
));
989 * Complete TE info and schedule LSA flooding
990 * Link-ID and Remote IP address must be set with neighbor info
991 * which are only valid once NSM state is FULL
993 static void ospf_mpls_te_nsm_change(struct ospf_neighbor
*nbr
, int old_state
)
995 struct ospf_interface
*oi
= nbr
->oi
;
996 struct mpls_te_link
*lp
;
998 /* Process Neighbor only when its state is NSM Full */
999 if (nbr
->state
!= NSM_Full
)
1002 /* Get interface information for Traffic Engineering */
1003 lp
= lookup_linkparams_by_ifp(oi
->ifp
);
1006 EC_OSPF_TE_UNEXPECTED
,
1007 "MPLS-TE (%s): Cannot get linkparams from OI(%s)?",
1008 __func__
, IF_NAME(oi
));
1012 if (oi
->area
== NULL
|| oi
->area
->ospf
== NULL
) {
1014 EC_OSPF_TE_UNEXPECTED
,
1015 "MPLS-TE (%s): Cannot refer to OSPF from OI(%s)?",
1016 __func__
, IF_NAME(oi
));
1020 /* Flush TE Opaque LSA if Neighbor State goes Down or Deleted */
1021 if (OspfMplsTE
.enabled
1022 && (nbr
->state
== NSM_Down
|| nbr
->state
== NSM_Deleted
)) {
1023 if (CHECK_FLAG(lp
->flags
, EXT_LPFLG_LSA_ENGAGED
)) {
1025 "MPLS-TE (%s): Interface %s goes down: flush LSA",
1026 __func__
, IF_NAME(oi
));
1027 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
1032 /* Keep Area information in combination with SR info. */
1033 lp
->area
= oi
->area
;
1036 * The Link ID is identical to the contents of the Link ID field
1037 * in the Router LSA for these link types.
1039 switch (oi
->state
) {
1040 case ISM_PointToPoint
:
1041 /* Set Link ID with neighbor Router ID */
1042 set_linkparams_link_id(lp
, nbr
->router_id
);
1043 /* Set Remote IP address */
1044 set_linkparams_rmtif_ipaddr(lp
, nbr
->address
.u
.prefix4
);
1050 /* Set Link ID with the Designated Router ID */
1051 set_linkparams_link_id(lp
, DR(oi
));
1055 /* State goes Down: Flush LSA if engaged */
1056 if (OspfMplsTE
.enabled
1057 && CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
)) {
1059 "MPLS-TE (%s): Interface %s goes down: flush LSA",
1060 __func__
, IF_NAME(oi
));
1061 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
1068 ote_debug("MPLS-TE (%s): Add Link-ID %pI4 for interface %s ", __func__
,
1069 &lp
->link_id
.value
, oi
->ifp
->name
);
1071 /* Try to Schedule LSA */
1072 if (OspfMplsTE
.enabled
) {
1073 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
))
1074 ospf_mpls_te_lsa_schedule(lp
, REFRESH_THIS_LSA
);
1076 ospf_mpls_te_lsa_schedule(lp
, REORIGINATE_THIS_LSA
);
1081 /*------------------------------------------------------------------------*
1082 * Followings are OSPF protocol processing functions for MPLS-TE LSA.
1083 *------------------------------------------------------------------------*/
1085 static void build_tlv_header(struct stream
*s
, struct tlv_header
*tlvh
)
1087 stream_put(s
, tlvh
, sizeof(struct tlv_header
));
1091 static void build_router_tlv(struct stream
*s
)
1093 struct tlv_header
*tlvh
= &OspfMplsTE
.router_addr
.header
;
1094 if (ntohs(tlvh
->type
) != 0) {
1095 build_tlv_header(s
, tlvh
);
1096 stream_put(s
, TLV_DATA(tlvh
), TLV_BODY_SIZE(tlvh
));
1101 static void build_link_subtlv(struct stream
*s
, struct tlv_header
*tlvh
)
1104 if ((tlvh
!= NULL
) && (ntohs(tlvh
->type
) != 0)) {
1105 build_tlv_header(s
, tlvh
);
1106 stream_put(s
, TLV_DATA(tlvh
), TLV_BODY_SIZE(tlvh
));
1111 static void build_link_tlv(struct stream
*s
, struct mpls_te_link
*lp
)
1113 set_linkparams_link_header(lp
);
1114 build_tlv_header(s
, &lp
->link_header
.header
);
1116 build_link_subtlv(s
, &lp
->link_type
.header
);
1117 build_link_subtlv(s
, &lp
->link_id
.header
);
1118 build_link_subtlv(s
, &lp
->lclif_ipaddr
.header
);
1119 build_link_subtlv(s
, &lp
->rmtif_ipaddr
.header
);
1120 build_link_subtlv(s
, &lp
->te_metric
.header
);
1121 build_link_subtlv(s
, &lp
->max_bw
.header
);
1122 build_link_subtlv(s
, &lp
->max_rsv_bw
.header
);
1123 build_link_subtlv(s
, &lp
->unrsv_bw
.header
);
1124 build_link_subtlv(s
, &lp
->rsc_clsclr
.header
);
1125 build_link_subtlv(s
, &lp
->lrrid
.header
);
1126 build_link_subtlv(s
, &lp
->llri
.header
);
1127 build_link_subtlv(s
, &lp
->rip
.header
);
1128 build_link_subtlv(s
, &lp
->ras
.header
);
1129 build_link_subtlv(s
, &lp
->av_delay
.header
);
1130 build_link_subtlv(s
, &lp
->mm_delay
.header
);
1131 build_link_subtlv(s
, &lp
->delay_var
.header
);
1132 build_link_subtlv(s
, &lp
->pkt_loss
.header
);
1133 build_link_subtlv(s
, &lp
->res_bw
.header
);
1134 build_link_subtlv(s
, &lp
->ava_bw
.header
);
1135 build_link_subtlv(s
, &lp
->use_bw
.header
);
1140 static void ospf_mpls_te_lsa_body_set(struct stream
*s
, struct mpls_te_link
*lp
)
1143 * The router address TLV is type 1, and ... It must appear in exactly
1144 * one Traffic Engineering LSA originated by a router but not in
1147 if (!IS_INTER_AS(lp
->type
))
1148 build_router_tlv(s
);
1151 * Only one Link TLV shall be carried in each LSA, allowing for fine
1152 * granularity changes in topology.
1154 build_link_tlv(s
, lp
);
1158 /* Create new opaque-LSA. */
1159 static struct ospf_lsa
*ospf_mpls_te_lsa_new(struct ospf
*ospf
,
1160 struct ospf_area
*area
,
1161 struct mpls_te_link
*lp
)
1164 struct lsa_header
*lsah
;
1165 struct ospf_lsa
*new = NULL
;
1166 uint8_t options
, lsa_type
= 0;
1167 struct in_addr lsa_id
;
1171 /* Create a stream for LSA. */
1172 s
= stream_new(OSPF_MAX_LSA_SIZE
);
1173 lsah
= (struct lsa_header
*)STREAM_DATA(s
);
1175 options
= OSPF_OPTION_O
; /* Don't forget this :-) */
1177 /* Set opaque-LSA header fields depending of the type of RFC */
1178 if (IS_INTER_AS(lp
->type
)) {
1179 if (IS_FLOOD_AS(lp
->flags
)) {
1180 /* Enable AS external as we flood Inter-AS with Opaque
1183 options
|= OSPF_OPTION_E
;
1184 lsa_type
= OSPF_OPAQUE_AS_LSA
;
1186 options
|= LSA_OPTIONS_GET(
1187 area
); /* Get area default option */
1188 options
|= LSA_OPTIONS_NSSA_GET(area
);
1189 lsa_type
= OSPF_OPAQUE_AREA_LSA
;
1191 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA
, lp
->instance
);
1192 lsa_id
.s_addr
= htonl(tmp
);
1199 lsa_header_set(s
, options
, lsa_type
, lsa_id
, ospf
->router_id
);
1201 options
|= LSA_OPTIONS_GET(area
); /* Get area default option */
1202 options
|= LSA_OPTIONS_NSSA_GET(area
);
1203 lsa_type
= OSPF_OPAQUE_AREA_LSA
;
1204 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
,
1206 lsa_id
.s_addr
= htonl(tmp
);
1207 lsa_header_set(s
, options
, lsa_type
, lsa_id
,
1208 area
->ospf
->router_id
);
1212 "MPLS-TE (%s): LSA[Type%d:%pI4]: Create an Opaque-LSA/MPLS-TE instance",
1213 __func__
, lsa_type
, &lsa_id
);
1215 /* Set opaque-LSA body fields. */
1216 ospf_mpls_te_lsa_body_set(s
, lp
);
1219 length
= stream_get_endp(s
);
1220 lsah
->length
= htons(length
);
1222 /* Now, create an OSPF LSA instance. */
1223 new = ospf_lsa_new_and_data(length
);
1225 new->vrf_id
= ospf
->vrf_id
;
1226 if (area
&& area
->ospf
)
1227 new->vrf_id
= area
->ospf
->vrf_id
;
1229 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
1230 memcpy(new->data
, lsah
, length
);
1236 static int ospf_mpls_te_lsa_originate1(struct ospf_area
*area
,
1237 struct mpls_te_link
*lp
)
1239 struct ospf_lsa
*new = NULL
;
1242 /* Create new Opaque-LSA/MPLS-TE instance. */
1243 new = ospf_mpls_te_lsa_new(area
->ospf
, area
, lp
);
1245 flog_warn(EC_OSPF_TE_UNEXPECTED
,
1246 "MPLS-TE (%s): ospf_mpls_te_lsa_new() ?", __func__
);
1250 /* Install this LSA into LSDB. */
1251 if (ospf_lsa_install(area
->ospf
, NULL
/*oi*/, new) == NULL
) {
1252 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1253 "MPLS-TE (%s): ospf_lsa_install() ?", __func__
);
1254 ospf_lsa_unlock(&new);
1258 /* Now this link-parameter entry has associated LSA. */
1259 SET_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
);
1260 /* Update new LSA origination count. */
1261 area
->ospf
->lsa_originate_count
++;
1263 /* Flood new LSA through area. */
1264 ospf_flood_through_area(area
, NULL
/*nbr*/, new);
1267 "MPLS-TE (%s): LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE: Area(%pI4), Link(%s)",
1268 __func__
, new->data
->type
, &new->data
->id
, &area
->area_id
,
1270 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
1271 ospf_lsa_header_dump(new->data
);
1277 static int ospf_mpls_te_lsa_originate_area(void *arg
)
1279 struct ospf_area
*area
= (struct ospf_area
*)arg
;
1280 struct listnode
*node
, *nnode
;
1281 struct mpls_te_link
*lp
;
1284 if (!OspfMplsTE
.enabled
) {
1285 ote_debug("MPLS-TE (%s): MPLS-TE is disabled now.", __func__
);
1286 rc
= 0; /* This is not an error case. */
1290 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
)) {
1291 /* Process only enabled LSA with area scope flooding */
1292 if (!CHECK_FLAG(lp
->flags
, LPFLG_LSA_ACTIVE
)
1293 || IS_FLOOD_AS(lp
->flags
))
1296 if (lp
->area
== NULL
)
1299 if (!IPV4_ADDR_SAME(&lp
->area
->area_id
, &area
->area_id
))
1302 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
)) {
1303 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_FORCED_REFRESH
)) {
1304 UNSET_FLAG(lp
->flags
, LPFLG_LSA_FORCED_REFRESH
);
1306 "MPLS-TE (%s): Refresh instead of Originate",
1308 ospf_mpls_te_lsa_schedule(lp
, REFRESH_THIS_LSA
);
1313 if (!is_mandated_params_set(lp
)) {
1315 "MPLS-TE (%s): Link(%s) lacks some mandated MPLS-TE parameters.",
1316 __func__
, lp
->ifp
? lp
->ifp
->name
: "?");
1320 /* Ok, let's try to originate an LSA for this area and Link. */
1322 "MPLS-TE (%s): Let's finally reoriginate the LSA %d through the Area %pI4 for Link %s",
1323 __func__
, lp
->instance
, &area
->area_id
,
1324 lp
->ifp
? lp
->ifp
->name
: "?");
1325 if (ospf_mpls_te_lsa_originate1(area
, lp
) != 0)
1333 static int ospf_mpls_te_lsa_originate2(struct ospf
*top
,
1334 struct mpls_te_link
*lp
)
1336 struct ospf_lsa
*new;
1339 /* Create new Opaque-LSA/Inter-AS instance. */
1340 new = ospf_mpls_te_lsa_new(top
, NULL
, lp
);
1342 flog_warn(EC_OSPF_LSA_UNEXPECTED
,
1343 "MPLS-TE (%s): ospf_router_info_lsa_new() ?",
1347 new->vrf_id
= top
->vrf_id
;
1349 /* Install this LSA into LSDB. */
1350 if (ospf_lsa_install(top
, NULL
/*oi */, new) == NULL
) {
1351 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1352 "MPLS-TE (%s): ospf_lsa_install() ?", __func__
);
1353 ospf_lsa_unlock(&new);
1357 /* Now this Router Info parameter entry has associated LSA. */
1358 SET_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
);
1359 /* Update new LSA origination count. */
1360 top
->lsa_originate_count
++;
1362 /* Flood new LSA through AS. */
1363 ospf_flood_through_as(top
, NULL
/*nbr */, new);
1366 "MPLS-TE (%s): LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE Inter-AS",
1367 __func__
, new->data
->type
, &new->data
->id
);
1368 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
1369 ospf_lsa_header_dump(new->data
);
1376 static int ospf_mpls_te_lsa_originate_as(void *arg
)
1379 struct ospf_area
*area
;
1380 struct listnode
*node
, *nnode
;
1381 struct mpls_te_link
*lp
;
1384 if ((!OspfMplsTE
.enabled
) || (OspfMplsTE
.inter_as
== Off
)) {
1385 ote_debug("MPLS-TE (%s): Inter-AS is disabled for now",
1387 rc
= 0; /* This is not an error case. */
1391 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
)) {
1392 /* Process only enabled INTER_AS Links or Pseudo-Links */
1393 if (!CHECK_FLAG(lp
->flags
, LPFLG_LSA_ACTIVE
)
1394 || !CHECK_FLAG(lp
->flags
, LPFLG_LSA_FLOOD_AS
)
1395 || !IS_INTER_AS(lp
->type
))
1398 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
)) {
1399 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_FORCED_REFRESH
)) {
1400 UNSET_FLAG(lp
->flags
, LPFLG_LSA_FORCED_REFRESH
);
1401 ospf_mpls_te_lsa_schedule(lp
, REFRESH_THIS_LSA
);
1406 if (!is_mandated_params_set(lp
)) {
1408 EC_OSPF_TE_UNEXPECTED
,
1409 "MPLS-TE (%s): Link(%s) lacks some mandated MPLS-TE parameters.",
1410 __func__
, lp
->ifp
? lp
->ifp
->name
: "?");
1414 /* Ok, let's try to originate an LSA for this AS and Link. */
1416 "MPLS-TE (%s): Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s",
1417 __func__
, lp
->instance
,
1418 IS_FLOOD_AS(lp
->flags
) ? "AS" : "Area",
1419 lp
->ifp
? lp
->ifp
->name
: "Unknown");
1421 if (IS_FLOOD_AS(lp
->flags
)) {
1422 top
= (struct ospf
*)arg
;
1423 ospf_mpls_te_lsa_originate2(top
, lp
);
1425 area
= (struct ospf_area
*)arg
;
1426 ospf_mpls_te_lsa_originate1(area
, lp
);
1435 * As Inter-AS LSA must be registered with both AREA and AS flooding, and
1436 * because all origination callback functions are call (disregarding the Opaque
1437 * LSA type and Flooding scope) it is necessary to determine which flooding
1438 * scope is associated with the LSA origination as parameter is of type void and
1439 * must be cast to struct *ospf for AS flooding and to struct *ospf_area for
1442 static int ospf_mpls_te_lsa_inter_as_as(void *arg
)
1444 if (OspfMplsTE
.inter_as
== AS
)
1445 return ospf_mpls_te_lsa_originate_as(arg
);
1450 static int ospf_mpls_te_lsa_inter_as_area(void *arg
)
1452 if (OspfMplsTE
.inter_as
== Area
)
1453 return ospf_mpls_te_lsa_originate_area(arg
);
1458 static struct ospf_lsa
*ospf_mpls_te_lsa_refresh(struct ospf_lsa
*lsa
)
1460 struct mpls_te_link
*lp
;
1461 struct ospf_area
*area
= lsa
->area
;
1463 struct ospf_lsa
*new = NULL
;
1465 if (!OspfMplsTE
.enabled
) {
1467 * This LSA must have flushed before due to MPLS-TE status
1469 * It seems a slip among routers in the routing domain.
1471 ote_debug("MPLS-TE (%s): MPLS-TE is disabled now", __func__
);
1473 htons(OSPF_LSA_MAXAGE
); /* Flush it anyway. */
1476 /* At first, resolve lsa/lp relationship. */
1477 if ((lp
= lookup_linkparams_by_instance(lsa
)) == NULL
) {
1478 flog_warn(EC_OSPF_TE_UNEXPECTED
,
1479 "MPLS-TE (%s): Invalid parameter?", __func__
);
1481 htons(OSPF_LSA_MAXAGE
); /* Flush it anyway. */
1482 ospf_opaque_lsa_flush_schedule(lsa
);
1486 /* Check if lp was not disable in the interval */
1487 if (!CHECK_FLAG(lp
->flags
, LPFLG_LSA_ACTIVE
)) {
1488 flog_warn(EC_OSPF_TE_UNEXPECTED
,
1489 "MPLS-TE (%s): lp was disabled: Flush it!", __func__
);
1491 htons(OSPF_LSA_MAXAGE
); /* Flush it anyway. */
1494 /* If the lsa's age reached to MaxAge, start flushing procedure. */
1495 if (IS_LSA_MAXAGE(lsa
)) {
1496 UNSET_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
);
1497 ospf_opaque_lsa_flush_schedule(lsa
);
1500 top
= ospf_lookup_by_vrf_id(lsa
->vrf_id
);
1501 /* Create new Opaque-LSA/MPLS-TE instance. */
1502 new = ospf_mpls_te_lsa_new(top
, area
, lp
);
1504 flog_warn(EC_OSPF_TE_UNEXPECTED
,
1505 "MPLS-TE (%s): ospf_mpls_te_lsa_new() ?", __func__
);
1508 new->data
->ls_seqnum
= lsa_seqnum_increment(lsa
);
1510 /* Install this LSA into LSDB. */
1511 /* Given "lsa" will be freed in the next function. */
1512 /* As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use
1513 * ospf_lookup() to get ospf instance */
1517 if (ospf_lsa_install(top
, NULL
/*oi */, new) == NULL
) {
1518 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1519 "MPLS-TE (%s): ospf_lsa_install() ?", __func__
);
1520 ospf_lsa_unlock(&new);
1524 /* Flood updated LSA through AS or Area depending of the RFC of the link
1526 if (IS_FLOOD_AS(lp
->flags
))
1527 ospf_flood_through_as(top
, NULL
, new);
1529 ospf_flood_through_area(area
, NULL
/*nbr*/, new);
1531 /* Debug logging. */
1532 ote_debug("MPLS-TE (%s): LSA[Type%d:%pI4]: Refresh Opaque-LSA/MPLS-TE",
1533 __func__
, new->data
->type
, &new->data
->id
);
1534 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
1535 ospf_lsa_header_dump(new->data
);
1540 void ospf_mpls_te_lsa_schedule(struct mpls_te_link
*lp
, enum lsa_opcode opcode
)
1542 struct ospf_lsa lsa
;
1543 struct lsa_header lsah
;
1547 memset(&lsa
, 0, sizeof(lsa
));
1548 memset(&lsah
, 0, sizeof(lsah
));
1549 top
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1551 /* Check if the pseudo link is ready to flood */
1552 if (!CHECK_FLAG(lp
->flags
, LPFLG_LSA_ACTIVE
))
1555 ote_debug("MPLS-TE (%s): Schedule %s%s%s LSA for interface %s",
1557 opcode
== REORIGINATE_THIS_LSA
? "Re-Originate" : "",
1558 opcode
== REFRESH_THIS_LSA
? "Refresh" : "",
1559 opcode
== FLUSH_THIS_LSA
? "Flush" : "",
1560 lp
->ifp
? lp
->ifp
->name
: "-");
1562 lsa
.area
= lp
->area
;
1564 if (IS_FLOOD_AS(lp
->flags
)) {
1565 lsah
.type
= OSPF_OPAQUE_AS_LSA
;
1566 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA
, lp
->instance
);
1567 lsah
.id
.s_addr
= htonl(tmp
);
1569 lsah
.type
= OSPF_OPAQUE_AREA_LSA
;
1570 if (IS_INTER_AS(lp
->type
)) {
1571 /* Set the area context if not know */
1572 if (lp
->area
== NULL
)
1573 lp
->area
= ospf_area_lookup_by_area_id(
1574 top
, OspfMplsTE
.interas_areaid
);
1575 /* Unable to set the area context. Abort! */
1576 if (lp
->area
== NULL
) {
1578 EC_OSPF_TE_UNEXPECTED
,
1579 "MPLS-TE (%s): Area context is null. Abort !",
1583 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA
,
1586 tmp
= SET_OPAQUE_LSID(
1587 OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
,
1589 lsah
.id
.s_addr
= htonl(tmp
);
1593 case REORIGINATE_THIS_LSA
:
1594 if (IS_FLOOD_AS(lp
->flags
)) {
1595 ospf_opaque_lsa_reoriginate_schedule(
1596 (void *)top
, OSPF_OPAQUE_AS_LSA
,
1597 OPAQUE_TYPE_INTER_AS_LSA
);
1599 if (IS_INTER_AS(lp
->type
))
1600 ospf_opaque_lsa_reoriginate_schedule(
1601 (void *)lp
->area
, OSPF_OPAQUE_AREA_LSA
,
1602 OPAQUE_TYPE_INTER_AS_LSA
);
1604 ospf_opaque_lsa_reoriginate_schedule(
1605 (void *)lp
->area
, OSPF_OPAQUE_AREA_LSA
,
1606 OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
);
1609 case REFRESH_THIS_LSA
:
1610 ospf_opaque_lsa_refresh_schedule(&lsa
);
1612 case FLUSH_THIS_LSA
:
1613 /* Reset Activity flag */
1614 lp
->flags
= LPFLG_LSA_INACTIVE
;
1615 ospf_opaque_lsa_flush_schedule(&lsa
);
1618 flog_warn(EC_OSPF_TE_UNEXPECTED
,
1619 "MPLS-TE (%s): Unknown opcode (%u)", __func__
,
1626 * ------------------------------------------------------
1627 * Followings are Link State Data Base control functions.
1628 * ------------------------------------------------------
1632 * Get Vertex from TED by the router which advertised the LSA. A new Vertex and
1633 * associated Link State Node are created if Vertex is not found.
1635 * @param ted Link State Traffic Engineering Database
1636 * @param lsa OSPF Link State Advertisement
1638 * @return Link State Vertex
1640 static struct ls_vertex
*get_vertex(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
1642 struct ls_node_id lnid
;
1643 struct ls_node
*lnode
;
1644 struct ls_vertex
*vertex
;
1647 if (!ted
|| !lsa
|| !lsa
->data
|| !lsa
->area
)
1650 /* Search if a Link State Vertex already exist */
1651 lnid
.origin
= OSPFv2
;
1652 lnid
.id
.ip
.addr
= lsa
->data
->adv_router
;
1653 lnid
.id
.ip
.area_id
= lsa
->area
->area_id
;
1654 vertex
= ls_find_vertex_by_id(ted
, lnid
);
1656 /* Create Node & Vertex in the Link State Date Base if not found */
1658 const struct in_addr inaddr_any
= {.s_addr
= INADDR_ANY
};
1660 lnode
= ls_node_new(lnid
, inaddr_any
, in6addr_any
);
1661 snprintfrr(lnode
->name
, MAX_NAME_LENGTH
, "%pI4",
1663 vertex
= ls_vertex_add(ted
, lnode
);
1666 if (IS_LSA_SELF(lsa
))
1673 * Get Edge from TED by Link State Attribute ID. A new Edge and associated Link
1674 * State Attributes are created if not found.
1676 * @param ted Link State Traffic Engineering Database
1677 * @param adv Link State Node ID of router which advertised Edge
1678 * @param link_id Link State Attribute ID
1680 * @return Link State Edge
1682 static struct ls_edge
*get_edge(struct ls_ted
*ted
, struct ls_node_id adv
,
1683 struct in_addr link_id
)
1686 struct ls_edge
*edge
;
1687 struct ls_attributes
*attr
;
1689 /* Search Edge that corresponds to the Link ID */
1690 key
= ((uint64_t)ntohl(link_id
.s_addr
)) & 0xffffffff;
1691 edge
= ls_find_edge_by_key(ted
, key
);
1693 /* Create new one if not exist */
1695 attr
= ls_attributes_new(adv
, link_id
, in6addr_any
, 0);
1696 edge
= ls_edge_add(ted
, attr
);
1703 * Export Link State information to consumer daemon through ZAPI Link State
1706 * @param type Type of Link State Element i.e. Vertex, Edge or Subnet
1707 * @param link_state Pointer to Link State Vertex, Edge or Subnet
1709 * @return 0 if success, -1 otherwise
1711 static int ospf_te_export(uint8_t type
, void *link_state
)
1713 struct ls_message msg
= {};
1716 if (!OspfMplsTE
.export
)
1720 case LS_MSG_TYPE_NODE
:
1721 ls_vertex2msg(&msg
, (struct ls_vertex
*)link_state
);
1722 rc
= ls_send_msg(zclient
, &msg
, NULL
);
1724 case LS_MSG_TYPE_ATTRIBUTES
:
1725 ls_edge2msg(&msg
, (struct ls_edge
*)link_state
);
1726 rc
= ls_send_msg(zclient
, &msg
, NULL
);
1728 case LS_MSG_TYPE_PREFIX
:
1729 ls_subnet2msg(&msg
, (struct ls_subnet
*)link_state
);
1730 rc
= ls_send_msg(zclient
, &msg
, NULL
);
1741 * Update Link State Edge & Attributes from the given Link State Attributes ID
1742 * and metric. This function is called when parsing Router LSA.
1744 * @param ted Link State Traffic Engineering Database
1745 * @param vertex Vertex where the Edge is attached as source
1746 * @param link_data Link State Edge ID
1747 * @param metric Standard metric attached to this Edge
1749 static void ospf_te_update_link(struct ls_ted
*ted
, struct ls_vertex
*vertex
,
1750 struct in_addr link_data
, uint8_t metric
)
1752 struct ls_edge
*edge
;
1753 struct ls_attributes
*attr
;
1756 if (!ted
|| !vertex
|| !vertex
->node
)
1759 /* Get Corresponding Edge from Link State Data Base */
1760 edge
= get_edge(ted
, vertex
->node
->adv
, link_data
);
1761 attr
= edge
->attributes
;
1763 /* re-attached edge to vertex if needed */
1765 edge
->source
= vertex
;
1767 /* Check if it is just an LSA refresh */
1768 if ((CHECK_FLAG(attr
->flags
, LS_ATTR_METRIC
)
1769 && (attr
->metric
== metric
))) {
1770 edge
->status
= SYNC
;
1774 /* Update metric value */
1775 attr
->metric
= metric
;
1776 SET_FLAG(attr
->flags
, LS_ATTR_METRIC
);
1777 if (edge
->status
!= NEW
)
1778 edge
->status
= UPDATE
;
1780 ote_debug(" |- %s Edge %pI4 with metric %d",
1781 edge
->status
== NEW
? "Add" : "Update", &attr
->standard
.local
,
1784 /* Export Link State Edge */
1785 ospf_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1786 edge
->status
= SYNC
;
1790 * Update Link State Subnet & Prefix from the given prefix and metric. This
1791 * function is called when parsing Router LSA.
1793 * @param ted Link State Traffic Engineering Database
1794 * @param vertex Vertex where the Edge is attached as source
1795 * @param p Prefix associated to the Subnet
1796 * @param metric Standard metric attached to this Edge
1798 static void ospf_te_update_subnet(struct ls_ted
*ted
, struct ls_vertex
*vertex
,
1799 struct prefix p
, uint8_t metric
)
1801 struct ls_subnet
*subnet
;
1802 struct ls_prefix
*ls_pref
;
1804 /* Search if there is a Subnet for this prefix */
1805 subnet
= ls_find_subnet(ted
, p
);
1807 /* If found a Subnet, check if it is attached to this Vertex */
1809 /* Re-attach the subnet to the vertex if necessary */
1810 if (subnet
->vertex
!= vertex
) {
1811 subnet
->vertex
= vertex
;
1812 listnode_add_sort_nodup(vertex
->prefixes
, subnet
);
1814 /* Check if it is a simple refresh */
1815 ls_pref
= subnet
->ls_pref
;
1816 if ((CHECK_FLAG(ls_pref
->flags
, LS_PREF_METRIC
))
1817 && (ls_pref
->metric
== metric
)) {
1818 subnet
->status
= SYNC
;
1821 ls_pref
->metric
= metric
;
1822 SET_FLAG(ls_pref
->flags
, LS_PREF_METRIC
);
1823 subnet
->status
= UPDATE
;
1825 /* Create new Link State Prefix */
1826 ls_pref
= ls_prefix_new(vertex
->node
->adv
, p
);
1827 ls_pref
->metric
= metric
;
1828 SET_FLAG(ls_pref
->flags
, LS_PREF_METRIC
);
1829 /* and add it to the TED */
1830 subnet
= ls_subnet_add(ted
, ls_pref
);
1833 ote_debug(" |- %s subnet %pFX with metric %d",
1834 subnet
->status
== NEW
? "Add" : "Update", &subnet
->key
,
1837 /* Export Link State Subnet */
1838 ospf_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1839 subnet
->status
= SYNC
;
1843 * Delete Subnet that correspond to the given IPv4 address and export deletion
1844 * information before removal. Prefix length is fixed to IPV4_MAX_BITLEN.
1846 * @param ted Links State Database
1847 * @param addr IPv4 address
1849 static void ospf_te_delete_subnet(struct ls_ted
*ted
, struct in_addr addr
)
1852 struct ls_subnet
*subnet
;
1854 /* Search subnet that correspond to the address/32 as prefix */
1856 p
.prefixlen
= IPV4_MAX_BITLEN
;
1858 subnet
= ls_find_subnet(ted
, p
);
1860 /* Remove subnet if found */
1862 subnet
->status
= DELETE
;
1863 ospf_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1864 ls_subnet_del_all(ted
, subnet
);
1869 * Parse Router LSA. This function will create or update corresponding Vertex,
1870 * Edge and Subnet. It also remove Edge and Subnet if they are marked as Orphan
1871 * once Router LSA is parsed.
1873 * @param ted Link State Traffic Engineering Database
1874 * @param lsa OSPF Link State Advertisement
1876 * @return 0 if success, -1 otherwise
1878 static int ospf_te_parse_router_lsa(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
1880 struct router_lsa
*rl
;
1881 enum ls_node_type type
;
1882 struct ls_vertex
*vertex
;
1883 struct ls_edge
*edge
;
1884 struct ls_subnet
*subnet
;
1885 struct listnode
*node
;
1889 if (!ted
|| !lsa
|| !lsa
->data
)
1892 ote_debug("MPLS-TE (%s): Parse Router LSA[%pI4] from Router[%pI4]",
1893 __func__
, &lsa
->data
->id
, &lsa
->data
->adv_router
);
1895 /* Get vertex from LSA Advertise Router ID */
1896 vertex
= get_vertex(ted
, lsa
);
1898 /* Set Node type information if it has changed */
1899 rl
= (struct router_lsa
*)lsa
->data
;
1900 if (IS_ROUTER_LSA_VIRTUAL(rl
))
1902 else if (IS_ROUTER_LSA_EXTERNAL(rl
))
1904 else if (IS_ROUTER_LSA_BORDER(rl
))
1909 if (vertex
->status
== NEW
) {
1910 vertex
->node
->type
= type
;
1911 SET_FLAG(vertex
->node
->flags
, LS_NODE_TYPE
);
1912 } else if (vertex
->node
->type
!= type
) {
1913 vertex
->node
->type
= type
;
1914 vertex
->status
= UPDATE
;
1917 /* Check if Vertex has been modified */
1918 if (vertex
->status
!= SYNC
) {
1919 ote_debug(" |- %s Vertex %pI4",
1920 vertex
->status
== NEW
? "Add" : "Update",
1921 &vertex
->node
->router_id
);
1923 /* Vertex is out of sync: export it */
1924 ospf_te_export(LS_MSG_TYPE_NODE
, vertex
);
1925 vertex
->status
= SYNC
;
1928 /* Mark outgoing Edge and Subnet as ORPHAN to detect deletion */
1929 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
))
1930 edge
->status
= ORPHAN
;
1932 for (ALL_LIST_ELEMENTS_RO(vertex
->prefixes
, node
, subnet
))
1933 subnet
->status
= ORPHAN
;
1935 /* Then, process Link Information */
1936 len
= lsa
->size
- OSPF_LSA_HEADER_SIZE
- OSPF_ROUTER_LSA_MIN_SIZE
;
1937 links
= ntohs(rl
->links
);
1938 for (int i
= 0; i
< links
&& len
> 0; len
-= 12, i
++) {
1942 switch (rl
->link
[i
].type
) {
1943 case LSA_LINK_TYPE_POINTOPOINT
:
1944 ospf_te_update_link(ted
, vertex
, rl
->link
[i
].link_data
,
1945 ntohs(rl
->link
[i
].metric
));
1946 /* Add corresponding subnet */
1948 p
.prefixlen
= IPV4_MAX_BITLEN
;
1949 p
.u
.prefix4
= rl
->link
[i
].link_data
;
1950 metric
= ntohs(rl
->link
[i
].metric
);
1951 ospf_te_update_subnet(ted
, vertex
, p
, metric
);
1953 case LSA_LINK_TYPE_STUB
:
1954 /* Keep only /32 prefix */
1955 p
.prefixlen
= ip_masklen(rl
->link
[i
].link_data
);
1956 if (p
.prefixlen
== IPV4_MAX_BITLEN
) {
1958 p
.u
.prefix4
= rl
->link
[i
].link_id
;
1959 metric
= ntohs(rl
->link
[i
].metric
);
1960 ospf_te_update_subnet(ted
, vertex
, p
, metric
);
1967 /* Clean remaining Orphan Edges or Subnets */
1968 if (OspfMplsTE
.export
)
1969 ls_vertex_clean(ted
, vertex
, zclient
);
1971 ls_vertex_clean(ted
, vertex
, NULL
);
1977 * Delete Vertex, Edge and Subnet associated to this Router LSA. This function
1978 * is called when the router received such LSA with MAX_AGE (Flush) or when the
1981 * @param ted Link State Traffic Engineering Database
1982 * @param lsa OSPF Link State Advertisement
1984 * @return 0 if success, -1 otherwise
1986 static int ospf_te_delete_router_lsa(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
1988 struct ls_node_id lnid
;
1989 struct ls_vertex
*vertex
;
1992 if (!ted
|| !lsa
|| !lsa
->data
)
1995 /* Search Vertex that corresponds to this LSA */
1996 lnid
.origin
= OSPFv2
;
1997 lnid
.id
.ip
.addr
= lsa
->data
->adv_router
;
1998 lnid
.id
.ip
.area_id
= lsa
->area
->area_id
;
1999 vertex
= ls_find_vertex_by_id(ted
, lnid
);
2003 ote_debug("MPLS-TE (%s): Delete Vertex %pI4 from Router LSA[%pI4]",
2004 __func__
, &vertex
->node
->router_id
, &lsa
->data
->id
);
2006 /* Export deleted vertex ... */
2007 vertex
->status
= DELETE
;
2008 ospf_te_export(LS_MSG_TYPE_NODE
, vertex
);
2010 /* ... and remove Node & Vertex from Link State Date Base */
2011 ls_vertex_del_all(ted
, vertex
);
2017 * Create or update Remote Vertex that corresponds to the remote ASBR of the
2018 * foreign network if Edge is associated to an Inter-AS LSA (Type 6).
2020 * @param ted Link State Traffic Engineering Database
2021 * @param edge Link State Edge
2023 static void ospf_te_update_remote_asbr(struct ls_ted
*ted
, struct ls_edge
*edge
)
2025 struct ls_node_id lnid
;
2026 struct ls_vertex
*vertex
;
2027 struct ls_node
*lnode
;
2028 struct ls_attributes
*attr
;
2035 /* Search if a Link State Vertex already exist */
2036 attr
= edge
->attributes
;
2037 lnid
.origin
= OSPFv2
;
2038 lnid
.id
.ip
.addr
= attr
->standard
.remote_addr
;
2039 lnid
.id
.ip
.area_id
= attr
->adv
.id
.ip
.area_id
;
2040 vertex
= ls_find_vertex_by_id(ted
, lnid
);
2042 /* Create Node & Vertex in the Link State Date Base if not found */
2044 const struct in_addr inaddr_any
= {.s_addr
= INADDR_ANY
};
2046 lnode
= ls_node_new(lnid
, inaddr_any
, in6addr_any
);
2047 snprintfrr(lnode
->name
, MAX_NAME_LENGTH
, "%pI4",
2049 vertex
= ls_vertex_add(ted
, lnode
);
2052 /* Update Node information */
2053 lnode
= vertex
->node
;
2054 if (CHECK_FLAG(lnode
->flags
, LS_NODE_TYPE
)) {
2055 if (lnode
->type
!= RMT_ASBR
) {
2056 lnode
->type
= RMT_ASBR
;
2057 if (vertex
->status
!= NEW
)
2058 vertex
->status
= UPDATE
;
2061 lnode
->type
= RMT_ASBR
;
2062 SET_FLAG(lnode
->flags
, LS_NODE_TYPE
);
2063 if (vertex
->status
!= NEW
)
2064 vertex
->status
= UPDATE
;
2066 if (CHECK_FLAG(lnode
->flags
, LS_NODE_AS_NUMBER
)) {
2067 if (lnode
->as_number
!= attr
->standard
.remote_as
) {
2068 lnode
->as_number
= attr
->standard
.remote_as
;
2069 if (vertex
->status
!= NEW
)
2070 vertex
->status
= UPDATE
;
2073 lnode
->as_number
= attr
->standard
.remote_as
;
2074 SET_FLAG(lnode
->flags
, LS_NODE_AS_NUMBER
);
2075 if (vertex
->status
!= NEW
)
2076 vertex
->status
= UPDATE
;
2079 /* Export Link State Vertex if needed */
2080 if (vertex
->status
== NEW
|| vertex
->status
== UPDATE
) {
2081 ote_debug(" |- %s Remote Vertex %pI4 for AS %u",
2082 vertex
->status
== NEW
? "Add" : "Update",
2083 &lnode
->router_id
, lnode
->as_number
);
2084 ospf_te_export(LS_MSG_TYPE_NODE
, vertex
);
2085 vertex
->status
= SYNC
;
2088 /* Update corresponding Subnets */
2090 p
.prefixlen
= IPV4_MAX_BITLEN
;
2091 p
.u
.prefix4
= attr
->standard
.local
;
2092 ospf_te_update_subnet(ted
, edge
->source
, p
, attr
->standard
.te_metric
);
2095 p
.prefixlen
= IPV4_MAX_BITLEN
;
2096 p
.u
.prefix4
= attr
->standard
.remote_addr
;
2097 ospf_te_update_subnet(ted
, vertex
, p
, attr
->standard
.te_metric
);
2099 /* Connect Edge to the remote Vertex */
2100 if (edge
->destination
== NULL
) {
2101 edge
->destination
= vertex
;
2102 listnode_add_sort_nodup(vertex
->incoming_edges
, edge
);
2105 /* Finally set type to ASBR the node that advertised this Edge ... */
2106 vertex
= edge
->source
;
2107 lnode
= vertex
->node
;
2108 if (CHECK_FLAG(lnode
->flags
, LS_NODE_TYPE
)) {
2109 if (lnode
->type
!= ASBR
) {
2111 if (vertex
->status
!= NEW
)
2112 vertex
->status
= UPDATE
;
2116 SET_FLAG(lnode
->flags
, LS_NODE_TYPE
);
2117 if (vertex
->status
!= NEW
)
2118 vertex
->status
= UPDATE
;
2121 /* ... and Export it if needed */
2122 if (vertex
->status
== NEW
|| vertex
->status
== UPDATE
) {
2123 ospf_te_export(LS_MSG_TYPE_NODE
, vertex
);
2124 vertex
->status
= SYNC
;
2129 * Parse Opaque Traffic Engineering LSA (Type 1) TLVs and create or update the
2130 * corresponding Link State Edge and Attributes. Vertex connections are also
2131 * updated if needed based on the remote IP address of the Edge and existing
2134 * @param ted Link State Traffic Engineering Database
2135 * @param lsa OSPF Link State Advertisement
2137 * @return 0 if success, -1 otherwise
2139 static int ospf_te_parse_te(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2141 struct ls_edge
*edge
;
2142 struct ls_vertex
*vertex
;
2143 struct ls_attributes
*old
, attr
= {};
2144 struct tlv_header
*tlvh
;
2149 /* Initialize Attribute */
2150 attr
.adv
.origin
= OSPFv2
;
2151 attr
.adv
.id
.ip
.addr
= lsa
->data
->adv_router
;
2152 if (lsa
->data
->type
!= OSPF_OPAQUE_AS_LSA
)
2153 attr
.adv
.id
.ip
.area_id
= lsa
->area
->area_id
;
2155 /* Initialize TLV browsing */
2156 tlvh
= TLV_HDR_TOP(lsa
->data
);
2157 len
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
2159 /* Check if TE Router-ID TLV is present */
2160 if (ntohs(tlvh
->type
) == TE_TLV_ROUTER_ADDR
) {
2161 /* if TE Router-ID is alone, we are done ... */
2162 if (len
== TE_LINK_SUBTLV_DEF_SIZE
)
2165 /* ... otherwise, skip it */
2166 len
-= TE_LINK_SUBTLV_DEF_SIZE
+ TLV_HDR_SIZE
;
2167 tlvh
= TLV_HDR_NEXT(tlvh
);
2170 /* Check if we have a valid TE Link TLV */
2171 if ((len
== 0) || (ntohs(tlvh
->type
) != TE_TLV_LINK
))
2174 sum
= sizeof(struct tlv_header
);
2175 /* Browse sub-TLV and fulfill Link State Attributes */
2176 for (tlvh
= TLV_DATA(tlvh
); sum
< len
; tlvh
= TLV_HDR_NEXT(tlvh
)) {
2177 uint32_t val32
, tab32
[2];
2178 float valf
, tabf
[8];
2179 struct in_addr addr
;
2181 value
= TLV_DATA(tlvh
);
2182 switch (ntohs(tlvh
->type
)) {
2183 case TE_LINK_SUBTLV_LCLIF_IPADDR
:
2184 memcpy(&addr
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2185 attr
.standard
.local
= addr
;
2186 SET_FLAG(attr
.flags
, LS_ATTR_LOCAL_ADDR
);
2188 case TE_LINK_SUBTLV_RMTIF_IPADDR
:
2189 memcpy(&addr
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2190 attr
.standard
.remote
= addr
;
2191 SET_FLAG(attr
.flags
, LS_ATTR_NEIGH_ADDR
);
2193 case TE_LINK_SUBTLV_TE_METRIC
:
2194 memcpy(&val32
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2195 attr
.standard
.te_metric
= ntohl(val32
);
2196 SET_FLAG(attr
.flags
, LS_ATTR_TE_METRIC
);
2198 case TE_LINK_SUBTLV_MAX_BW
:
2199 memcpy(&valf
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2200 attr
.standard
.max_bw
= ntohf(valf
);
2201 SET_FLAG(attr
.flags
, LS_ATTR_MAX_BW
);
2203 case TE_LINK_SUBTLV_MAX_RSV_BW
:
2204 memcpy(&valf
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2205 attr
.standard
.max_rsv_bw
= ntohf(valf
);
2206 SET_FLAG(attr
.flags
, LS_ATTR_MAX_RSV_BW
);
2208 case TE_LINK_SUBTLV_UNRSV_BW
:
2209 memcpy(tabf
, value
, TE_LINK_SUBTLV_UNRSV_SIZE
);
2210 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
2211 attr
.standard
.unrsv_bw
[i
] = ntohf(tabf
[i
]);
2212 SET_FLAG(attr
.flags
, LS_ATTR_UNRSV_BW
);
2214 case TE_LINK_SUBTLV_RSC_CLSCLR
:
2215 memcpy(&val32
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2216 attr
.standard
.admin_group
= ntohl(val32
);
2217 SET_FLAG(attr
.flags
, LS_ATTR_ADM_GRP
);
2219 case TE_LINK_SUBTLV_LLRI
:
2220 memcpy(tab32
, value
, TE_LINK_SUBTLV_LLRI_SIZE
);
2221 attr
.standard
.local_id
= ntohl(tab32
[0]);
2222 attr
.standard
.remote_id
= ntohl(tab32
[1]);
2223 SET_FLAG(attr
.flags
, LS_ATTR_LOCAL_ID
);
2224 SET_FLAG(attr
.flags
, LS_ATTR_NEIGH_ID
);
2226 case TE_LINK_SUBTLV_RIP
:
2227 memcpy(&addr
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2228 attr
.standard
.remote_addr
= addr
;
2229 SET_FLAG(attr
.flags
, LS_ATTR_REMOTE_ADDR
);
2231 case TE_LINK_SUBTLV_RAS
:
2232 memcpy(&val32
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2233 attr
.standard
.remote_as
= ntohl(val32
);
2234 SET_FLAG(attr
.flags
, LS_ATTR_REMOTE_AS
);
2236 case TE_LINK_SUBTLV_AV_DELAY
:
2237 memcpy(&val32
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2238 attr
.extended
.delay
= ntohl(val32
);
2239 SET_FLAG(attr
.flags
, LS_ATTR_DELAY
);
2241 case TE_LINK_SUBTLV_MM_DELAY
:
2242 memcpy(tab32
, value
, TE_LINK_SUBTLV_MM_DELAY_SIZE
);
2243 attr
.extended
.min_delay
= ntohl(tab32
[0]);
2244 attr
.extended
.max_delay
= ntohl(tab32
[1]);
2245 SET_FLAG(attr
.flags
, LS_ATTR_MIN_MAX_DELAY
);
2247 case TE_LINK_SUBTLV_DELAY_VAR
:
2248 memcpy(&val32
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2249 attr
.extended
.jitter
= ntohl(val32
);
2250 SET_FLAG(attr
.flags
, LS_ATTR_JITTER
);
2252 case TE_LINK_SUBTLV_PKT_LOSS
:
2253 memcpy(&val32
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2254 attr
.extended
.pkt_loss
= ntohl(val32
);
2255 SET_FLAG(attr
.flags
, LS_ATTR_PACKET_LOSS
);
2257 case TE_LINK_SUBTLV_RES_BW
:
2258 memcpy(&valf
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2259 attr
.extended
.rsv_bw
= ntohf(valf
);
2260 SET_FLAG(attr
.flags
, LS_ATTR_RSV_BW
);
2262 case TE_LINK_SUBTLV_AVA_BW
:
2263 memcpy(&valf
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2264 attr
.extended
.ava_bw
= ntohf(valf
);
2265 SET_FLAG(attr
.flags
, LS_ATTR_AVA_BW
);
2267 case TE_LINK_SUBTLV_USE_BW
:
2268 memcpy(&valf
, value
, TE_LINK_SUBTLV_DEF_SIZE
);
2269 attr
.extended
.used_bw
= ntohf(valf
);
2270 SET_FLAG(attr
.flags
, LS_ATTR_USE_BW
);
2275 sum
+= TLV_SIZE(tlvh
);
2278 /* Get corresponding Edge from Link State Data Base */
2279 edge
= get_edge(ted
, attr
.adv
, attr
.standard
.local
);
2280 old
= edge
->attributes
;
2282 ote_debug(" |- Process Traffic Engineering LSA %pI4 for Edge %pI4",
2283 &lsa
->data
->id
, &attr
.standard
.local
);
2285 /* Update standard fields */
2286 len
= sizeof(struct ls_standard
);
2287 if ((attr
.flags
& 0x0FFFF) == (old
->flags
& 0x0FFFF)) {
2288 if (memcmp(&attr
.standard
, &old
->standard
, len
) != 0) {
2289 memcpy(&old
->standard
, &attr
.standard
, len
);
2290 if (edge
->status
!= NEW
)
2291 edge
->status
= UPDATE
;
2294 memcpy(&old
->standard
, &attr
.standard
, len
);
2295 old
->flags
|= attr
.flags
& 0x0FFFF;
2296 if (edge
->status
!= NEW
)
2297 edge
->status
= UPDATE
;
2299 /* Update extended fields */
2300 len
= sizeof(struct ls_extended
);
2301 if ((attr
.flags
& 0x0FF0000) == (old
->flags
& 0x0FF0000)) {
2302 if (memcmp(&attr
.extended
, &old
->extended
, len
) != 0) {
2303 memcpy(&old
->extended
, &attr
.extended
, len
);
2304 if (edge
->status
!= NEW
)
2305 edge
->status
= UPDATE
;
2308 memcpy(&old
->extended
, &attr
.extended
, len
);
2309 old
->flags
|= attr
.flags
& 0x0FF0000;
2310 if (edge
->status
!= NEW
)
2311 edge
->status
= UPDATE
;
2314 /* If LSA is an Opaque Inter-AS, Add Node and Subnet */
2315 lsa_id
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
2316 if (lsa_id
== OPAQUE_TYPE_INTER_AS_LSA
)
2317 ospf_te_update_remote_asbr(ted
, edge
);
2319 /* Update remote Link if remote IP addr is known */
2320 if (CHECK_FLAG(old
->flags
, LS_ATTR_NEIGH_ADDR
)) {
2321 struct ls_edge
*dst
;
2323 dst
= ls_find_edge_by_destination(ted
, old
);
2324 /* Attach remote link if not set */
2325 if (dst
&& edge
->source
&& dst
->destination
== NULL
) {
2326 vertex
= edge
->source
;
2327 if (vertex
->incoming_edges
)
2328 listnode_add_sort_nodup(vertex
->incoming_edges
,
2330 dst
->destination
= vertex
;
2332 /* and destination vertex to this edge */
2333 if (dst
&& dst
->source
&& edge
->destination
== NULL
) {
2334 vertex
= dst
->source
;
2335 if (vertex
->incoming_edges
)
2336 listnode_add_sort_nodup(vertex
->incoming_edges
,
2338 edge
->destination
= vertex
;
2342 /* Export Link State Edge if needed */
2343 if (edge
->status
== NEW
|| edge
->status
== UPDATE
) {
2344 ote_debug(" |- %s TE info. for Edge %pI4",
2345 edge
->status
== NEW
? "Add" : "Update",
2346 &edge
->attributes
->standard
.local
);
2348 ospf_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
2349 edge
->status
= SYNC
;
2356 * Delete Link State Attributes information that correspond to the Opaque
2357 * Traffic Engineering LSA (Type 1) TLVs. Note that the Edge is not removed.
2359 * @param ted Link State Traffic Engineering Database
2360 * @param lsa OSPF Link State Advertisement
2362 * @return 0 if success, -1 otherwise
2364 static int ospf_te_delete_te(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2366 struct ls_edge
*edge
;
2367 struct ls_attributes
*attr
;
2368 struct tlv_header
*tlvh
;
2369 struct in_addr addr
;
2374 /* Initialize TLV browsing */
2375 tlvh
= TLV_HDR_TOP(lsa
->data
);
2376 /* Skip Router TE ID if present */
2377 if (ntohs(tlvh
->type
) == TE_TLV_ROUTER_ADDR
)
2378 tlvh
= TLV_HDR_NEXT(tlvh
);
2379 len
= TLV_BODY_SIZE(tlvh
);
2380 sum
= sizeof(struct tlv_header
);
2382 /* Browse sub-TLV to find Link ID */
2383 for (tlvh
= TLV_DATA(tlvh
); sum
< len
; tlvh
= TLV_HDR_NEXT(tlvh
)) {
2384 if (ntohs(tlvh
->type
) == TE_LINK_SUBTLV_LCLIF_IPADDR
) {
2385 memcpy(&addr
, TLV_DATA(tlvh
), TE_LINK_SUBTLV_DEF_SIZE
);
2386 key
= ((uint64_t)ntohl(addr
.s_addr
)) & 0xffffffff;
2389 sum
+= TLV_SIZE(tlvh
);
2394 /* Search Edge that corresponds to the Link ID */
2395 edge
= ls_find_edge_by_key(ted
, key
);
2396 if (!edge
|| !edge
->attributes
)
2398 attr
= edge
->attributes
;
2400 /* First, remove Remote ASBR and associated Edge & Subnet if any */
2401 lsa_id
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
2402 if (lsa_id
== OPAQUE_TYPE_INTER_AS_LSA
) {
2403 ote_debug(" |- Delete remote ASBR, Edge and Subnet");
2405 if (edge
->destination
) {
2406 edge
->destination
->status
= DELETE
;
2407 ospf_te_export(LS_MSG_TYPE_NODE
, edge
->destination
);
2408 ls_vertex_del_all(ted
, edge
->destination
);
2411 ospf_te_delete_subnet(ted
, attr
->standard
.local
);
2413 edge
->status
= DELETE
;
2414 ospf_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
2415 ls_edge_del_all(ted
, edge
);
2420 ote_debug(" |- Delete TE info. for Edge %pI4",
2421 &edge
->attributes
->standard
.local
);
2423 /* Remove Link State Attributes TE information */
2424 memset(&attr
->standard
, 0, sizeof(struct ls_standard
));
2425 attr
->flags
&= 0x0FFFF;
2426 memset(&attr
->extended
, 0, sizeof(struct ls_extended
));
2427 attr
->flags
&= 0x0FF0000;
2428 ls_attributes_srlg_del(attr
);
2430 /* Export Edge that has been updated */
2431 if (CHECK_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
)
2432 || CHECK_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
)) {
2433 edge
->status
= UPDATE
;
2434 ospf_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
2435 edge
->status
= SYNC
;
2437 /* Remove completely the Edge if Segment Routing is not set */
2438 ospf_te_delete_subnet(ted
, attr
->standard
.local
);
2439 edge
->status
= DELETE
;
2440 ospf_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
2441 ls_edge_del_all(ted
, edge
);
2448 * Parse Opaque Router Information LSA (Type 4) TLVs and update the
2449 * corresponding Link State Vertex with these information (Segment Routing).
2451 * @param ted Link State Traffic Engineering Database
2452 * @param lsa OSPF Link State Advertisement
2454 * @return 0 if success, -1 otherwise
2456 static int ospf_te_parse_ri(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2458 struct ls_vertex
*vertex
;
2459 struct ls_node
*node
;
2460 struct lsa_header
*lsah
= lsa
->data
;
2461 struct tlv_header
*tlvh
;
2462 uint16_t len
= 0, sum
= 0;
2464 /* Get vertex / Node from LSA Advertised Router ID */
2465 vertex
= get_vertex(ted
, lsa
);
2466 node
= vertex
->node
;
2468 ote_debug(" |- Process Router Information LSA %pI4 for Vertex %pI4",
2469 &lsa
->data
->id
, &node
->router_id
);
2471 /* Initialize TLV browsing */
2472 len
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
2473 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< len
&& tlvh
;
2474 tlvh
= TLV_HDR_NEXT(tlvh
)) {
2475 struct ri_sr_tlv_sr_algorithm
*algo
;
2476 struct ri_sr_tlv_sid_label_range
*range
;
2477 struct ri_sr_tlv_node_msd
*msd
;
2478 uint32_t size
, lower
;
2480 switch (ntohs(tlvh
->type
)) {
2481 case RI_SR_TLV_SR_ALGORITHM
:
2482 algo
= (struct ri_sr_tlv_sr_algorithm
*)tlvh
;
2484 for (int i
= 0; i
< ntohs(algo
->header
.length
); i
++) {
2485 if (CHECK_FLAG(node
->flags
, LS_NODE_SR
)
2486 && (node
->algo
[i
] == algo
->value
[i
]))
2489 node
->algo
[i
] = algo
->value
[i
];
2490 SET_FLAG(node
->flags
, LS_NODE_SR
);
2491 if (vertex
->status
!= NEW
)
2492 vertex
->status
= UPDATE
;
2495 /* Reset other Algorithms */
2496 for (int i
= ntohs(algo
->header
.length
); i
< 2; i
++) {
2497 if (vertex
->status
!= NEW
2498 && node
->algo
[i
] != SR_ALGORITHM_UNSET
)
2499 vertex
->status
= UPDATE
;
2500 node
->algo
[i
] = SR_ALGORITHM_UNSET
;
2505 case RI_SR_TLV_SRGB_LABEL_RANGE
:
2506 range
= (struct ri_sr_tlv_sid_label_range
*)tlvh
;
2507 size
= GET_RANGE_SIZE(ntohl(range
->size
));
2508 lower
= GET_LABEL(ntohl(range
->lower
.value
));
2509 if ((CHECK_FLAG(node
->flags
, LS_NODE_SR
))
2510 && ((node
->srgb
.range_size
== size
)
2511 && (node
->srgb
.lower_bound
== lower
)))
2514 node
->srgb
.range_size
= size
;
2515 node
->srgb
.lower_bound
= lower
;
2516 SET_FLAG(node
->flags
, LS_NODE_SR
);
2517 if (vertex
->status
!= NEW
)
2518 vertex
->status
= UPDATE
;
2522 case RI_SR_TLV_SRLB_LABEL_RANGE
:
2523 range
= (struct ri_sr_tlv_sid_label_range
*)tlvh
;
2524 size
= GET_RANGE_SIZE(ntohl(range
->size
));
2525 lower
= GET_LABEL(ntohl(range
->lower
.value
));
2526 if ((CHECK_FLAG(node
->flags
, LS_NODE_SRLB
))
2527 && ((node
->srlb
.range_size
== size
)
2528 && (node
->srlb
.lower_bound
== lower
)))
2531 node
->srlb
.range_size
= size
;
2532 node
->srlb
.lower_bound
= lower
;
2533 SET_FLAG(node
->flags
, LS_NODE_SRLB
);
2534 if (vertex
->status
!= NEW
)
2535 vertex
->status
= UPDATE
;
2539 case RI_SR_TLV_NODE_MSD
:
2540 msd
= (struct ri_sr_tlv_node_msd
*)tlvh
;
2541 if ((CHECK_FLAG(node
->flags
, LS_NODE_MSD
))
2542 && (node
->msd
== msd
->value
))
2545 node
->msd
= msd
->value
;
2546 SET_FLAG(node
->flags
, LS_NODE_MSD
);
2547 if (vertex
->status
!= NEW
)
2548 vertex
->status
= UPDATE
;
2555 sum
+= TLV_SIZE(tlvh
);
2558 /* Vertex has been created or updated: export it */
2559 if (vertex
->status
== NEW
|| vertex
->status
== UPDATE
) {
2560 ote_debug(" |- %s SR info - SRGB[%d/%d] for Vertex %pI4",
2561 vertex
->status
== NEW
? "Add" : "Update",
2562 vertex
->node
->srgb
.lower_bound
,
2563 vertex
->node
->srgb
.range_size
,
2564 &vertex
->node
->router_id
);
2566 ospf_te_export(LS_MSG_TYPE_NODE
, vertex
);
2567 vertex
->status
= SYNC
;
2574 * Delete Link State Node information (Segment Routing) that correspond to the
2575 * Opaque Router Information LSA (Type 4) TLVs. Note that the Vertex is not
2578 * @param ted Link State Traffic Engineering Database
2579 * @param lsa OSPF Link State Advertisement
2581 * @return 0 if success, -1 otherwise
2583 static int ospf_te_delete_ri(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2585 struct ls_node_id lnid
;
2586 struct ls_vertex
*vertex
;
2587 struct ls_node
*node
;
2589 /* Search if a Link State Vertex already exist */
2590 lnid
.origin
= OSPFv2
;
2591 lnid
.id
.ip
.addr
= lsa
->data
->adv_router
;
2592 lnid
.id
.ip
.area_id
= lsa
->area
->area_id
;
2593 vertex
= ls_find_vertex_by_id(ted
, lnid
);
2597 /* Remove Segment Routing Information if any */
2598 node
= vertex
->node
;
2599 UNSET_FLAG(node
->flags
, LS_NODE_SR
);
2600 memset(&node
->srgb
, 0, sizeof(struct ls_srgb
));
2601 node
->algo
[0] = SR_ALGORITHM_UNSET
;
2602 node
->algo
[1] = SR_ALGORITHM_UNSET
;
2603 UNSET_FLAG(node
->flags
, LS_NODE_SRLB
);
2604 memset(&node
->srlb
, 0, sizeof(struct ls_srlb
));
2605 UNSET_FLAG(node
->flags
, LS_NODE_MSD
);
2607 vertex
->status
= UPDATE
;
2609 ote_debug(" |- Delete SR info. for Vertex %pI4",
2610 &vertex
->node
->router_id
);
2612 /* Vertex has been updated: export it */
2613 ospf_te_export(LS_MSG_TYPE_NODE
, vertex
);
2614 vertex
->status
= SYNC
;
2620 * Parse Opaque Extended Prefix LSA (Type 7) TLVs and update the corresponding
2621 * Link State Subnet with these information (Segment Routing ID).
2623 * @param ted Link State Traffic Engineering Database
2624 * @param lsa OSPF Link State Advertisement
2626 * @return 0 if success, -1 otherwise
2628 static int ospf_te_parse_ext_pref(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2630 struct ls_node_id lnid
;
2631 struct ls_subnet
*subnet
;
2632 struct ls_prefix
*ls_pref
;
2634 struct ext_tlv_prefix
*ext
;
2635 struct ext_subtlv_prefix_sid
*pref_sid
;
2638 /* Get corresponding Subnet from Link State Data Base */
2639 ext
= (struct ext_tlv_prefix
*)TLV_HDR_TOP(lsa
->data
);
2640 pref
.family
= AF_INET
;
2641 pref
.prefixlen
= ext
->pref_length
;
2642 pref
.u
.prefix4
= ext
->address
;
2643 subnet
= ls_find_subnet(ted
, pref
);
2645 /* Create new Link State Prefix if not found */
2647 lnid
.origin
= OSPFv2
;
2648 lnid
.id
.ip
.addr
= lsa
->data
->adv_router
;
2649 lnid
.id
.ip
.area_id
= lsa
->area
->area_id
;
2650 ls_pref
= ls_prefix_new(lnid
, pref
);
2651 /* and add it to the TED */
2652 subnet
= ls_subnet_add(ted
, ls_pref
);
2655 ote_debug(" |- Process Extended Prefix LSA %pI4 for subnet %pFX",
2656 &lsa
->data
->id
, &pref
);
2658 /* Initialize TLV browsing */
2659 ls_pref
= subnet
->ls_pref
;
2660 pref_sid
= (struct ext_subtlv_prefix_sid
*)((char *)(ext
) + TLV_HDR_SIZE
2661 + EXT_TLV_PREFIX_SIZE
);
2662 label
= CHECK_FLAG(pref_sid
->flags
, EXT_SUBTLV_PREFIX_SID_VFLG
)
2663 ? GET_LABEL(ntohl(pref_sid
->value
))
2664 : ntohl(pref_sid
->value
);
2666 /* Check if it is a simple refresh */
2667 if (CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)
2668 && ls_pref
->sr
.algo
== pref_sid
->algorithm
2669 && ls_pref
->sr
.sid_flag
== pref_sid
->flags
2670 && ls_pref
->sr
.sid
== label
)
2673 /* Fulfill SR information */
2674 ls_pref
->sr
.algo
= pref_sid
->algorithm
;
2675 ls_pref
->sr
.sid_flag
= pref_sid
->flags
;
2676 ls_pref
->sr
.sid
= label
;
2677 SET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
2678 if (subnet
->status
!= NEW
)
2679 subnet
->status
= UPDATE
;
2681 /* Export Subnet if needed */
2682 if (subnet
->status
== NEW
|| subnet
->status
== UPDATE
) {
2683 ote_debug(" |- %s SID %d to subnet %pFX",
2684 subnet
->status
== NEW
? "Add" : "Update",
2685 ls_pref
->sr
.sid
, &ls_pref
->pref
);
2687 ospf_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
2688 subnet
->status
= SYNC
;
2695 * Delete Link State Subnet information (Segment Routing ID) that correspond to
2696 * the Opaque Extended Prefix LSA (Type 7) TLVs. Note that the Subnet is not
2699 * @param ted Link State Traffic Engineering Database
2700 * @param lsa OSPF Link State Advertisement
2702 * @return 0 if success, -1 otherwise
2704 static int ospf_te_delete_ext_pref(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2706 struct ls_subnet
*subnet
;
2707 struct ls_prefix
*ls_pref
;
2709 struct ext_tlv_prefix
*ext
;
2711 /* Get corresponding Subnet from Link State Data Base */
2712 ext
= (struct ext_tlv_prefix
*)TLV_HDR_TOP(lsa
->data
);
2713 pref
.family
= AF_INET
;
2714 pref
.prefixlen
= ext
->pref_length
;
2715 pref
.u
.prefix4
= ext
->address
;
2716 subnet
= ls_find_subnet(ted
, pref
);
2718 /* Check if there is a corresponding subnet */
2722 ote_debug(" |- Delete SID %d to subnet %pFX", subnet
->ls_pref
->sr
.sid
,
2723 &subnet
->ls_pref
->pref
);
2725 /* Remove Segment Routing information */
2726 ls_pref
= subnet
->ls_pref
;
2727 UNSET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
2728 memset(&ls_pref
->sr
, 0, sizeof(struct ls_sid
));
2729 subnet
->status
= UPDATE
;
2731 /* Subnet has been updated: export it */
2732 ospf_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
2733 subnet
->status
= SYNC
;
2739 * Parse Opaque Extended Link LSA (Type 8) TLVs and update the corresponding
2740 * Link State Edge with these information (Segment Routing Adjacency).
2742 * @param ted Link State Traffic Engineering Database
2743 * @param lsa OSPF Link State Advertisement
2745 * @return 0 if success, -1 otherwise
2747 static int ospf_te_parse_ext_link(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2749 struct ls_node_id lnid
;
2750 struct tlv_header
*tlvh
;
2751 struct ext_tlv_link
*ext
;
2752 struct ls_edge
*edge
;
2753 struct ls_attributes
*atr
;
2754 uint16_t len
= 0, sum
= 0, i
;
2757 /* Get corresponding Edge from Link State Data Base */
2758 lnid
.origin
= OSPFv2
;
2759 lnid
.id
.ip
.addr
= lsa
->data
->adv_router
;
2760 lnid
.id
.ip
.area_id
= lsa
->area
->area_id
;
2761 ext
= (struct ext_tlv_link
*)TLV_HDR_TOP(lsa
->data
);
2762 edge
= get_edge(ted
, lnid
, ext
->link_data
);
2763 atr
= edge
->attributes
;
2765 ote_debug(" |- Process Extended Link LSA %pI4 for edge %pI4",
2766 &lsa
->data
->id
, &edge
->attributes
->standard
.local
);
2768 /* Initialize TLV browsing */
2769 len
= TLV_BODY_SIZE(&ext
->header
) - EXT_TLV_LINK_SIZE
;
2770 tlvh
= (struct tlv_header
*)((char *)(ext
) + TLV_HDR_SIZE
2771 + EXT_TLV_LINK_SIZE
);
2772 for (; sum
< len
; tlvh
= TLV_HDR_NEXT(tlvh
)) {
2773 struct ext_subtlv_adj_sid
*adj
;
2774 struct ext_subtlv_lan_adj_sid
*ladj
;
2775 struct ext_subtlv_rmt_itf_addr
*rmt
;
2777 switch (ntohs(tlvh
->type
)) {
2778 case EXT_SUBTLV_ADJ_SID
:
2779 adj
= (struct ext_subtlv_adj_sid
*)tlvh
;
2780 label
= CHECK_FLAG(adj
->flags
,
2781 EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
2782 ? GET_LABEL(ntohl(adj
->value
))
2783 : ntohl(adj
->value
);
2784 i
= CHECK_FLAG(adj
->flags
,
2785 EXT_SUBTLV_LINK_ADJ_SID_BFLG
) ? 1 : 0;
2786 if (((i
&& CHECK_FLAG(atr
->flags
, LS_ATTR_BCK_ADJ_SID
))
2787 || (!i
&& CHECK_FLAG(atr
->flags
, LS_ATTR_ADJ_SID
)))
2788 && atr
->adj_sid
[i
].flags
== adj
->flags
2789 && atr
->adj_sid
[i
].sid
== label
2790 && atr
->adj_sid
[i
].weight
== adj
->weight
)
2793 atr
->adj_sid
[i
].flags
= adj
->flags
;
2794 atr
->adj_sid
[i
].sid
= label
;
2795 atr
->adj_sid
[i
].weight
= adj
->weight
;
2797 SET_FLAG(atr
->flags
, LS_ATTR_ADJ_SID
);
2799 SET_FLAG(atr
->flags
, LS_ATTR_BCK_ADJ_SID
);
2800 if (edge
->status
!= NEW
)
2801 edge
->status
= UPDATE
;
2804 case EXT_SUBTLV_LAN_ADJ_SID
:
2805 ladj
= (struct ext_subtlv_lan_adj_sid
*)tlvh
;
2806 label
= CHECK_FLAG(ladj
->flags
,
2807 EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
2808 ? GET_LABEL(ntohl(ladj
->value
))
2809 : ntohl(ladj
->value
);
2810 i
= CHECK_FLAG(ladj
->flags
,
2811 EXT_SUBTLV_LINK_ADJ_SID_BFLG
) ? 1 : 0;
2812 if (((i
&& CHECK_FLAG(atr
->flags
, LS_ATTR_BCK_ADJ_SID
))
2813 || (!i
&& CHECK_FLAG(atr
->flags
, LS_ATTR_ADJ_SID
)))
2814 && atr
->adj_sid
[i
].flags
== ladj
->flags
2815 && atr
->adj_sid
[i
].sid
== label
2816 && atr
->adj_sid
[i
].weight
== ladj
->weight
2817 && IPV4_ADDR_SAME(&atr
->adj_sid
[1].neighbor
.addr
,
2818 &ladj
->neighbor_id
))
2821 atr
->adj_sid
[i
].flags
= ladj
->flags
;
2822 atr
->adj_sid
[i
].sid
= label
;
2823 atr
->adj_sid
[i
].weight
= ladj
->weight
;
2824 atr
->adj_sid
[i
].neighbor
.addr
= ladj
->neighbor_id
;
2826 SET_FLAG(atr
->flags
, LS_ATTR_ADJ_SID
);
2828 SET_FLAG(atr
->flags
, LS_ATTR_BCK_ADJ_SID
);
2829 if (edge
->status
!= NEW
)
2830 edge
->status
= UPDATE
;
2833 case EXT_SUBTLV_RMT_ITF_ADDR
:
2834 rmt
= (struct ext_subtlv_rmt_itf_addr
*)tlvh
;
2835 if (CHECK_FLAG(atr
->flags
, LS_ATTR_NEIGH_ADDR
)
2836 && IPV4_ADDR_SAME(&atr
->standard
.remote
,
2840 atr
->standard
.remote
= rmt
->value
;
2841 SET_FLAG(atr
->flags
, LS_ATTR_NEIGH_ADDR
);
2842 if (edge
->status
!= NEW
)
2843 edge
->status
= UPDATE
;
2849 sum
+= TLV_SIZE(tlvh
);
2852 /* Export Link State Edge if needed */
2853 if (edge
->status
== NEW
|| edge
->status
== UPDATE
) {
2854 ote_debug(" |- %s Adj-SID %d & %d to edge %pI4",
2855 edge
->status
== NEW
? "Add" : "Update",
2856 edge
->attributes
->adj_sid
[0].sid
,
2857 edge
->attributes
->adj_sid
[1].sid
,
2858 &edge
->attributes
->standard
.local
);
2860 ospf_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
2861 edge
->status
= SYNC
;
2868 * Delete Link State Edge information (Segment Routing Adjacency) that
2869 * correspond to the Opaque Extended Link LSA (Type 8) TLVs. Note that the Edge
2872 * @param ted Link State Traffic Engineering Database
2873 * @param lsa OSPF Link State Advertisement
2875 * @return 0 if success, -1 otherwise
2877 static int ospf_te_delete_ext_link(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2879 struct ls_edge
*edge
;
2880 struct ls_attributes
*atr
;
2881 struct ext_tlv_link
*ext
;
2884 /* Search for corresponding Edge from Link State Data Base */
2885 ext
= (struct ext_tlv_link
*)TLV_HDR_TOP(lsa
->data
);
2886 key
= ((uint64_t)ntohl(ext
->link_data
.s_addr
)) & 0xffffffff;
2887 edge
= ls_find_edge_by_key(ted
, key
);
2889 /* Check if there is a corresponding Edge */
2893 ote_debug(" |- Delete Adj-SID %d to edge %pI4",
2894 edge
->attributes
->adj_sid
[0].sid
,
2895 &edge
->attributes
->standard
.local
);
2897 /* Remove Segment Routing information */
2898 atr
= edge
->attributes
;
2899 UNSET_FLAG(atr
->flags
, LS_ATTR_ADJ_SID
);
2900 UNSET_FLAG(atr
->flags
, LS_ATTR_BCK_ADJ_SID
);
2901 memset(atr
->adj_sid
, 0, 2 * sizeof(struct ls_sid
));
2902 edge
->status
= UPDATE
;
2904 /* Edge has been updated: export it */
2905 ospf_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
2906 edge
->status
= SYNC
;
2912 * Parse Opaque LSA Type and call corresponding parser.
2914 * @param ted Link State Traffic Engineering Database
2915 * @param lsa OSPF Link State Advertisement
2917 * @return 0 if success, -1 otherwise
2919 static int ospf_te_parse_opaque_lsa(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2921 uint8_t key
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
2924 ote_debug("MPLS-TE (%s): Parse Opaque LSA[%pI4] from Router[%pI4]",
2925 __func__
, &lsa
->data
->id
, &lsa
->data
->adv_router
);
2928 case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
:
2929 case OPAQUE_TYPE_INTER_AS_LSA
:
2930 rc
= ospf_te_parse_te(ted
, lsa
);
2932 case OPAQUE_TYPE_ROUTER_INFORMATION_LSA
:
2933 rc
= ospf_te_parse_ri(ted
, lsa
);
2935 case OPAQUE_TYPE_EXTENDED_PREFIX_LSA
:
2936 rc
= ospf_te_parse_ext_pref(ted
, lsa
);
2938 case OPAQUE_TYPE_EXTENDED_LINK_LSA
:
2939 rc
= ospf_te_parse_ext_link(ted
, lsa
);
2949 * Parse Opaque LSA Type and call corresponding deletion function.
2951 * @param ted Link State Traffic Engineering Database
2952 * @param lsa OSPF Link State Advertisement
2954 * @return 0 if success, -1 otherwise
2956 static int ospf_te_delete_opaque_lsa(struct ls_ted
*ted
, struct ospf_lsa
*lsa
)
2958 uint8_t key
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
2961 ote_debug("MPLS-TE (%s): Parse Opaque LSA[%pI4] from Router[%pI4]",
2962 __func__
, &lsa
->data
->id
, &lsa
->data
->adv_router
);
2965 case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
:
2966 case OPAQUE_TYPE_INTER_AS_LSA
:
2967 rc
= ospf_te_delete_te(ted
, lsa
);
2969 case OPAQUE_TYPE_ROUTER_INFORMATION_LSA
:
2970 rc
= ospf_te_delete_ri(ted
, lsa
);
2972 case OPAQUE_TYPE_EXTENDED_PREFIX_LSA
:
2973 rc
= ospf_te_delete_ext_pref(ted
, lsa
);
2975 case OPAQUE_TYPE_EXTENDED_LINK_LSA
:
2976 rc
= ospf_te_delete_ext_link(ted
, lsa
);
2986 * Update Traffic Engineering Database Elements that correspond to the received
2987 * OSPF LSA. If LSA age is equal to MAX_AGE, call deletion function instead.
2989 * @param lsa OSPF Link State Advertisement
2991 * @return 0 if success, -1 otherwise
2993 static int ospf_mpls_te_lsa_update(struct ospf_lsa
*lsa
)
2998 /* Check that MPLS-TE is active */
2999 if (!OspfMplsTE
.enabled
|| !OspfMplsTE
.ted
)
3004 flog_warn(EC_OSPF_LSA_NULL
, "TE (%s): Abort! LSA is NULL",
3009 /* If LSA is MAX_AGE, remove corresponding Link State element */
3010 if (IS_LSA_MAXAGE(lsa
)) {
3011 switch (lsa
->data
->type
) {
3012 case OSPF_ROUTER_LSA
:
3013 rc
= ospf_te_delete_router_lsa(OspfMplsTE
.ted
, lsa
);
3015 case OSPF_OPAQUE_AREA_LSA
:
3016 case OSPF_OPAQUE_AS_LSA
:
3017 rc
= ospf_te_delete_opaque_lsa(OspfMplsTE
.ted
, lsa
);
3024 /* Parse LSA to Update corresponding Link State element */
3025 switch (lsa
->data
->type
) {
3026 case OSPF_ROUTER_LSA
:
3027 rc
= ospf_te_parse_router_lsa(OspfMplsTE
.ted
, lsa
);
3029 case OSPF_OPAQUE_AREA_LSA
:
3030 case OSPF_OPAQUE_AS_LSA
:
3031 rc
= ospf_te_parse_opaque_lsa(OspfMplsTE
.ted
, lsa
);
3043 * Delete Traffic Engineering Database element from OSPF LSA. This function
3044 * process only self LSA (i.e. advertised by the router) which reach MAX_AGE
3045 * as LSA deleted by neighbor routers are Flushed (i.e. advertised with
3046 * age == MAX_AGE) and processed by ospf_mpls_te_lsa_update() function.
3048 * @param lsa OSPF Link State Advertisement
3050 * @return 0 if success, -1 otherwise
3052 static int ospf_mpls_te_lsa_delete(struct ospf_lsa
*lsa
)
3057 /* Check that MPLS-TE is active */
3058 if (!OspfMplsTE
.enabled
|| !OspfMplsTE
.ted
)
3063 flog_warn(EC_OSPF_LSA_NULL
, "TE (%s): Abort! LSA is NULL",
3069 * Process only self LSAs that reach MAX_AGE. Indeed, when the router
3070 * need to update or refresh an LSA, it first removes the old LSA from
3071 * the LSDB and then insert the new one. Thus, to avoid removing
3072 * corresponding Link State element and loosing some parameters
3073 * instead of just updating it, only self LSAs that reach MAX_AGE are
3074 * processed here. Other LSAs are processed by ospf_mpls_te_lsa_update()
3075 * and eventually removed when LSA age is MAX_AGE i.e. LSA is flushed
3076 * by the originator.
3078 if (!IS_LSA_SELF(lsa
) || !IS_LSA_MAXAGE(lsa
))
3081 /* Parse Link State information */
3082 switch (lsa
->data
->type
) {
3083 case OSPF_ROUTER_LSA
:
3084 rc
= ospf_te_delete_router_lsa(OspfMplsTE
.ted
, lsa
);
3086 case OSPF_OPAQUE_AREA_LSA
:
3087 case OSPF_OPAQUE_AS_LSA
:
3088 rc
= ospf_te_delete_opaque_lsa(OspfMplsTE
.ted
, lsa
);
3099 * Send the whole Link State Traffic Engineering Database to the consumer that
3100 * request it through a ZAPI Link State Synchronous Opaque Message.
3102 * @param info ZAPI Opaque message
3104 * @return 0 if success, -1 otherwise
3106 int ospf_te_sync_ted(struct zapi_opaque_reg_info dst
)
3110 /* Check that MPLS-TE and TE distribution are enabled */
3111 if (!OspfMplsTE
.enabled
|| !OspfMplsTE
.export
)
3114 rc
= ls_sync_ted(OspfMplsTE
.ted
, zclient
, &dst
);
3120 * Initialize Traffic Engineering Database from the various OSPF Link State
3123 * @param ted Link State Traffice Engineering Database
3124 * @param ospf OSPF main structure
3126 static void ospf_te_init_ted(struct ls_ted
*ted
, struct ospf
*ospf
)
3128 struct listnode
*node
, *nnode
;
3129 struct route_node
*rn
;
3130 struct ospf_area
*area
;
3131 struct ospf_lsa
*lsa
;
3133 /* Iterate over all areas. */
3134 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
)) {
3138 /* Parse all Router LSAs from the area LSDB */
3139 LSDB_LOOP (ROUTER_LSDB(area
), rn
, lsa
)
3140 ospf_te_parse_router_lsa(ted
, lsa
);
3142 /* Parse all Opaque LSAs from the area LSDB */
3143 LSDB_LOOP (OPAQUE_AREA_LSDB(area
), rn
, lsa
)
3144 ospf_te_parse_opaque_lsa(ted
, lsa
);
3147 /* Parse AS-external opaque LSAs from OSPF LSDB */
3149 LSDB_LOOP (OPAQUE_AS_LSDB(ospf
), rn
, lsa
)
3150 ospf_te_parse_opaque_lsa(ted
, lsa
);
3155 /*------------------------------------------------------------------------*
3156 * Followings are vty session control functions.
3157 *------------------------------------------------------------------------*/
3158 #define check_tlv_size(size, msg) \
3160 if (ntohs(tlvh->length) > size) { \
3162 vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \
3163 msg, ntohs(tlvh->length), size); \
3165 zlog_debug(" Wrong %s TLV size: %d(%d)", \
3166 msg, ntohs(tlvh->length), size); \
3167 return size + TLV_HDR_SIZE; \
3171 static uint16_t show_vty_router_addr(struct vty
*vty
, struct tlv_header
*tlvh
)
3173 struct te_tlv_router_addr
*top
= (struct te_tlv_router_addr
*)tlvh
;
3175 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Router Address");
3178 vty_out(vty
, " Router-Address: %pI4\n", &top
->value
);
3180 zlog_debug(" Router-Address: %pI4", &top
->value
);
3182 return TLV_SIZE(tlvh
);
3185 static uint16_t show_vty_link_header(struct vty
*vty
, struct tlv_header
*tlvh
,
3188 struct te_tlv_link
*top
= (struct te_tlv_link
*)tlvh
;
3190 if (TLV_SIZE(tlvh
) > buf_size
) {
3193 " TLV size %d exceeds buffer size. Abort!",
3197 " TLV size %d exceeds buffer size. Abort!",
3203 vty_out(vty
, " Link: %u octets of data\n",
3204 ntohs(top
->header
.length
));
3206 zlog_debug(" Link: %u octets of data",
3207 ntohs(top
->header
.length
));
3209 return TLV_HDR_SIZE
; /* Here is special, not "TLV_SIZE". */
3212 static uint16_t show_vty_link_subtlv_link_type(struct vty
*vty
,
3213 struct tlv_header
*tlvh
)
3215 struct te_link_subtlv_link_type
*top
;
3216 const char *cp
= "Unknown";
3218 check_tlv_size(TE_LINK_SUBTLV_TYPE_SIZE
, "Link Type");
3220 top
= (struct te_link_subtlv_link_type
*)tlvh
;
3221 switch (top
->link_type
.value
) {
3222 case LINK_TYPE_SUBTLV_VALUE_PTP
:
3223 cp
= "Point-to-point";
3225 case LINK_TYPE_SUBTLV_VALUE_MA
:
3233 vty_out(vty
, " Link-Type: %s (%u)\n", cp
,
3234 top
->link_type
.value
);
3236 zlog_debug(" Link-Type: %s (%u)", cp
, top
->link_type
.value
);
3238 return TLV_SIZE(tlvh
);
3241 static uint16_t show_vty_link_subtlv_link_id(struct vty
*vty
,
3242 struct tlv_header
*tlvh
)
3244 struct te_link_subtlv_link_id
*top
;
3246 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Link ID");
3248 top
= (struct te_link_subtlv_link_id
*)tlvh
;
3250 vty_out(vty
, " Link-ID: %pI4\n", &top
->value
);
3252 zlog_debug(" Link-ID: %pI4", &top
->value
);
3254 return TLV_SIZE(tlvh
);
3257 static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty
*vty
,
3258 struct tlv_header
*tlvh
,
3261 struct te_link_subtlv_lclif_ipaddr
*top
;
3264 if (TLV_SIZE(tlvh
) > buf_size
) {
3267 " TLV size %d exceeds buffer size. Abort!",
3271 " TLV size %d exceeds buffer size. Abort!",
3276 top
= (struct te_link_subtlv_lclif_ipaddr
*)tlvh
;
3277 n
= ntohs(tlvh
->length
) / sizeof(top
->value
[0]);
3280 vty_out(vty
, " Local Interface IP Address(es): %d\n", n
);
3282 zlog_debug(" Local Interface IP Address(es): %d", n
);
3284 for (i
= 0; i
< n
; i
++) {
3286 vty_out(vty
, " #%d: %pI4\n", i
, &top
->value
[i
]);
3288 zlog_debug(" #%d: %pI4", i
, &top
->value
[i
]);
3290 return TLV_SIZE(tlvh
);
3293 static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty
*vty
,
3294 struct tlv_header
*tlvh
,
3297 struct te_link_subtlv_rmtif_ipaddr
*top
;
3300 if (TLV_SIZE(tlvh
) > buf_size
) {
3303 " TLV size %d exceeds buffer size. Abort!",
3307 " TLV size %d exceeds buffer size. Abort!",
3312 top
= (struct te_link_subtlv_rmtif_ipaddr
*)tlvh
;
3313 n
= ntohs(tlvh
->length
) / sizeof(top
->value
[0]);
3315 vty_out(vty
, " Remote Interface IP Address(es): %d\n", n
);
3317 zlog_debug(" Remote Interface IP Address(es): %d", n
);
3319 for (i
= 0; i
< n
; i
++) {
3321 vty_out(vty
, " #%d: %pI4\n", i
, &top
->value
[i
]);
3323 zlog_debug(" #%d: %pI4", i
, &top
->value
[i
]);
3325 return TLV_SIZE(tlvh
);
3328 static uint16_t show_vty_link_subtlv_te_metric(struct vty
*vty
,
3329 struct tlv_header
*tlvh
)
3331 struct te_link_subtlv_te_metric
*top
;
3333 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "TE Metric");
3335 top
= (struct te_link_subtlv_te_metric
*)tlvh
;
3337 vty_out(vty
, " Traffic Engineering Metric: %u\n",
3338 (uint32_t)ntohl(top
->value
));
3340 zlog_debug(" Traffic Engineering Metric: %u",
3341 (uint32_t)ntohl(top
->value
));
3343 return TLV_SIZE(tlvh
);
3346 static uint16_t show_vty_link_subtlv_max_bw(struct vty
*vty
,
3347 struct tlv_header
*tlvh
)
3349 struct te_link_subtlv_max_bw
*top
;
3352 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Maximum Bandwidth");
3354 top
= (struct te_link_subtlv_max_bw
*)tlvh
;
3355 fval
= ntohf(top
->value
);
3358 vty_out(vty
, " Maximum Bandwidth: %g (Bytes/sec)\n", fval
);
3360 zlog_debug(" Maximum Bandwidth: %g (Bytes/sec)", fval
);
3362 return TLV_SIZE(tlvh
);
3365 static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty
*vty
,
3366 struct tlv_header
*tlvh
)
3368 struct te_link_subtlv_max_rsv_bw
*top
;
3371 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Maximum Reservable Bandwidth");
3373 top
= (struct te_link_subtlv_max_rsv_bw
*)tlvh
;
3374 fval
= ntohf(top
->value
);
3377 vty_out(vty
, " Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
3380 zlog_debug(" Maximum Reservable Bandwidth: %g (Bytes/sec)",
3383 return TLV_SIZE(tlvh
);
3386 static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty
*vty
,
3387 struct tlv_header
*tlvh
)
3389 struct te_link_subtlv_unrsv_bw
*top
;
3393 check_tlv_size(TE_LINK_SUBTLV_UNRSV_SIZE
, "Unreserved Bandwidth");
3395 top
= (struct te_link_subtlv_unrsv_bw
*)tlvh
;
3398 " Unreserved Bandwidth per Class Type in Byte/s:\n");
3401 " Unreserved Bandwidth per Class Type in Byte/s:");
3402 for (i
= 0; i
< MAX_CLASS_TYPE
; i
+= 2) {
3403 fval1
= ntohf(top
->value
[i
]);
3404 fval2
= ntohf(top
->value
[i
+ 1]);
3408 " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
3409 i
, fval1
, i
+ 1, fval2
);
3412 " [%d]: %g (Bytes/sec), [%d]: %g (Bytes/sec)",
3413 i
, fval1
, i
+ 1, fval2
);
3416 return TLV_SIZE(tlvh
);
3419 static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty
*vty
,
3420 struct tlv_header
*tlvh
)
3422 struct te_link_subtlv_rsc_clsclr
*top
;
3424 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Resource class/color");
3426 top
= (struct te_link_subtlv_rsc_clsclr
*)tlvh
;
3428 vty_out(vty
, " Resource class/color: 0x%x\n",
3429 (uint32_t)ntohl(top
->value
));
3431 zlog_debug(" Resource Class/Color: 0x%x",
3432 (uint32_t)ntohl(top
->value
));
3434 return TLV_SIZE(tlvh
);
3437 static uint16_t show_vty_link_subtlv_lrrid(struct vty
*vty
,
3438 struct tlv_header
*tlvh
)
3440 struct te_link_subtlv_lrrid
*top
;
3442 check_tlv_size(TE_LINK_SUBTLV_LRRID_SIZE
, "Local/Remote Router ID");
3444 top
= (struct te_link_subtlv_lrrid
*)tlvh
;
3447 vty_out(vty
, " Local TE Router ID: %pI4\n",
3449 vty_out(vty
, " Remote TE Router ID: %pI4\n",
3452 zlog_debug(" Local TE Router ID: %pI4",
3454 zlog_debug(" Remote TE Router ID: %pI4",
3458 return TLV_SIZE(tlvh
);
3461 static uint16_t show_vty_link_subtlv_llri(struct vty
*vty
,
3462 struct tlv_header
*tlvh
)
3464 struct te_link_subtlv_llri
*top
;
3466 check_tlv_size(TE_LINK_SUBTLV_LLRI_SIZE
, "Link Local/Remote ID");
3468 top
= (struct te_link_subtlv_llri
*)tlvh
;
3471 vty_out(vty
, " Link Local ID: %d\n",
3472 (uint32_t)ntohl(top
->local
));
3473 vty_out(vty
, " Link Remote ID: %d\n",
3474 (uint32_t)ntohl(top
->remote
));
3476 zlog_debug(" Link Local ID: %d",
3477 (uint32_t)ntohl(top
->local
));
3478 zlog_debug(" Link Remote ID: %d",
3479 (uint32_t)ntohl(top
->remote
));
3482 return TLV_SIZE(tlvh
);
3485 static uint16_t show_vty_link_subtlv_rip(struct vty
*vty
,
3486 struct tlv_header
*tlvh
)
3488 struct te_link_subtlv_rip
*top
;
3490 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Remote ASBR Address");
3492 top
= (struct te_link_subtlv_rip
*)tlvh
;
3495 vty_out(vty
, " Inter-AS TE Remote ASBR IP address: %pI4\n",
3498 zlog_debug(" Inter-AS TE Remote ASBR IP address: %pI4",
3501 return TLV_SIZE(tlvh
);
3504 static uint16_t show_vty_link_subtlv_ras(struct vty
*vty
,
3505 struct tlv_header
*tlvh
)
3507 struct te_link_subtlv_ras
*top
;
3509 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Remote AS number");
3511 top
= (struct te_link_subtlv_ras
*)tlvh
;
3514 vty_out(vty
, " Inter-AS TE Remote AS number: %u\n",
3517 zlog_debug(" Inter-AS TE Remote AS number: %u",
3520 return TLV_SIZE(tlvh
);
3523 static uint16_t show_vty_link_subtlv_av_delay(struct vty
*vty
,
3524 struct tlv_header
*tlvh
)
3526 struct te_link_subtlv_av_delay
*top
;
3530 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Average Link Delay");
3532 top
= (struct te_link_subtlv_av_delay
*)tlvh
;
3533 delay
= (uint32_t)ntohl(top
->value
) & TE_EXT_MASK
;
3534 anomalous
= (uint32_t)ntohl(top
->value
) & TE_EXT_ANORMAL
;
3537 vty_out(vty
, " %s Average Link Delay: %d (micro-sec)\n",
3538 anomalous
? "Anomalous" : "Normal", delay
);
3540 zlog_debug(" %s Average Link Delay: %d (micro-sec)",
3541 anomalous
? "Anomalous" : "Normal", delay
);
3543 return TLV_SIZE(tlvh
);
3546 static uint16_t show_vty_link_subtlv_mm_delay(struct vty
*vty
,
3547 struct tlv_header
*tlvh
)
3549 struct te_link_subtlv_mm_delay
*top
;
3553 check_tlv_size(TE_LINK_SUBTLV_MM_DELAY_SIZE
, "Min/Max Link Delay");
3555 top
= (struct te_link_subtlv_mm_delay
*)tlvh
;
3556 low
= (uint32_t)ntohl(top
->low
) & TE_EXT_MASK
;
3557 anomalous
= (uint32_t)ntohl(top
->low
) & TE_EXT_ANORMAL
;
3558 high
= (uint32_t)ntohl(top
->high
);
3561 vty_out(vty
, " %s Min/Max Link Delay: %d/%d (micro-sec)\n",
3562 anomalous
? "Anomalous" : "Normal", low
, high
);
3564 zlog_debug(" %s Min/Max Link Delay: %d/%d (micro-sec)",
3565 anomalous
? "Anomalous" : "Normal", low
, high
);
3567 return TLV_SIZE(tlvh
);
3570 static uint16_t show_vty_link_subtlv_delay_var(struct vty
*vty
,
3571 struct tlv_header
*tlvh
)
3573 struct te_link_subtlv_delay_var
*top
;
3576 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Link Delay Variation");
3578 top
= (struct te_link_subtlv_delay_var
*)tlvh
;
3579 jitter
= (uint32_t)ntohl(top
->value
) & TE_EXT_MASK
;
3582 vty_out(vty
, " Delay Variation: %d (micro-sec)\n", jitter
);
3584 zlog_debug(" Delay Variation: %d (micro-sec)", jitter
);
3586 return TLV_SIZE(tlvh
);
3589 static uint16_t show_vty_link_subtlv_pkt_loss(struct vty
*vty
,
3590 struct tlv_header
*tlvh
)
3592 struct te_link_subtlv_pkt_loss
*top
;
3597 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Link Loss");
3599 top
= (struct te_link_subtlv_pkt_loss
*)tlvh
;
3600 loss
= (uint32_t)ntohl(top
->value
) & TE_EXT_MASK
;
3601 fval
= (float)(loss
* LOSS_PRECISION
);
3602 anomalous
= (uint32_t)ntohl(top
->value
) & TE_EXT_ANORMAL
;
3605 vty_out(vty
, " %s Link Loss: %g (%%)\n",
3606 anomalous
? "Anomalous" : "Normal", fval
);
3608 zlog_debug(" %s Link Loss: %g (%%)",
3609 anomalous
? "Anomalous" : "Normal", fval
);
3611 return TLV_SIZE(tlvh
);
3614 static uint16_t show_vty_link_subtlv_res_bw(struct vty
*vty
,
3615 struct tlv_header
*tlvh
)
3617 struct te_link_subtlv_res_bw
*top
;
3620 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Residual Bandwidth");
3622 top
= (struct te_link_subtlv_res_bw
*)tlvh
;
3623 fval
= ntohf(top
->value
);
3627 " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
3631 " Unidirectional Residual Bandwidth: %g (Bytes/sec)",
3634 return TLV_SIZE(tlvh
);
3637 static uint16_t show_vty_link_subtlv_ava_bw(struct vty
*vty
,
3638 struct tlv_header
*tlvh
)
3640 struct te_link_subtlv_ava_bw
*top
;
3643 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Available Bandwidth");
3645 top
= (struct te_link_subtlv_ava_bw
*)tlvh
;
3646 fval
= ntohf(top
->value
);
3650 " Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
3654 " Unidirectional Available Bandwidth: %g (Bytes/sec)",
3657 return TLV_SIZE(tlvh
);
3660 static uint16_t show_vty_link_subtlv_use_bw(struct vty
*vty
,
3661 struct tlv_header
*tlvh
)
3663 struct te_link_subtlv_use_bw
*top
;
3666 check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE
, "Utilized Bandwidth");
3668 top
= (struct te_link_subtlv_use_bw
*)tlvh
;
3669 fval
= ntohf(top
->value
);
3673 " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
3677 " Unidirectional Utilized Bandwidth: %g (Bytes/sec)",
3680 return TLV_SIZE(tlvh
);
3683 static uint16_t show_vty_unknown_tlv(struct vty
*vty
, struct tlv_header
*tlvh
,
3686 if (TLV_SIZE(tlvh
) > buf_size
) {
3689 " TLV size %d exceeds buffer size. Abort!",
3693 " TLV size %d exceeds buffer size. Abort!",
3699 vty_out(vty
, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
3700 ntohs(tlvh
->type
), ntohs(tlvh
->length
));
3702 zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]",
3703 ntohs(tlvh
->type
), ntohs(tlvh
->length
));
3705 return TLV_SIZE(tlvh
);
3708 static uint16_t ospf_mpls_te_show_link_subtlv(struct vty
*vty
,
3709 struct tlv_header
*tlvh0
,
3710 uint16_t subtotal
, uint16_t total
)
3712 struct tlv_header
*tlvh
;
3713 uint16_t sum
= subtotal
;
3715 for (tlvh
= tlvh0
; sum
< total
; tlvh
= TLV_HDR_NEXT(tlvh
)) {
3716 switch (ntohs(tlvh
->type
)) {
3717 case TE_LINK_SUBTLV_LINK_TYPE
:
3718 sum
+= show_vty_link_subtlv_link_type(vty
, tlvh
);
3720 case TE_LINK_SUBTLV_LINK_ID
:
3721 sum
+= show_vty_link_subtlv_link_id(vty
, tlvh
);
3723 case TE_LINK_SUBTLV_LCLIF_IPADDR
:
3724 sum
+= show_vty_link_subtlv_lclif_ipaddr(vty
, tlvh
,
3727 case TE_LINK_SUBTLV_RMTIF_IPADDR
:
3728 sum
+= show_vty_link_subtlv_rmtif_ipaddr(vty
, tlvh
,
3731 case TE_LINK_SUBTLV_TE_METRIC
:
3732 sum
+= show_vty_link_subtlv_te_metric(vty
, tlvh
);
3734 case TE_LINK_SUBTLV_MAX_BW
:
3735 sum
+= show_vty_link_subtlv_max_bw(vty
, tlvh
);
3737 case TE_LINK_SUBTLV_MAX_RSV_BW
:
3738 sum
+= show_vty_link_subtlv_max_rsv_bw(vty
, tlvh
);
3740 case TE_LINK_SUBTLV_UNRSV_BW
:
3741 sum
+= show_vty_link_subtlv_unrsv_bw(vty
, tlvh
);
3743 case TE_LINK_SUBTLV_RSC_CLSCLR
:
3744 sum
+= show_vty_link_subtlv_rsc_clsclr(vty
, tlvh
);
3746 case TE_LINK_SUBTLV_LRRID
:
3747 sum
+= show_vty_link_subtlv_lrrid(vty
, tlvh
);
3749 case TE_LINK_SUBTLV_LLRI
:
3750 sum
+= show_vty_link_subtlv_llri(vty
, tlvh
);
3752 case TE_LINK_SUBTLV_RIP
:
3753 sum
+= show_vty_link_subtlv_rip(vty
, tlvh
);
3755 case TE_LINK_SUBTLV_RAS
:
3756 sum
+= show_vty_link_subtlv_ras(vty
, tlvh
);
3758 case TE_LINK_SUBTLV_AV_DELAY
:
3759 sum
+= show_vty_link_subtlv_av_delay(vty
, tlvh
);
3761 case TE_LINK_SUBTLV_MM_DELAY
:
3762 sum
+= show_vty_link_subtlv_mm_delay(vty
, tlvh
);
3764 case TE_LINK_SUBTLV_DELAY_VAR
:
3765 sum
+= show_vty_link_subtlv_delay_var(vty
, tlvh
);
3767 case TE_LINK_SUBTLV_PKT_LOSS
:
3768 sum
+= show_vty_link_subtlv_pkt_loss(vty
, tlvh
);
3770 case TE_LINK_SUBTLV_RES_BW
:
3771 sum
+= show_vty_link_subtlv_res_bw(vty
, tlvh
);
3773 case TE_LINK_SUBTLV_AVA_BW
:
3774 sum
+= show_vty_link_subtlv_ava_bw(vty
, tlvh
);
3776 case TE_LINK_SUBTLV_USE_BW
:
3777 sum
+= show_vty_link_subtlv_use_bw(vty
, tlvh
);
3780 sum
+= show_vty_unknown_tlv(vty
, tlvh
, total
- sum
);
3787 static void ospf_mpls_te_show_info(struct vty
*vty
, struct json_object
*json
,
3788 struct ospf_lsa
*lsa
)
3790 struct lsa_header
*lsah
= lsa
->data
;
3791 struct tlv_header
*tlvh
, *next
;
3792 uint16_t sum
, total
;
3793 uint16_t (*subfunc
)(struct vty
* vty
, struct tlv_header
* tlvh
,
3794 uint16_t subtotal
, uint16_t total
) = NULL
;
3800 total
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
3802 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< total
&& tlvh
;
3803 tlvh
= (next
? next
: TLV_HDR_NEXT(tlvh
))) {
3804 if (subfunc
!= NULL
) {
3805 sum
= (*subfunc
)(vty
, tlvh
, sum
, total
);
3806 next
= (struct tlv_header
*)((char *)tlvh
+ sum
);
3812 switch (ntohs(tlvh
->type
)) {
3813 case TE_TLV_ROUTER_ADDR
:
3814 sum
+= show_vty_router_addr(vty
, tlvh
);
3817 sum
+= show_vty_link_header(vty
, tlvh
, total
- sum
);
3818 subfunc
= ospf_mpls_te_show_link_subtlv
;
3819 next
= TLV_DATA(tlvh
);
3822 sum
+= show_vty_unknown_tlv(vty
, tlvh
, total
- sum
);
3829 static void ospf_mpls_te_config_write_router(struct vty
*vty
)
3832 if (OspfMplsTE
.enabled
) {
3833 vty_out(vty
, " mpls-te on\n");
3834 vty_out(vty
, " mpls-te router-address %pI4\n",
3835 &OspfMplsTE
.router_addr
.value
);
3837 if (OspfMplsTE
.inter_as
== AS
)
3838 vty_out(vty
, " mpls-te inter-as as\n");
3839 if (OspfMplsTE
.inter_as
== Area
)
3840 vty_out(vty
, " mpls-te inter-as area %pI4 \n",
3841 &OspfMplsTE
.interas_areaid
);
3842 if (OspfMplsTE
.export
)
3843 vty_out(vty
, " mpls-te export\n");
3848 /*------------------------------------------------------------------------*
3849 * Followings are vty command functions.
3850 *------------------------------------------------------------------------*/
3852 DEFUN (ospf_mpls_te_on
,
3853 ospf_mpls_te_on_cmd
,
3856 "Enable the MPLS-TE functionality\n")
3858 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
3859 struct listnode
*node
;
3860 struct mpls_te_link
*lp
;
3862 if (OspfMplsTE
.enabled
)
3865 ote_debug("MPLS-TE: OFF -> ON");
3867 OspfMplsTE
.enabled
= true;
3869 /* Reoriginate RFC3630 & RFC6827 Links */
3870 ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule
,
3871 REORIGINATE_THIS_LSA
);
3873 /* Reoriginate LSA if INTER-AS is always on */
3874 if (OspfMplsTE
.inter_as
!= Off
) {
3875 for (ALL_LIST_ELEMENTS_RO(OspfMplsTE
.iflist
, node
, lp
)) {
3876 if (IS_INTER_AS(lp
->type
)) {
3877 ospf_mpls_te_lsa_schedule(lp
,
3878 REORIGINATE_THIS_LSA
);
3883 /* Create TED and initialize it */
3884 OspfMplsTE
.ted
= ls_ted_new(1, "OSPF", 0);
3885 if (!OspfMplsTE
.ted
) {
3886 vty_out(vty
, "Unable to create Link State Data Base\n");
3889 ospf_te_init_ted(OspfMplsTE
.ted
, ospf
);
3894 DEFUN (no_ospf_mpls_te
,
3895 no_ospf_mpls_te_cmd
,
3899 "Disable the MPLS-TE functionality\n")
3901 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
3902 struct listnode
*node
, *nnode
;
3903 struct mpls_te_link
*lp
;
3905 if (!OspfMplsTE
.enabled
)
3908 ote_debug("MPLS-TE: ON -> OFF");
3911 ls_ted_del_all(&OspfMplsTE
.ted
);
3912 OspfMplsTE
.enabled
= false;
3914 /* Flush all TE Opaque LSAs */
3915 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
))
3916 if (CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
))
3917 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
3920 * This resets the OspfMplsTE.inter_as to its initial state.
3921 * This is to avoid having an inter-as value different from
3922 * Off when mpls-te gets restarted (after being removed)
3924 OspfMplsTE
.inter_as
= Off
;
3929 DEFUN (ospf_mpls_te_router_addr
,
3930 ospf_mpls_te_router_addr_cmd
,
3931 "mpls-te router-address A.B.C.D",
3933 "Stable IP address of the advertising router\n"
3934 "MPLS-TE router address in IPv4 address format\n")
3936 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
3938 struct te_tlv_router_addr
*ra
= &OspfMplsTE
.router_addr
;
3939 struct in_addr value
;
3941 if (!inet_aton(argv
[idx_ipv4
]->arg
, &value
)) {
3942 vty_out(vty
, "Please specify Router-Addr by A.B.C.D\n");
3946 if (ntohs(ra
->header
.type
) == 0
3947 || ntohl(ra
->value
.s_addr
) != ntohl(value
.s_addr
)) {
3948 struct listnode
*node
, *nnode
;
3949 struct mpls_te_link
*lp
;
3950 int need_to_reoriginate
= 0;
3952 set_mpls_te_router_addr(value
);
3954 if (!OspfMplsTE
.enabled
)
3957 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
)) {
3958 if ((lp
->area
== NULL
) || IS_FLOOD_AS(lp
->flags
))
3961 if (!CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
)) {
3962 need_to_reoriginate
= 1;
3967 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
)) {
3968 if ((lp
->area
== NULL
) || IS_FLOOD_AS(lp
->flags
))
3971 if (need_to_reoriginate
)
3972 SET_FLAG(lp
->flags
, LPFLG_LSA_FORCED_REFRESH
);
3974 ospf_mpls_te_lsa_schedule(lp
, REFRESH_THIS_LSA
);
3977 if (need_to_reoriginate
)
3978 ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule
,
3979 REORIGINATE_THIS_LSA
);
3985 static int set_inter_as_mode(struct vty
*vty
, const char *mode_name
,
3986 const char *area_id
)
3988 enum inter_as_mode mode
;
3989 struct listnode
*node
;
3990 struct mpls_te_link
*lp
;
3993 if (OspfMplsTE
.enabled
) {
3995 /* Read and Check inter_as mode */
3996 if (strcmp(mode_name
, "as") == 0)
3998 else if (strcmp(mode_name
, "area") == 0) {
4000 VTY_GET_OSPF_AREA_ID(OspfMplsTE
.interas_areaid
, format
,
4004 "Unknown mode. Please choose between as or area\n");
4009 "MPLS-TE (%s): Inter-AS enable with %s flooding support",
4010 __func__
, mode2text
[mode
]);
4012 /* Enable mode and re-originate LSA if needed */
4013 if ((OspfMplsTE
.inter_as
== Off
)
4014 && (mode
!= OspfMplsTE
.inter_as
)) {
4015 OspfMplsTE
.inter_as
= mode
;
4016 /* Re-originate all InterAS-TEv2 LSA */
4017 for (ALL_LIST_ELEMENTS_RO(OspfMplsTE
.iflist
, node
,
4019 if (IS_INTER_AS(lp
->type
)) {
4022 LPFLG_LSA_FLOOD_AS
);
4024 UNSET_FLAG(lp
->flags
,
4025 LPFLG_LSA_FLOOD_AS
);
4026 ospf_mpls_te_lsa_schedule(
4027 lp
, REORIGINATE_THIS_LSA
);
4032 "Please change Inter-AS support to disable first before going to mode %s\n",
4037 vty_out(vty
, "mpls-te has not been turned on\n");
4044 DEFUN (ospf_mpls_te_inter_as_as
,
4045 ospf_mpls_te_inter_as_cmd
,
4046 "mpls-te inter-as as",
4048 "Configure MPLS-TE Inter-AS support\n"
4049 "AS native mode self originate INTER_AS LSA with Type 11 (as flooding scope)\n")
4051 return set_inter_as_mode(vty
, "as", "");
4054 DEFUN (ospf_mpls_te_inter_as_area
,
4055 ospf_mpls_te_inter_as_area_cmd
,
4056 "mpls-te inter-as area <A.B.C.D|(0-4294967295)>",
4058 "Configure MPLS-TE Inter-AS support\n"
4059 "AREA native mode self originate INTER_AS LSA with Type 10 (area flooding scope)\n"
4060 "OSPF area ID in IP format\n"
4061 "OSPF area ID as decimal value\n")
4063 int idx_ipv4_number
= 3;
4064 return set_inter_as_mode(vty
, "area", argv
[idx_ipv4_number
]->arg
);
4067 DEFUN (no_ospf_mpls_te_inter_as
,
4068 no_ospf_mpls_te_inter_as_cmd
,
4069 "no mpls-te inter-as",
4072 "Disable MPLS-TE Inter-AS support\n")
4075 struct listnode
*node
, *nnode
;
4076 struct mpls_te_link
*lp
;
4078 ote_debug("MPLS-TE: Inter-AS support OFF");
4080 if ((OspfMplsTE
.enabled
) && (OspfMplsTE
.inter_as
!= Off
)) {
4081 /* Flush all Inter-AS LSA */
4082 for (ALL_LIST_ELEMENTS(OspfMplsTE
.iflist
, node
, nnode
, lp
))
4083 if (IS_INTER_AS(lp
->type
)
4084 && CHECK_FLAG(lp
->flags
, LPFLG_LSA_ENGAGED
))
4085 ospf_mpls_te_lsa_schedule(lp
, FLUSH_THIS_LSA
);
4087 OspfMplsTE
.inter_as
= Off
;
4093 DEFUN (ospf_mpls_te_export
,
4094 ospf_mpls_te_export_cmd
,
4097 "Export the MPLS-TE information as Link State\n")
4100 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
4102 if (OspfMplsTE
.enabled
) {
4103 if (ls_register(zclient
, true) != 0) {
4104 vty_out(vty
, "Unable to register Link State\n");
4107 OspfMplsTE
.export
= true;
4109 vty_out(vty
, "mpls-te has not been turned on\n");
4116 DEFUN (no_ospf_mpls_te_export
,
4117 no_ospf_mpls_te_export_cmd
,
4118 "no mpls-te export",
4121 "Stop export of the MPLS-TE information as Link State\n")
4124 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
4126 if (OspfMplsTE
.export
) {
4127 if (ls_unregister(zclient
, true) != 0) {
4128 vty_out(vty
, "Unable to unregister Link State\n");
4131 OspfMplsTE
.export
= false;
4136 DEFUN (show_ip_ospf_mpls_te_router
,
4137 show_ip_ospf_mpls_te_router_cmd
,
4138 "show ip ospf mpls-te router",
4142 "MPLS-TE information\n"
4143 "MPLS-TE Router parameters\n")
4145 if (OspfMplsTE
.enabled
) {
4146 vty_out(vty
, "--- MPLS-TE router parameters ---\n");
4148 if (ntohs(OspfMplsTE
.router_addr
.header
.type
) != 0)
4149 show_vty_router_addr(vty
,
4150 &OspfMplsTE
.router_addr
.header
);
4152 vty_out(vty
, " Router address is not set\n");
4153 vty_out(vty
, " Link State distribution is %s\n",
4154 OspfMplsTE
.export
? "Active" : "Inactive");
4159 static void show_mpls_te_link_sub(struct vty
*vty
, struct interface
*ifp
)
4161 struct mpls_te_link
*lp
;
4163 if ((OspfMplsTE
.enabled
) && HAS_LINK_PARAMS(ifp
) && !if_is_loopback(ifp
)
4165 && ((lp
= lookup_linkparams_by_ifp(ifp
)) != NULL
)) {
4166 /* Continue only if interface is not passive or support Inter-AS
4168 if (!(ospf_oi_count(ifp
) > 0)) {
4169 if (IS_INTER_AS(lp
->type
)) {
4171 "-- Inter-AS TEv2 link parameters for %s --\n",
4174 /* MPLS-TE is not activate on this interface */
4175 /* or this interface is passive and Inter-AS
4176 * TEv2 is not activate */
4178 " %s: MPLS-TE is disabled on this interface\n",
4183 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n",
4187 if (TLV_TYPE(lp
->link_type
) != 0)
4188 show_vty_link_subtlv_link_type(vty
,
4189 &lp
->link_type
.header
);
4190 if (TLV_TYPE(lp
->link_id
) != 0)
4191 show_vty_link_subtlv_link_id(vty
, &lp
->link_id
.header
);
4192 if (TLV_TYPE(lp
->lclif_ipaddr
) != 0)
4193 show_vty_link_subtlv_lclif_ipaddr(
4194 vty
, &lp
->lclif_ipaddr
.header
,
4195 lp
->lclif_ipaddr
.header
.length
);
4196 if (TLV_TYPE(lp
->rmtif_ipaddr
) != 0)
4197 show_vty_link_subtlv_rmtif_ipaddr(
4198 vty
, &lp
->rmtif_ipaddr
.header
,
4199 lp
->rmtif_ipaddr
.header
.length
);
4200 if (TLV_TYPE(lp
->rip
) != 0)
4201 show_vty_link_subtlv_rip(vty
, &lp
->rip
.header
);
4202 if (TLV_TYPE(lp
->ras
) != 0)
4203 show_vty_link_subtlv_ras(vty
, &lp
->ras
.header
);
4204 if (TLV_TYPE(lp
->te_metric
) != 0)
4205 show_vty_link_subtlv_te_metric(vty
,
4206 &lp
->te_metric
.header
);
4207 if (TLV_TYPE(lp
->max_bw
) != 0)
4208 show_vty_link_subtlv_max_bw(vty
, &lp
->max_bw
.header
);
4209 if (TLV_TYPE(lp
->max_rsv_bw
) != 0)
4210 show_vty_link_subtlv_max_rsv_bw(vty
,
4211 &lp
->max_rsv_bw
.header
);
4212 if (TLV_TYPE(lp
->unrsv_bw
) != 0)
4213 show_vty_link_subtlv_unrsv_bw(vty
,
4214 &lp
->unrsv_bw
.header
);
4215 if (TLV_TYPE(lp
->rsc_clsclr
) != 0)
4216 show_vty_link_subtlv_rsc_clsclr(vty
,
4217 &lp
->rsc_clsclr
.header
);
4218 if (TLV_TYPE(lp
->av_delay
) != 0)
4219 show_vty_link_subtlv_av_delay(vty
,
4220 &lp
->av_delay
.header
);
4221 if (TLV_TYPE(lp
->mm_delay
) != 0)
4222 show_vty_link_subtlv_mm_delay(vty
,
4223 &lp
->mm_delay
.header
);
4224 if (TLV_TYPE(lp
->delay_var
) != 0)
4225 show_vty_link_subtlv_delay_var(vty
,
4226 &lp
->delay_var
.header
);
4227 if (TLV_TYPE(lp
->pkt_loss
) != 0)
4228 show_vty_link_subtlv_pkt_loss(vty
,
4229 &lp
->pkt_loss
.header
);
4230 if (TLV_TYPE(lp
->res_bw
) != 0)
4231 show_vty_link_subtlv_res_bw(vty
, &lp
->res_bw
.header
);
4232 if (TLV_TYPE(lp
->ava_bw
) != 0)
4233 show_vty_link_subtlv_ava_bw(vty
, &lp
->ava_bw
.header
);
4234 if (TLV_TYPE(lp
->use_bw
) != 0)
4235 show_vty_link_subtlv_use_bw(vty
, &lp
->use_bw
.header
);
4236 vty_out(vty
, "---------------\n\n");
4238 vty_out(vty
, " %s: MPLS-TE is disabled on this interface\n",
4245 DEFUN (show_ip_ospf_mpls_te_link
,
4246 show_ip_ospf_mpls_te_link_cmd
,
4247 "show ip ospf [vrf <NAME|all>] mpls-te interface [INTERFACE]",
4253 "MPLS-TE information\n"
4254 "Interface information\n"
4258 int idx_interface
= 0;
4259 struct interface
*ifp
= NULL
;
4260 struct listnode
*node
;
4261 char *vrf_name
= NULL
;
4262 bool all_vrf
= false;
4265 struct ospf
*ospf
= NULL
;
4267 if (argv_find(argv
, argc
, "vrf", &idx_vrf
)) {
4268 vrf_name
= argv
[idx_vrf
+ 1]->arg
;
4269 all_vrf
= strmatch(vrf_name
, "all");
4271 argv_find(argv
, argc
, "INTERFACE", &idx_interface
);
4272 /* vrf input is provided could be all or specific vrf*/
4275 for (ALL_LIST_ELEMENTS_RO(om
->ospf
, node
, ospf
)) {
4276 if (!ospf
->oi_running
)
4278 vrf
= vrf_lookup_by_id(ospf
->vrf_id
);
4279 FOR_ALL_INTERFACES (vrf
, ifp
)
4280 show_mpls_te_link_sub(vty
, ifp
);
4284 ospf
= ospf_lookup_by_inst_name(inst
, vrf_name
);
4286 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
4287 if (ospf
== NULL
|| !ospf
->oi_running
)
4290 vrf
= vrf_lookup_by_id(ospf
->vrf_id
);
4293 if (idx_interface
) {
4294 ifp
= if_lookup_by_name(
4295 argv
[idx_interface
]->arg
,
4298 vty_out(vty
, "No such interface name in vrf %s\n",
4304 FOR_ALL_INTERFACES (vrf
, ifp
)
4305 show_mpls_te_link_sub(vty
, ifp
);
4309 show_mpls_te_link_sub(vty
, ifp
);
4313 DEFUN (show_ip_ospf_mpls_te_db
,
4314 show_ip_ospf_mpls_te_db_cmd
,
4315 "show ip ospf mpls-te database [<vertex [<self-originate|adv-router A.B.C.D>]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
4319 "MPLS-TE information\n"
4320 "MPLS-TE database\n"
4322 "Self-originated MPLS-TE router\n"
4323 "Advertised MPLS-TE router\n"
4324 "MPLS-TE router ID (as an IP address)\n"
4326 "MPLS-TE Edge ID (as an IP address)\n"
4328 "MPLS-TE Subnet ID (as an IP prefix)\n"
4333 struct in_addr ip_addr
;
4335 struct ls_vertex
*vertex
;
4336 struct ls_edge
*edge
;
4337 struct ls_subnet
*subnet
;
4339 bool verbose
= false;
4340 bool uj
= use_json(argc
, argv
);
4341 json_object
*json
= NULL
;
4343 if (!OspfMplsTE
.enabled
|| !OspfMplsTE
.ted
) {
4344 vty_out(vty
, "MPLS-TE database is not enabled\n");
4349 json
= json_object_new_object();
4351 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "verbose"))
4355 if (argv_find(argv
, argc
, "vertex", &idx
)) {
4357 if (argv_find(argv
, argc
, "self-originate", &idx
))
4358 vertex
= OspfMplsTE
.ted
->self
;
4359 else if (argv_find(argv
, argc
, "adv-router", &idx
)) {
4360 if (!inet_aton(argv
[idx
+ 1]->arg
, &ip_addr
)) {
4362 "Specified Router ID %s is invalid\n",
4363 argv
[idx
+ 1]->arg
);
4364 return CMD_WARNING_CONFIG_FAILED
;
4366 /* Get the Vertex from the Link State Database */
4367 key
= ((uint64_t)ntohl(ip_addr
.s_addr
)) & 0xffffffff;
4368 vertex
= ls_find_vertex_by_key(OspfMplsTE
.ted
, key
);
4370 vty_out(vty
, "No vertex found for ID %pI4\n",
4378 ls_show_vertex(vertex
, vty
, json
, verbose
);
4380 ls_show_vertices(OspfMplsTE
.ted
, vty
, json
, verbose
);
4382 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
4384 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
4385 if (!inet_aton(argv
[idx
]->arg
, &ip_addr
)) {
4387 "Specified Edge ID %s is invalid\n",
4389 return CMD_WARNING_CONFIG_FAILED
;
4391 /* Get the Edge from the Link State Database */
4392 key
= ((uint64_t)ntohl(ip_addr
.s_addr
)) & 0xffffffff;
4393 edge
= ls_find_edge_by_key(OspfMplsTE
.ted
, key
);
4395 vty_out(vty
, "No edge found for ID %pI4\n",
4403 ls_show_edge(edge
, vty
, json
, verbose
);
4405 ls_show_edges(OspfMplsTE
.ted
, vty
, json
, verbose
);
4407 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
4409 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
4410 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
4411 vty_out(vty
, "Invalid prefix format %s\n",
4413 return CMD_WARNING_CONFIG_FAILED
;
4415 /* Get the Subnet from the Link State Database */
4416 subnet
= ls_find_subnet(OspfMplsTE
.ted
, pref
);
4418 vty_out(vty
, "No subnet found for ID %pFX\n",
4426 ls_show_subnet(subnet
, vty
, json
, verbose
);
4428 ls_show_subnets(OspfMplsTE
.ted
, vty
, json
, verbose
);
4431 /* Show the complete TED */
4432 ls_show_ted(OspfMplsTE
.ted
, vty
, json
, verbose
);
4436 vty_json(vty
, json
);
4440 static void ospf_mpls_te_register_vty(void)
4442 install_element(VIEW_NODE
, &show_ip_ospf_mpls_te_router_cmd
);
4443 install_element(VIEW_NODE
, &show_ip_ospf_mpls_te_link_cmd
);
4444 install_element(VIEW_NODE
, &show_ip_ospf_mpls_te_db_cmd
);
4446 install_element(OSPF_NODE
, &ospf_mpls_te_on_cmd
);
4447 install_element(OSPF_NODE
, &no_ospf_mpls_te_cmd
);
4448 install_element(OSPF_NODE
, &ospf_mpls_te_router_addr_cmd
);
4449 install_element(OSPF_NODE
, &ospf_mpls_te_inter_as_cmd
);
4450 install_element(OSPF_NODE
, &ospf_mpls_te_inter_as_area_cmd
);
4451 install_element(OSPF_NODE
, &no_ospf_mpls_te_inter_as_cmd
);
4452 install_element(OSPF_NODE
, &ospf_mpls_te_export_cmd
);
4453 install_element(OSPF_NODE
, &no_ospf_mpls_te_export_cmd
);