2 * This is an implementation of RFC7684 OSPFv2 Prefix/Link Attribute
5 * Module name: Extended Prefix/Link Opaque LSA
7 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
8 * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
10 * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
43 #include "sockunion.h" /* for inet_aton() */
46 #include "libospf.h" /* for ospf interface types */
48 #include "ospfd/ospfd.h"
49 #include "ospfd/ospf_interface.h"
50 #include "ospfd/ospf_ism.h"
51 #include "ospfd/ospf_asbr.h"
52 #include "ospfd/ospf_lsa.h"
53 #include "ospfd/ospf_lsdb.h"
54 #include "ospfd/ospf_neighbor.h"
55 #include "ospfd/ospf_nsm.h"
56 #include "ospfd/ospf_flood.h"
57 #include "ospfd/ospf_packet.h"
58 #include "ospfd/ospf_spf.h"
59 #include "ospfd/ospf_dump.h"
60 #include "ospfd/ospf_route.h"
61 #include "ospfd/ospf_ase.h"
62 #include "ospfd/ospf_zebra.h"
63 #include "ospfd/ospf_sr.h"
64 #include "ospfd/ospf_ext.h"
65 #include "ospfd/ospf_errors.h"
67 /* Following structure are internal use only. */
70 * Global variable to manage Extended Prefix/Link Opaque LSA on this node.
71 * Note that all parameter values are stored in network byte order.
73 static struct ospf_ext_lp OspfEXT
;
76 * -----------------------------------------------------------------------
77 * Followings are initialize/terminate functions for Extended Prefix/Link
78 * Opaque LSA handling.
79 * -----------------------------------------------------------------------
82 /* Extended Prefix Opaque LSA related callback functions */
83 static void ospf_ext_pref_show_info(struct vty
*vty
, struct ospf_lsa
*lsa
);
84 static int ospf_ext_pref_lsa_originate(void *arg
);
85 static struct ospf_lsa
*ospf_ext_pref_lsa_refresh(struct ospf_lsa
*lsa
);
86 static void ospf_ext_pref_lsa_schedule(struct ext_itf
*exti
,
87 enum lsa_opcode opcode
);
88 /* Extended Link Opaque LSA related callback functions */
89 static int ospf_ext_link_new_if(struct interface
*ifp
);
90 static int ospf_ext_link_del_if(struct interface
*ifp
);
91 static void ospf_ext_ism_change(struct ospf_interface
*oi
, int old_status
);
92 static void ospf_ext_link_nsm_change(struct ospf_neighbor
*nbr
, int old_status
);
93 static void ospf_ext_link_show_info(struct vty
*vty
, struct ospf_lsa
*lsa
);
94 static int ospf_ext_link_lsa_originate(void *arg
);
95 static struct ospf_lsa
*ospf_ext_link_lsa_refresh(struct ospf_lsa
*lsa
);
96 static void ospf_ext_link_lsa_schedule(struct ext_itf
*exti
,
97 enum lsa_opcode opcode
);
98 static void ospf_ext_lsa_schedule(struct ext_itf
*exti
, enum lsa_opcode op
);
99 static int ospf_ext_link_lsa_update(struct ospf_lsa
*lsa
);
100 static int ospf_ext_pref_lsa_update(struct ospf_lsa
*lsa
);
101 static void del_ext_info(void *val
);
104 * Extended Link/Prefix initialization
108 * @return - 0 if OK, <> 0 otherwise
110 int ospf_ext_init(void)
114 memset(&OspfEXT
, 0, sizeof(struct ospf_ext_lp
));
115 OspfEXT
.enabled
= false;
116 /* Only Area flooding is supported yet */
117 OspfEXT
.scope
= OSPF_OPAQUE_AREA_LSA
;
118 /* Initialize interface list */
119 OspfEXT
.iflist
= list_new();
120 OspfEXT
.iflist
->del
= del_ext_info
;
122 zlog_info("EXT (%s): Register Extended Link Opaque LSA", __func__
);
123 rc
= ospf_register_opaque_functab(
124 OSPF_OPAQUE_AREA_LSA
, OPAQUE_TYPE_EXTENDED_LINK_LSA
,
125 ospf_ext_link_new_if
, /* new if */
126 ospf_ext_link_del_if
, /* del if */
127 ospf_ext_ism_change
, /* ism change */
128 ospf_ext_link_nsm_change
, /* nsm change */
129 NULL
, /* Write router config. */
130 NULL
, /* Write interface conf. */
131 NULL
, /* Write debug config. */
132 ospf_ext_link_show_info
, /* Show LSA info */
133 ospf_ext_link_lsa_originate
, /* Originate LSA */
134 ospf_ext_link_lsa_refresh
, /* Refresh LSA */
135 ospf_ext_link_lsa_update
, /* new_lsa_hook */
136 NULL
); /* del_lsa_hook */
139 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
140 "EXT (%s): Failed to register Extended Link LSA",
145 zlog_info("EXT (%s): Register Extended Prefix Opaque LSA", __func__
);
146 rc
= ospf_register_opaque_functab(
147 OspfEXT
.scope
, OPAQUE_TYPE_EXTENDED_PREFIX_LSA
,
148 NULL
, /* new if handle by link */
149 NULL
, /* del if handle by link */
150 NULL
, /* ism change */
151 NULL
, /* nsm change */
152 ospf_sr_config_write_router
, /* Write router config. */
153 NULL
, /* Write interface conf. */
154 NULL
, /* Write debug config. */
155 ospf_ext_pref_show_info
, /* Show LSA info */
156 ospf_ext_pref_lsa_originate
, /* Originate LSA */
157 ospf_ext_pref_lsa_refresh
, /* Refresh LSA */
158 ospf_ext_pref_lsa_update
, /* new_lsa_hook */
159 NULL
); /* del_lsa_hook */
161 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
162 "EXT (%s): Failed to register Extended Prefix LSA",
171 * Extended Link/Prefix termination function
176 void ospf_ext_term(void)
179 if ((OspfEXT
.scope
== OSPF_OPAQUE_AREA_LSA
)
180 || (OspfEXT
.scope
== OSPF_OPAQUE_AS_LSA
))
181 ospf_delete_opaque_functab(OspfEXT
.scope
,
182 OPAQUE_TYPE_EXTENDED_PREFIX_LSA
);
184 ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA
,
185 OPAQUE_TYPE_EXTENDED_LINK_LSA
);
187 list_delete(&OspfEXT
.iflist
);
189 OspfEXT
.enabled
= false;
195 * Extended Link/Prefix finish function
200 void ospf_ext_finish(void)
203 struct listnode
*node
;
204 struct ext_itf
*exti
;
206 /* Flush Router Info LSA */
207 for (ALL_LIST_ELEMENTS_RO(OspfEXT
.iflist
, node
, exti
))
208 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
))
209 ospf_ext_lsa_schedule(exti
, FLUSH_THIS_LSA
);
211 OspfEXT
.enabled
= false;
215 * ---------------------------------------------------------------------
216 * Followings are control functions for Extended Prefix/Link Opaque LSA
217 * parameters management.
218 * ---------------------------------------------------------------------
221 /* Functions to free memory space */
222 static void del_ext_info(void *val
)
224 XFREE(MTYPE_OSPF_EXT_PARAMS
, val
);
227 /* Increment instance value for Extended Prefix Opaque LSAs Opaque ID field */
228 static uint32_t get_ext_pref_instance_value(void)
230 static uint32_t seqno
= 0;
232 if (seqno
< MAX_LEGAL_EXT_INSTANCE_NUM
)
235 seqno
= 1; /* Avoid zero. */
240 /* Increment instance value for Extended Link Opaque LSAs Opaque ID field */
241 static uint32_t get_ext_link_instance_value(void)
243 static uint32_t seqno
= 0;
245 if (seqno
< MAX_LEGAL_EXT_INSTANCE_NUM
)
248 seqno
= 1; /* Avoid zero. */
253 /* Lookup Extended Prefix/Links by ifp from OspfEXT struct iflist */
254 static struct ext_itf
*lookup_ext_by_ifp(struct interface
*ifp
)
256 struct listnode
*node
, *nnode
;
257 struct ext_itf
*exti
;
259 for (ALL_LIST_ELEMENTS(OspfEXT
.iflist
, node
, nnode
, exti
))
260 if (exti
->ifp
== ifp
)
266 /* Lookup Extended Prefix/Links by LSA ID from OspfEXT struct iflist */
267 static struct ext_itf
*lookup_ext_by_instance(struct ospf_lsa
*lsa
)
269 struct listnode
*node
;
270 struct ext_itf
*exti
;
271 uint32_t key
= GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
));
272 uint8_t type
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
275 for (ALL_LIST_ELEMENTS_RO(OspfEXT
.iflist
, node
, exti
))
276 if ((exti
->instance
== key
) && (exti
->type
== type
))
283 * ----------------------------------------------------------------------
284 * The underlying subsection defines setters and unsetters to create and
285 * delete tlvs and subtlvs
286 * ----------------------------------------------------------------------
289 /* Extended Prefix TLV - RFC7684 section 2.1 */
290 static void set_ext_prefix(struct ext_itf
*exti
, uint8_t route_type
,
291 uint8_t flags
, struct prefix_ipv4 p
)
294 TLV_TYPE(exti
->prefix
) = htons(EXT_TLV_PREFIX
);
295 /* Warning: Size must be adjust depending of subTLV's */
296 TLV_LEN(exti
->prefix
) = htons(EXT_TLV_PREFIX_SIZE
);
297 exti
->prefix
.route_type
= route_type
;
298 exti
->prefix
.flags
= flags
;
299 /* Only Address Family Ipv4 (0) is defined in RFC 7684 */
301 exti
->prefix
.pref_length
= p
.prefixlen
;
302 exti
->prefix
.address
= p
.prefix
;
305 /* Extended Link TLV - RFC7684 section 3.1 */
306 static void set_ext_link(struct ext_itf
*exti
, uint8_t type
, struct in_addr id
,
310 TLV_TYPE(exti
->link
) = htons(EXT_TLV_LINK
);
311 /* Warning: Size must be adjust depending of subTLV's */
312 TLV_LEN(exti
->link
) = htons(EXT_TLV_LINK_SIZE
);
313 exti
->link
.link_type
= type
;
314 exti
->link
.link_id
= id
;
315 exti
->link
.link_data
= data
;
318 /* Prefix SID SubTLV - section 5 */
319 static void set_prefix_sid(struct ext_itf
*exti
, uint8_t algorithm
,
320 uint32_t value
, int value_type
, uint8_t flags
)
323 if ((algorithm
!= SR_ALGORITHM_SPF
)
324 && (algorithm
!= SR_ALGORITHM_STRICT_SPF
)) {
325 flog_err(EC_OSPF_INVALID_ALGORITHM
,
326 "EXT (%s): unrecognized algorithm, not SPF or S-SPF",
331 /* Update flags according to the type of value field: label or index */
332 if (value_type
== SID_LABEL
)
333 SET_FLAG(flags
, EXT_SUBTLV_PREFIX_SID_VFLG
);
335 /* set prefix sid subtlv for an extended prefix tlv */
336 TLV_TYPE(exti
->node_sid
) = htons(EXT_SUBTLV_PREFIX_SID
);
337 exti
->node_sid
.algorithm
= algorithm
;
338 exti
->node_sid
.flags
= flags
;
339 exti
->node_sid
.mtid
= 0; /* Multi-Topology is not supported */
341 /* Set Label or Index value */
342 if (value_type
== SID_LABEL
) {
343 TLV_LEN(exti
->node_sid
) =
344 htons(SID_LABEL_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE
));
345 exti
->node_sid
.value
= htonl(SET_LABEL(value
));
347 TLV_LEN(exti
->node_sid
) =
348 htons(SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE
));
349 exti
->node_sid
.value
= htonl(value
);
353 /* Adjacency SID SubTLV - section 6.1 */
354 static void set_adj_sid(struct ext_itf
*exti
, bool backup
, uint32_t value
,
360 /* Determine which ADJ_SID must be set: nominal or backup */
362 flags
= EXT_SUBTLV_LINK_ADJ_SID_BFLG
;
370 TLV_TYPE(exti
->adj_sid
[index
]) = htons(EXT_SUBTLV_ADJ_SID
);
372 /* Only Local ADJ-SID is supported for the moment */
373 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_LFLG
);
375 exti
->adj_sid
[index
].mtid
= 0; /* Multi-Topology is not supported */
377 /* Adjust Length, Flags and Value depending on the type of Label */
378 if (value_type
== SID_LABEL
) {
379 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
);
380 TLV_LEN(exti
->adj_sid
[index
]) =
381 htons(SID_LABEL_SIZE(EXT_SUBTLV_ADJ_SID_SIZE
));
382 exti
->adj_sid
[index
].value
= htonl(SET_LABEL(value
));
384 UNSET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
);
385 TLV_LEN(exti
->adj_sid
[index
]) =
386 htons(SID_INDEX_SIZE(EXT_SUBTLV_ADJ_SID_SIZE
));
387 exti
->adj_sid
[index
].value
= htonl(value
);
390 exti
->adj_sid
[index
].flags
= flags
; /* Set computed flags */
391 exti
->adj_sid
[index
].mtid
= 0; /* Multi-Topology is not supported */
392 exti
->adj_sid
[index
].weight
= 0; /* Load-Balancing is not supported */
395 /* LAN Adjacency SID SubTLV - section 6.2 */
396 static void set_lan_adj_sid(struct ext_itf
*exti
, bool backup
, uint32_t value
,
397 int value_type
, struct in_addr neighbor_id
)
403 /* Determine which ADJ_SID must be set: nominal or backup */
405 flags
= EXT_SUBTLV_LINK_ADJ_SID_BFLG
;
413 TLV_TYPE(exti
->lan_sid
[index
]) = htons(EXT_SUBTLV_LAN_ADJ_SID
);
415 /* Only Local ADJ-SID is supported for the moment */
416 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_LFLG
);
418 /* Adjust Length, Flags and Value depending on the type of Label */
419 if (value_type
== SID_LABEL
) {
420 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
);
421 TLV_LEN(exti
->lan_sid
[index
]) =
422 htons(SID_LABEL_SIZE(EXT_SUBTLV_PREFIX_RANGE_SIZE
));
423 exti
->lan_sid
[index
].value
= htonl(SET_LABEL(value
));
425 UNSET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
);
426 TLV_LEN(exti
->lan_sid
[index
]) =
427 htons(SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_RANGE_SIZE
));
428 exti
->lan_sid
[index
].value
= htonl(value
);
431 exti
->lan_sid
[index
].flags
= flags
; /* Set computed flags */
432 exti
->lan_sid
[index
].mtid
= 0; /* Multi-Topology is not supported */
433 exti
->lan_sid
[index
].weight
= 0; /* Load-Balancing is not supported */
434 exti
->lan_sid
[index
].neighbor_id
= neighbor_id
;
437 /* Experimental SubTLV from Cisco */
438 static void set_rmt_itf_addr(struct ext_itf
*exti
, struct in_addr rmtif
)
441 TLV_TYPE(exti
->rmt_itf_addr
) = htons(EXT_SUBTLV_RMT_ITF_ADDR
);
442 TLV_LEN(exti
->rmt_itf_addr
) = htons(sizeof(struct in_addr
));
443 exti
->rmt_itf_addr
.value
= rmtif
;
446 /* Delete Extended LSA */
447 static void ospf_extended_lsa_delete(struct ext_itf
*exti
)
450 /* Process only Active Extended Prefix/Link LSA */
451 if (!CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
))
454 osr_debug("EXT (%s): Disable %s%s%s-SID on interface %s", __func__
,
455 exti
->stype
== PREF_SID
? "Prefix" : "",
456 exti
->stype
== ADJ_SID
? "Adjacency" : "",
457 exti
->stype
== LAN_ADJ_SID
? "LAN-Adjacency" : "",
460 /* Flush LSA if already engaged */
461 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
)) {
462 ospf_ext_lsa_schedule(exti
, FLUSH_THIS_LSA
);
463 UNSET_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
);
466 /* De-activate this Extended Prefix/Link and remove corresponding
467 * Segment-Routing Prefix-SID or (LAN)-ADJ-SID */
468 exti
->flags
= EXT_LPFLG_LSA_INACTIVE
;
469 ospf_sr_ext_itf_delete(exti
);
473 * Update Extended prefix SID index for Loopback interface type
475 * @param ifname - Loopback interface name
476 * @param index - new value for the prefix SID of this interface
477 * @param p - prefix for this interface or NULL if Extended Prefix
480 * @return instance number if update is OK, 0 otherwise
482 uint32_t ospf_ext_schedule_prefix_index(struct interface
*ifp
, uint32_t index
,
483 struct prefix_ipv4
*p
, uint8_t flags
)
486 struct ext_itf
*exti
;
488 /* Find Extended Prefix interface */
489 exti
= lookup_ext_by_ifp(ifp
);
494 osr_debug("EXT (%s): Schedule new prefix %pFX with index %u "
495 "on interface %s", __func__
, p
, index
, ifp
->name
);
497 /* Set first Extended Prefix then the Prefix SID information */
498 set_ext_prefix(exti
, OSPF_PATH_INTRA_AREA
, EXT_TLV_PREF_NFLG
,
500 set_prefix_sid(exti
, SR_ALGORITHM_SPF
, index
, SID_INDEX
, flags
);
502 /* Try to Schedule LSA */
503 // SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
504 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
)) {
505 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
))
506 ospf_ext_pref_lsa_schedule(exti
,
509 ospf_ext_pref_lsa_schedule(
510 exti
, REORIGINATE_THIS_LSA
);
513 osr_debug("EXT (%s): Remove prefix for interface %s", __func__
,
516 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
)) {
517 ospf_ext_pref_lsa_schedule(exti
, FLUSH_THIS_LSA
);
518 exti
->flags
= EXT_LPFLG_LSA_INACTIVE
;
522 return SET_OPAQUE_LSID(exti
->type
, exti
->instance
);
526 * Used by Segment Routing to activate/deactivate Extended Link/Prefix flooding
528 * @param enable To activate or not Segment Routing Extended LSA flooding
532 void ospf_ext_update_sr(bool enable
)
534 struct listnode
*node
;
535 struct ext_itf
*exti
;
537 osr_debug("EXT (%s): %s Extended LSAs for Segment Routing ", __func__
,
538 enable
? "Enable" : "Disable");
541 OspfEXT
.enabled
= true;
543 /* Refresh LSAs if already engaged or originate */
544 for (ALL_LIST_ELEMENTS_RO(OspfEXT
.iflist
, node
, exti
)) {
545 /* Skip inactive Extended Link */
546 if (!CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
))
549 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
))
550 ospf_ext_lsa_schedule(exti
, REFRESH_THIS_LSA
);
552 ospf_ext_lsa_schedule(exti
,
553 REORIGINATE_THIS_LSA
);
556 /* Start by Removing Extended LSA */
557 for (ALL_LIST_ELEMENTS_RO(OspfEXT
.iflist
, node
, exti
))
558 ospf_extended_lsa_delete(exti
);
560 /* And then disable Extended Link/Prefix */
561 OspfEXT
.enabled
= false;
566 * -----------------------------------------------------------------------
567 * Followings are callback functions against generic Opaque-LSAs handling
568 * -----------------------------------------------------------------------
571 /* Add new Interface in Extended Interface List */
572 static int ospf_ext_link_new_if(struct interface
*ifp
)
577 if (lookup_ext_by_ifp(ifp
) != NULL
) {
578 rc
= 0; /* Do nothing here. */
582 new = XCALLOC(MTYPE_OSPF_EXT_PARAMS
, sizeof(struct ext_itf
));
584 /* initialize new information and link back the interface */
586 new->flags
= EXT_LPFLG_LSA_INACTIVE
;
588 listnode_add(OspfEXT
.iflist
, new);
594 /* Remove existing Interface from Extended Interface List */
595 static int ospf_ext_link_del_if(struct interface
*ifp
)
597 struct ext_itf
*exti
;
600 exti
= lookup_ext_by_ifp(ifp
);
602 /* Flush LSA and remove Adjacency SID */
603 ospf_extended_lsa_delete(exti
);
605 /* Dequeue listnode entry from the list. */
606 listnode_delete(OspfEXT
.iflist
, exti
);
608 XFREE(MTYPE_OSPF_EXT_PARAMS
, exti
);
612 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
613 "EXT (%s): interface %s is not found", __func__
,
614 ifp
? ifp
->name
: "-");
621 * Determine if an Interface belongs to an Extended Link Adjacency or
622 * Extended Prefix SID type and allocate new instance value accordingly
624 static void ospf_ext_ism_change(struct ospf_interface
*oi
, int old_status
)
626 struct ext_itf
*exti
;
628 /* Get interface information for Segment Routing */
629 exti
= lookup_ext_by_ifp(oi
->ifp
);
631 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
632 "EXT (%s): Cannot get Extended info. from OI(%s)",
633 __func__
, IF_NAME(oi
));
637 /* Reset Extended information if ospf interface goes Down */
638 if (oi
->state
== ISM_Down
) {
639 ospf_extended_lsa_delete(exti
);
641 exti
->flags
= EXT_LPFLG_LSA_INACTIVE
;
645 /* Determine if interface is related to a Prefix or an Adjacency SID */
646 if (oi
->type
== OSPF_IFTYPE_LOOPBACK
) {
647 exti
->stype
= PREF_SID
;
648 exti
->type
= OPAQUE_TYPE_EXTENDED_PREFIX_LSA
;
649 exti
->flags
= EXT_LPFLG_LSA_ACTIVE
;
650 exti
->instance
= get_ext_pref_instance_value();
651 exti
->area
= oi
->area
;
653 osr_debug("EXT (%s): Set Prefix SID to interface %s ",
654 __func__
, oi
->ifp
->name
);
656 /* Complete SRDB if the interface belongs to a Prefix */
658 ospf_sr_update_local_prefix(oi
->ifp
, oi
->address
);
660 /* Determine if interface is related to Adj. or LAN Adj. SID */
661 if (oi
->state
== ISM_DR
)
662 exti
->stype
= LAN_ADJ_SID
;
664 exti
->stype
= ADJ_SID
;
666 exti
->type
= OPAQUE_TYPE_EXTENDED_LINK_LSA
;
667 exti
->instance
= get_ext_link_instance_value();
668 exti
->area
= oi
->area
;
671 * Note: Adjacency SID information are completed when ospf
672 * adjacency become up see ospf_ext_link_nsm_change()
674 osr_debug("EXT (%s): Set %sAdjacency SID for interface %s ",
675 __func__
, exti
->stype
== ADJ_SID
? "" : "LAN-",
681 * Finish Extended Link configuration and flood corresponding LSA
682 * when OSPF adjacency on this link fire up
684 static void ospf_ext_link_nsm_change(struct ospf_neighbor
*nbr
, int old_status
)
686 struct ospf_interface
*oi
= nbr
->oi
;
687 struct ext_itf
*exti
;
690 /* Process Link only when neighbor old or new state is NSM Full */
691 if (nbr
->state
!= NSM_Full
&& old_status
!= NSM_Full
)
694 /* Get interface information for Segment Routing */
695 exti
= lookup_ext_by_ifp(oi
->ifp
);
697 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
698 "EXT (%s): Cannot get Extended info. from OI(%s)",
699 __func__
, IF_NAME(oi
));
703 /* Check that we have a valid area and ospf context */
704 if (oi
->area
== NULL
|| oi
->area
->ospf
== NULL
) {
705 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
706 "EXT (%s): Cannot refer to OSPF from OI(%s)",
707 __func__
, IF_NAME(oi
));
711 /* Remove Extended Link if Neighbor State goes Down or Deleted */
712 if (nbr
->state
== NSM_Down
|| nbr
->state
== NSM_Deleted
) {
713 ospf_extended_lsa_delete(exti
);
717 /* Keep Area information in combination with SR info. */
718 exti
->area
= oi
->area
;
720 /* Process only Adjacency/LAN SID */
721 if (exti
->stype
== PREF_SID
)
725 case ISM_PointToPoint
:
726 /* Segment ID is an Adjacency one */
727 exti
->stype
= ADJ_SID
;
729 /* Set Extended Link TLV with link_id == Nbr Router ID */
730 set_ext_link(exti
, OSPF_IFTYPE_POINTOPOINT
, nbr
->router_id
,
731 oi
->address
->u
.prefix4
);
733 /* Set Extended Link Adjacency SubTLVs, backup first */
734 label
= get_ext_link_label_value();
735 set_adj_sid(exti
, true, label
, SID_LABEL
);
736 label
= get_ext_link_label_value();
737 set_adj_sid(exti
, false, label
, SID_LABEL
);
738 /* And Remote Interface address */
739 set_rmt_itf_addr(exti
, nbr
->address
.u
.prefix4
);
744 /* Segment ID is a LAN Adjacency for the DR only */
745 exti
->stype
= LAN_ADJ_SID
;
747 /* Set Extended Link TLV with link_id == DR */
748 set_ext_link(exti
, OSPF_IFTYPE_BROADCAST
, DR(oi
),
749 oi
->address
->u
.prefix4
);
751 /* Set Extended Link Adjacency SubTLVs, backup first */
752 label
= get_ext_link_label_value();
753 set_lan_adj_sid(exti
, true, label
, SID_LABEL
, nbr
->router_id
);
754 label
= get_ext_link_label_value();
755 set_lan_adj_sid(exti
, false, label
, SID_LABEL
, nbr
->router_id
);
761 /* Segment ID is an Adjacency if not the DR */
762 exti
->stype
= ADJ_SID
;
764 /* Set Extended Link TLV with link_id == DR */
765 set_ext_link(exti
, OSPF_IFTYPE_BROADCAST
, DR(oi
),
766 oi
->address
->u
.prefix4
);
768 /* Set Extended Link Adjacency SubTLVs, backup first */
769 label
= get_ext_link_label_value();
770 set_adj_sid(exti
, true, label
, SID_LABEL
);
771 label
= get_ext_link_label_value();
772 set_adj_sid(exti
, false, label
, SID_LABEL
);
777 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
))
778 ospf_ext_link_lsa_schedule(exti
, FLUSH_THIS_LSA
);
779 exti
->flags
= EXT_LPFLG_LSA_INACTIVE
;
783 osr_debug("EXT (%s): Complete %sAdjacency SID for interface %s ",
784 __func__
, exti
->stype
== ADJ_SID
? "" : "LAN-",
787 /* flood this links params if everything is ok */
788 SET_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
);
789 if (OspfEXT
.enabled
) {
790 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
))
791 ospf_ext_link_lsa_schedule(exti
, REFRESH_THIS_LSA
);
793 ospf_ext_link_lsa_schedule(exti
, REORIGINATE_THIS_LSA
);
796 /* Finally install (LAN)Adjacency-SID in the SRDB */
797 ospf_sr_ext_itf_add(exti
);
800 /* Callbacks to handle Extended Link Segment Routing LSA information */
801 static int ospf_ext_link_lsa_update(struct ospf_lsa
*lsa
)
805 flog_warn(EC_OSPF_LSA_NULL
, "EXT (%s): Abort! LSA is NULL",
810 /* Process only Opaque LSA */
811 if ((lsa
->data
->type
!= OSPF_OPAQUE_AREA_LSA
)
812 && (lsa
->data
->type
!= OSPF_OPAQUE_AS_LSA
))
815 /* Process only Extended Link LSA */
816 if (GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
))
817 != OPAQUE_TYPE_EXTENDED_LINK_LSA
)
820 /* Check if it is not my LSA */
821 if (IS_LSA_SELF(lsa
))
824 /* Check if Extended is enable */
825 if (!OspfEXT
.enabled
)
828 /* Call Segment Routing LSA update or deletion */
829 if (!IS_LSA_MAXAGE(lsa
))
830 ospf_sr_ext_link_lsa_update(lsa
);
832 ospf_sr_ext_link_lsa_delete(lsa
);
837 /* Callbacks to handle Extended Prefix Segment Routing LSA information */
838 static int ospf_ext_pref_lsa_update(struct ospf_lsa
*lsa
)
843 flog_warn(EC_OSPF_LSA_NULL
, "EXT (%s): Abort! LSA is NULL",
848 /* Process only Opaque LSA */
849 if ((lsa
->data
->type
!= OSPF_OPAQUE_AREA_LSA
)
850 && (lsa
->data
->type
!= OSPF_OPAQUE_AS_LSA
))
853 /* Process only Extended Prefix LSA */
854 if (GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
))
855 != OPAQUE_TYPE_EXTENDED_PREFIX_LSA
)
858 /* Check if it is not my LSA */
859 if (IS_LSA_SELF(lsa
))
862 /* Check if Extended is enable */
863 if (!OspfEXT
.enabled
)
866 /* Call Segment Routing LSA update or deletion */
867 if (!IS_LSA_MAXAGE(lsa
))
868 ospf_sr_ext_prefix_lsa_update(lsa
);
870 ospf_sr_ext_prefix_lsa_delete(lsa
);
876 * -------------------------------------------------------
877 * Followings are OSPF protocol processing functions for
878 * Extended Prefix/Link Opaque LSA
879 * -------------------------------------------------------
882 static void build_tlv_header(struct stream
*s
, struct tlv_header
*tlvh
)
884 stream_put(s
, tlvh
, sizeof(struct tlv_header
));
887 static void build_tlv(struct stream
*s
, struct tlv_header
*tlvh
)
890 if ((tlvh
!= NULL
) && (ntohs(tlvh
->type
) != 0)) {
891 build_tlv_header(s
, tlvh
);
892 stream_put(s
, TLV_DATA(tlvh
), TLV_BODY_SIZE(tlvh
));
896 /* Build an Extended Prefix Opaque LSA body for extended prefix TLV */
897 static void ospf_ext_pref_lsa_body_set(struct stream
*s
, struct ext_itf
*exti
)
901 if ((exti
== NULL
) || (exti
->stype
!= PREF_SID
))
904 /* Adjust Extended Prefix TLV size */
905 TLV_LEN(exti
->prefix
) = htons(ntohs(TLV_LEN(exti
->node_sid
))
906 + EXT_TLV_PREFIX_SIZE
+ TLV_HDR_SIZE
);
908 /* Build LSA body for an Extended Prefix TLV */
909 build_tlv_header(s
, &exti
->prefix
.header
);
910 stream_put(s
, TLV_DATA(&exti
->prefix
.header
), EXT_TLV_PREFIX_SIZE
);
911 /* Then add Prefix SID SubTLV */
912 build_tlv(s
, &exti
->node_sid
.header
);
915 /* Build an Extended Link Opaque LSA body for extended link TLV */
916 static void ospf_ext_link_lsa_body_set(struct stream
*s
, struct ext_itf
*exti
)
922 || ((exti
->stype
!= ADJ_SID
) && (exti
->stype
!= LAN_ADJ_SID
)))
925 if (exti
->stype
== ADJ_SID
) {
926 /* Adjust Extended Link TLV size for Adj. SID */
927 size
= EXT_TLV_LINK_SIZE
+ 2 * EXT_SUBTLV_ADJ_SID_SIZE
929 if (ntohs(TLV_TYPE(exti
->rmt_itf_addr
)) != 0)
930 size
= size
+ EXT_SUBTLV_RMT_ITF_ADDR_SIZE
932 TLV_LEN(exti
->link
) = htons(size
);
934 /* Build LSA body for an Extended Link TLV with Adj. SID */
935 build_tlv_header(s
, &exti
->link
.header
);
936 stream_put(s
, TLV_DATA(&exti
->link
.header
), EXT_TLV_LINK_SIZE
);
937 /* then add Adjacency SubTLVs */
938 build_tlv(s
, &exti
->adj_sid
[1].header
);
939 build_tlv(s
, &exti
->adj_sid
[0].header
);
941 /* Add Cisco experimental SubTLV if interface is PtoP */
942 if (ntohs(TLV_TYPE(exti
->rmt_itf_addr
)) != 0)
943 build_tlv(s
, &exti
->rmt_itf_addr
.header
);
945 /* Adjust Extended Link TLV size for LAN SID */
946 size
= EXT_TLV_LINK_SIZE
947 + 2 * (EXT_SUBTLV_LAN_ADJ_SID_SIZE
+ TLV_HDR_SIZE
);
948 TLV_LEN(exti
->link
) = htons(size
);
950 /* Build LSA body for an Extended Link TLV with LAN SID */
951 build_tlv_header(s
, &exti
->link
.header
);
952 stream_put(s
, TLV_DATA(&exti
->link
.header
), EXT_TLV_LINK_SIZE
);
953 /* then add LAN-Adjacency SubTLVs */
954 build_tlv(s
, &exti
->lan_sid
[1].header
);
955 build_tlv(s
, &exti
->lan_sid
[0].header
);
959 /* Create new Extended Prefix opaque-LSA for every extended prefix */
960 static struct ospf_lsa
*ospf_ext_pref_lsa_new(struct ospf_area
*area
,
961 struct ext_itf
*exti
)
964 struct lsa_header
*lsah
;
965 struct ospf_lsa
*new = NULL
;
967 uint8_t options
, lsa_type
;
968 struct in_addr lsa_id
;
969 struct in_addr router_id
;
977 /* Create a stream for LSA. */
978 s
= stream_new(OSPF_MAX_LSA_SIZE
);
980 /* Prepare LSA Header */
981 lsah
= (struct lsa_header
*)STREAM_DATA(s
);
983 lsa_type
= OspfEXT
.scope
;
986 * LSA ID is a variable number identifying different instances of
987 * Extended Prefix Opaque LSA from the same router see RFC 7684
989 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA
, exti
->instance
);
990 lsa_id
.s_addr
= htonl(tmp
);
992 options
= OSPF_OPTION_O
; /* Don't forget this :-) */
994 /* Fix Options and Router ID depending of the flooding scope */
995 if ((OspfEXT
.scope
== OSPF_OPAQUE_AS_LSA
) || (area
== NULL
)) {
996 options
= OSPF_OPTION_E
;
997 top
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
998 router_id
.s_addr
= top
? top
->router_id
.s_addr
: 0;
1000 options
|= LSA_OPTIONS_GET(area
); /* Get area default option */
1001 options
|= LSA_OPTIONS_NSSA_GET(area
);
1002 router_id
= area
->ospf
->router_id
;
1005 /* Set opaque-LSA header fields. */
1006 lsa_header_set(s
, options
, lsa_type
, lsa_id
, router_id
);
1009 "EXT (%s): LSA[Type%u:%pI4]: Create an Opaque-LSA Extended "
1010 "Prefix Opaque LSA instance",
1011 __func__
, lsa_type
, &lsa_id
);
1013 /* Set opaque-LSA body fields. */
1014 ospf_ext_pref_lsa_body_set(s
, exti
);
1017 length
= stream_get_endp(s
);
1018 lsah
->length
= htons(length
);
1020 /* Now, create an OSPF LSA instance. */
1021 new = ospf_lsa_new_and_data(length
);
1023 /* Segment Routing belongs only to default VRF */
1024 new->vrf_id
= VRF_DEFAULT
;
1026 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
1027 memcpy(new->data
, lsah
, length
);
1033 /* Create new Extended Link opaque-LSA for every extended link TLV */
1034 static struct ospf_lsa
*ospf_ext_link_lsa_new(struct ospf_area
*area
,
1035 struct ext_itf
*exti
)
1038 struct lsa_header
*lsah
;
1039 struct ospf_lsa
*new = NULL
;
1040 uint8_t options
, lsa_type
;
1041 struct in_addr lsa_id
;
1049 /* Create a stream for LSA. */
1050 s
= stream_new(OSPF_MAX_LSA_SIZE
);
1051 lsah
= (struct lsa_header
*)STREAM_DATA(s
);
1053 options
= OSPF_OPTION_O
; /* Don't forget this :-) */
1054 options
|= LSA_OPTIONS_GET(area
); /* Get area default option */
1055 options
|= LSA_OPTIONS_NSSA_GET(area
);
1056 /* Extended Link Opaque LSA are only flooded within an area */
1057 lsa_type
= OSPF_OPAQUE_AREA_LSA
;
1060 * LSA ID is a variable number identifying different instances of
1061 * Extended Link Opaque LSA from the same router see RFC 7684
1063 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA
, exti
->instance
);
1064 lsa_id
.s_addr
= htonl(tmp
);
1067 "EXT (%s) LSA[Type%u:%pI4]: Create an Opaque-LSA Extended "
1068 "Link Opaque LSA instance",
1069 __func__
, lsa_type
, &lsa_id
);
1071 /* Set opaque-LSA header fields. */
1072 lsa_header_set(s
, options
, lsa_type
, lsa_id
, area
->ospf
->router_id
);
1074 /* Set opaque-LSA body fields. */
1075 ospf_ext_link_lsa_body_set(s
, exti
);
1078 length
= stream_get_endp(s
);
1079 lsah
->length
= htons(length
);
1081 /* Now, create an OSPF LSA instance. */
1082 new = ospf_lsa_new_and_data(length
);
1084 /* Segment Routing belongs only to default VRF */
1085 new->vrf_id
= VRF_DEFAULT
;
1087 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
1088 memcpy(new->data
, lsah
, length
);
1095 * Process the origination of an Extended Prefix Opaque LSA
1096 * for every extended prefix TLV
1098 static int ospf_ext_pref_lsa_originate1(struct ospf_area
*area
,
1099 struct ext_itf
*exti
)
1101 struct ospf_lsa
*new;
1105 /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
1106 new = ospf_ext_pref_lsa_new(area
, exti
);
1108 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1109 "EXT (%s): ospf_ext_pref_lsa_new() error", __func__
);
1113 /* Install this LSA into LSDB. */
1114 if (ospf_lsa_install(area
->ospf
, NULL
/*oi */, new) == NULL
) {
1115 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1116 "EXT (%s): ospf_lsa_install() error", __func__
);
1117 ospf_lsa_unlock(&new);
1121 /* Now this Extended Prefix Opaque LSA info parameter entry has
1124 SET_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
);
1126 /* Update new LSA origination count. */
1127 area
->ospf
->lsa_originate_count
++;
1129 /* Flood new LSA through area. */
1130 ospf_flood_through_area(area
, NULL
/*nbr */, new);
1133 "EXT (%s): LSA[Type%u:%pI4]: Originate Opaque-LSA"
1134 "Extended Prefix Opaque LSA: Area(%pI4), Link(%s)",
1135 __func__
, new->data
->type
, &new->data
->id
,
1136 &area
->area_id
, exti
->ifp
->name
);
1137 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
1138 ospf_lsa_header_dump(new->data
);
1146 * Process the origination of an Extended Link Opaque LSA
1147 * for every extended link TLV
1149 static int ospf_ext_link_lsa_originate1(struct ospf_area
*area
,
1150 struct ext_itf
*exti
)
1152 struct ospf_lsa
*new;
1155 /* Create new Opaque-LSA/Extended Link Opaque LSA instance. */
1156 new = ospf_ext_link_lsa_new(area
, exti
);
1158 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1159 "EXT (%s): ospf_ext_link_lsa_new() error", __func__
);
1163 /* Install this LSA into LSDB. */
1164 if (ospf_lsa_install(area
->ospf
, NULL
/*oi */, new) == NULL
) {
1165 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1166 "EXT (%s): ospf_lsa_install() error", __func__
);
1167 ospf_lsa_unlock(&new);
1171 /* Now this link-parameter entry has associated LSA. */
1172 SET_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
);
1174 /* Update new LSA origination count. */
1175 area
->ospf
->lsa_originate_count
++;
1177 /* Flood new LSA through area. */
1178 ospf_flood_through_area(area
, NULL
/*nbr */, new);
1181 "EXT (%s): LSA[Type%u:%pI4]: Originate Opaque-LSA "
1182 "Extended Link Opaque LSA: Area(%pI4), Link(%s)",
1183 __func__
, new->data
->type
, &new->data
->id
,
1184 &area
->area_id
, exti
->ifp
->name
);
1185 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
1186 ospf_lsa_header_dump(new->data
);
1193 /* Trigger the origination of Extended Prefix Opaque LSAs */
1194 static int ospf_ext_pref_lsa_originate(void *arg
)
1196 struct ospf_area
*area
= (struct ospf_area
*)arg
;
1197 struct listnode
*node
;
1198 struct ext_itf
*exti
;
1201 if (!OspfEXT
.enabled
) {
1203 "EXT (%s): Segment Routing functionality is Disabled now",
1205 rc
= 0; /* This is not an error case. */
1208 osr_debug("EXT (%s): Start Originate Prefix LSA for area %pI4",
1209 __func__
, &area
->area_id
);
1211 /* Check if Extended Prefix Opaque LSA is already engaged */
1212 for (ALL_LIST_ELEMENTS_RO(OspfEXT
.iflist
, node
, exti
)) {
1214 /* Process only Prefix SID */
1215 if (exti
->stype
!= PREF_SID
)
1218 /* Process only Extended Prefix with valid Area ID */
1219 if ((exti
->area
== NULL
)
1220 || (!IPV4_ADDR_SAME(&exti
->area
->area_id
, &area
->area_id
)))
1223 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
)) {
1224 if (CHECK_FLAG(exti
->flags
,
1225 EXT_LPFLG_LSA_FORCED_REFRESH
)) {
1227 EC_OSPF_EXT_LSA_UNEXPECTED
,
1228 "EXT (%s): Refresh instead of Originate",
1230 UNSET_FLAG(exti
->flags
,
1231 EXT_LPFLG_LSA_FORCED_REFRESH
);
1232 ospf_ext_pref_lsa_schedule(exti
,
1238 /* Ok, let's try to originate an LSA */
1240 "EXT (%s): Let's finally re-originate the LSA 7.0.0.%u "
1241 "for Itf %s", __func__
, exti
->instance
,
1242 exti
->ifp
? exti
->ifp
->name
: "");
1243 ospf_ext_pref_lsa_originate1(area
, exti
);
1250 /* Trigger the origination of Extended Link Opaque LSAs */
1251 static int ospf_ext_link_lsa_originate(void *arg
)
1253 struct ospf_area
*area
= (struct ospf_area
*)arg
;
1254 struct listnode
*node
;
1255 struct ext_itf
*exti
;
1258 if (!OspfEXT
.enabled
) {
1260 "EXT (%s): Segment Routing functionality is Disabled now",
1262 rc
= 0; /* This is not an error case. */
1266 /* Check if Extended Prefix Opaque LSA is already engaged */
1267 for (ALL_LIST_ELEMENTS_RO(OspfEXT
.iflist
, node
, exti
)) {
1268 /* Process only Adjacency or LAN SID */
1269 if (exti
->stype
== PREF_SID
)
1272 /* Skip Inactive Extended Link */
1273 if (!CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
))
1276 /* Process only Extended Link with valid Area ID */
1277 if ((exti
->area
== NULL
)
1278 || (!IPV4_ADDR_SAME(&exti
->area
->area_id
, &area
->area_id
)))
1281 /* Skip Extended Link which are not Active */
1282 if (!CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
))
1285 /* Check if LSA not already engaged */
1286 if (CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
)) {
1287 if (CHECK_FLAG(exti
->flags
,
1288 EXT_LPFLG_LSA_FORCED_REFRESH
)) {
1290 EC_OSPF_EXT_LSA_UNEXPECTED
,
1291 "EXT (%s): Refresh instead of Originate",
1293 UNSET_FLAG(exti
->flags
,
1294 EXT_LPFLG_LSA_FORCED_REFRESH
);
1295 ospf_ext_link_lsa_schedule(exti
,
1301 /* Ok, let's try to originate an LSA */
1303 "EXT (%s): Let's finally reoriginate the LSA 8.0.0.%u "
1304 "for Itf %s through the Area %pI4", __func__
,
1305 exti
->instance
, exti
->ifp
? exti
->ifp
->name
: "-",
1307 ospf_ext_link_lsa_originate1(area
, exti
);
1314 /* Refresh an Extended Prefix Opaque LSA */
1315 static struct ospf_lsa
*ospf_ext_pref_lsa_refresh(struct ospf_lsa
*lsa
)
1317 struct ospf_lsa
*new = NULL
;
1318 struct ospf_area
*area
= lsa
->area
;
1320 struct ext_itf
*exti
;
1322 if (!OspfEXT
.enabled
) {
1324 * This LSA must have flushed before due to Extended Prefix
1325 * Opaque LSA status change.
1326 * It seems a slip among routers in the routing domain.
1329 "EXT (%s): Segment Routing functionality is Disabled",
1331 /* Flush it anyway. */
1332 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1335 /* Lookup this lsa corresponding Extended parameters */
1336 exti
= lookup_ext_by_instance(lsa
);
1338 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1339 "EXT (%s): Invalid parameter LSA ID", __func__
);
1340 /* Flush it anyway. */
1341 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1344 /* Check if Interface was not disable in the interval */
1345 if ((exti
!= NULL
) && !CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
)) {
1346 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1347 "EXT (%s): Interface was Disabled: Flush it!",
1349 /* Flush it anyway. */
1350 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1353 /* If the lsa's age reached to MaxAge, start flushing procedure. */
1354 if (IS_LSA_MAXAGE(lsa
)) {
1356 UNSET_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
);
1357 ospf_opaque_lsa_flush_schedule(lsa
);
1361 /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
1362 new = ospf_ext_pref_lsa_new(area
, exti
);
1365 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1366 "EXT (%s): ospf_ext_pref_lsa_new() error", __func__
);
1369 new->data
->ls_seqnum
= lsa_seqnum_increment(lsa
);
1372 * Install this LSA into LSDB
1373 * Given "lsa" will be freed in the next function
1374 * As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use
1375 * ospf_lookup() to get ospf instance
1380 top
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1382 if (ospf_lsa_install(top
, NULL
/*oi */, new) == NULL
) {
1383 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1384 "EXT (%s): ospf_lsa_install() error", __func__
);
1385 ospf_lsa_unlock(&new);
1389 /* Flood updated LSA through the Prefix Area according to the RFC7684 */
1390 ospf_flood_through_area(area
, NULL
/*nbr */, new);
1392 /* Debug logging. */
1393 osr_debug("EXT (%s): LSA[Type%u:%pI4] Refresh Extended Prefix LSA",
1394 __func__
, new->data
->type
, &new->data
->id
);
1395 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
1396 ospf_lsa_header_dump(new->data
);
1402 /* Refresh an Extended Link Opaque LSA */
1403 static struct ospf_lsa
*ospf_ext_link_lsa_refresh(struct ospf_lsa
*lsa
)
1405 struct ext_itf
*exti
;
1406 struct ospf_area
*area
= lsa
->area
;
1407 struct ospf
*top
= area
->ospf
;
1408 struct ospf_lsa
*new = NULL
;
1410 if (!OspfEXT
.enabled
) {
1412 * This LSA must have flushed before due to OSPF-SR status
1413 * change. It seems a slip among routers in the routing domain.
1415 zlog_info("EXT (%s): Segment Routing functionality is Disabled",
1417 /* Flush it anyway. */
1418 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1421 /* Lookup this LSA corresponding Extended parameters */
1422 exti
= lookup_ext_by_instance(lsa
);
1424 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1425 "EXT (%s): Invalid parameter LSA ID", __func__
);
1426 /* Flush it anyway. */
1427 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1430 /* Check if Interface was not disable in the interval */
1431 if ((exti
!= NULL
) && !CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
)) {
1432 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1433 "EXT (%s): Interface was Disabled: Flush it!",
1435 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1438 /* If the lsa's age reached to MaxAge, start flushing procedure */
1439 if (IS_LSA_MAXAGE(lsa
)) {
1441 UNSET_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
);
1442 ospf_opaque_lsa_flush_schedule(lsa
);
1446 /* Create new Opaque-LSA/Extended Link instance */
1447 new = ospf_ext_link_lsa_new(area
, exti
);
1449 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1450 "EXT (%s): Error creating new LSA", __func__
);
1453 new->data
->ls_seqnum
= lsa_seqnum_increment(lsa
);
1455 /* Install this LSA into LSDB. */
1456 /* Given "lsa" will be freed in the next function */
1457 if (ospf_lsa_install(top
, NULL
/*oi */, new) == NULL
) {
1458 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1459 "EXT (%s): Error installing new LSA", __func__
);
1460 ospf_lsa_unlock(&new);
1464 /* Flood updated LSA through the link Area according to the RFC7684 */
1465 ospf_flood_through_area(area
, NULL
/*nbr */, new);
1467 /* Debug logging. */
1468 osr_debug("EXT (%s): LSA[Type%u:%pI4]: Refresh Extended Link LSA",
1469 __func__
, new->data
->type
, &new->data
->id
);
1470 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
1471 ospf_lsa_header_dump(new->data
);
1476 /* Schedule Extended Prefix Opaque LSA origination/refreshment/flushing */
1477 static void ospf_ext_pref_lsa_schedule(struct ext_itf
*exti
,
1478 enum lsa_opcode opcode
)
1480 struct ospf_lsa lsa
;
1481 struct lsa_header lsah
;
1485 memset(&lsa
, 0, sizeof(lsa
));
1486 memset(&lsah
, 0, sizeof(lsah
));
1492 /* Check if the corresponding link is ready to be flooded */
1493 if (!(CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
)))
1496 osr_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__
,
1497 opcode
== REORIGINATE_THIS_LSA
? "Re-Originate" : "",
1498 opcode
== REFRESH_THIS_LSA
? "Refresh" : "",
1499 opcode
== FLUSH_THIS_LSA
? "Flush" : "",
1500 exti
->ifp
? exti
->ifp
->name
: "-");
1503 if (exti
->area
== NULL
) {
1505 "EXT (%s): Area is not yet set. Try to use Backbone Area",
1508 top
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1509 struct in_addr backbone
= {.s_addr
= INADDR_ANY
};
1510 exti
->area
= ospf_area_lookup_by_area_id(top
, backbone
);
1511 if (exti
->area
== NULL
) {
1512 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1513 "EXT (%s): Unable to set Area", __func__
);
1517 /* Set LSA header information */
1518 lsa
.area
= exti
->area
;
1520 lsah
.type
= OSPF_OPAQUE_AREA_LSA
;
1521 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA
, exti
->instance
);
1522 lsah
.id
.s_addr
= htonl(tmp
);
1525 case REORIGINATE_THIS_LSA
:
1526 ospf_opaque_lsa_reoriginate_schedule(
1527 (void *)exti
->area
, OSPF_OPAQUE_AREA_LSA
,
1528 OPAQUE_TYPE_EXTENDED_PREFIX_LSA
);
1530 case REFRESH_THIS_LSA
:
1531 ospf_opaque_lsa_refresh_schedule(&lsa
);
1533 case FLUSH_THIS_LSA
:
1534 UNSET_FLAG(exti
->flags
, EXT_LPFLG_LSA_ENGAGED
);
1535 ospf_opaque_lsa_flush_schedule(&lsa
);
1540 /* Schedule Extended Link Opaque LSA origination/refreshment/flushing */
1541 static void ospf_ext_link_lsa_schedule(struct ext_itf
*exti
,
1542 enum lsa_opcode opcode
)
1544 struct ospf_lsa lsa
;
1545 struct lsa_header lsah
;
1549 memset(&lsa
, 0, sizeof(lsa
));
1550 memset(&lsah
, 0, sizeof(lsah
));
1556 /* Check if the corresponding link is ready to be flooded */
1557 if (!(CHECK_FLAG(exti
->flags
, EXT_LPFLG_LSA_ACTIVE
)))
1560 osr_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__
,
1561 opcode
== REORIGINATE_THIS_LSA
? "Re-Originate" : "",
1562 opcode
== REFRESH_THIS_LSA
? "Refresh" : "",
1563 opcode
== FLUSH_THIS_LSA
? "Flush" : "",
1564 exti
->ifp
? exti
->ifp
->name
: "-");
1567 if (exti
->area
== NULL
) {
1569 "EXT (%s): Area is not yet set. Try to use Backbone Area",
1572 top
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1573 struct in_addr backbone
= {.s_addr
= INADDR_ANY
};
1574 exti
->area
= ospf_area_lookup_by_area_id(top
, backbone
);
1575 if (exti
->area
== NULL
) {
1576 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED
,
1577 "EXT (%s): Unable to set Area", __func__
);
1581 /* Set LSA header information */
1582 lsa
.area
= exti
->area
;
1584 lsah
.type
= OSPF_OPAQUE_AREA_LSA
;
1585 tmp
= SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA
, exti
->instance
);
1586 lsah
.id
.s_addr
= htonl(tmp
);
1589 case REORIGINATE_THIS_LSA
:
1590 ospf_opaque_lsa_reoriginate_schedule(
1591 (void *)exti
->area
, OSPF_OPAQUE_AREA_LSA
,
1592 OPAQUE_TYPE_EXTENDED_LINK_LSA
);
1594 case REFRESH_THIS_LSA
:
1595 ospf_opaque_lsa_refresh_schedule(&lsa
);
1597 case FLUSH_THIS_LSA
:
1598 ospf_opaque_lsa_flush_schedule(&lsa
);
1603 /* Schedule Extended Link or Prefix depending of the Type of LSA */
1604 static void ospf_ext_lsa_schedule(struct ext_itf
*exti
, enum lsa_opcode op
)
1607 if (exti
->stype
== PREF_SID
)
1608 ospf_ext_pref_lsa_schedule(exti
, op
);
1610 ospf_ext_link_lsa_schedule(exti
, op
);
1614 * ------------------------------------
1615 * Followings are vty show functions.
1616 * ------------------------------------
1619 /* Cisco experimental SubTLV */
1620 static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty
*vty
,
1621 struct tlv_header
*tlvh
)
1623 struct ext_subtlv_rmt_itf_addr
*top
;
1625 top
= (struct ext_subtlv_rmt_itf_addr
*)tlvh
;
1628 " Remote Interface Address Sub-TLV: Length %u\n "
1630 ntohs(top
->header
.length
), inet_ntoa(top
->value
));
1632 return TLV_SIZE(tlvh
);
1635 /* Adjacency SID SubTLV */
1636 static uint16_t show_vty_ext_link_adj_sid(struct vty
*vty
,
1637 struct tlv_header
*tlvh
)
1639 struct ext_subtlv_adj_sid
*top
= (struct ext_subtlv_adj_sid
*)tlvh
;
1642 " Adj-SID Sub-TLV: Length %u\n\tFlags: "
1643 "0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
1644 ntohs(top
->header
.length
), top
->flags
, top
->mtid
, top
->weight
,
1645 CHECK_FLAG(top
->flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
) ? "Label"
1647 CHECK_FLAG(top
->flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1648 ? GET_LABEL(ntohl(top
->value
))
1649 : ntohl(top
->value
));
1651 return TLV_SIZE(tlvh
);
1654 /* LAN Adjacency SubTLV */
1655 static uint16_t show_vty_ext_link_lan_adj_sid(struct vty
*vty
,
1656 struct tlv_header
*tlvh
)
1658 struct ext_subtlv_lan_adj_sid
*top
=
1659 (struct ext_subtlv_lan_adj_sid
*)tlvh
;
1662 " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: "
1663 "0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: "
1665 ntohs(top
->header
.length
), top
->flags
, top
->mtid
, top
->weight
,
1666 inet_ntoa(top
->neighbor_id
),
1667 CHECK_FLAG(top
->flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
) ? "Label"
1669 CHECK_FLAG(top
->flags
, EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1670 ? GET_LABEL(ntohl(top
->value
))
1671 : ntohl(top
->value
));
1673 return TLV_SIZE(tlvh
);
1676 static uint16_t show_vty_unknown_tlv(struct vty
*vty
, struct tlv_header
*tlvh
)
1678 vty_out(vty
, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
1679 ntohs(tlvh
->type
), ntohs(tlvh
->length
));
1681 return TLV_SIZE(tlvh
);
1684 /* Extended Link Sub TLVs */
1685 static uint16_t show_vty_link_info(struct vty
*vty
, struct tlv_header
*ext
)
1687 struct ext_tlv_link
*top
= (struct ext_tlv_link
*)ext
;
1688 struct tlv_header
*tlvh
;
1689 uint16_t length
= ntohs(top
->header
.length
) - 3 * sizeof(uint32_t);
1693 " Extended Link TLV: Length %u\n Link Type: 0x%x\n"
1695 ntohs(top
->header
.length
), top
->link_type
,
1696 inet_ntoa(top
->link_id
));
1697 vty_out(vty
, " Link data: %s\n", inet_ntoa(top
->link_data
));
1699 tlvh
= (struct tlv_header
*)((char *)(ext
) + TLV_HDR_SIZE
1700 + EXT_TLV_LINK_SIZE
);
1701 for (; sum
< length
; tlvh
= TLV_HDR_NEXT(tlvh
)) {
1702 switch (ntohs(tlvh
->type
)) {
1703 case EXT_SUBTLV_ADJ_SID
:
1704 sum
+= show_vty_ext_link_adj_sid(vty
, tlvh
);
1706 case EXT_SUBTLV_LAN_ADJ_SID
:
1707 sum
+= show_vty_ext_link_lan_adj_sid(vty
, tlvh
);
1709 case EXT_SUBTLV_RMT_ITF_ADDR
:
1710 sum
+= show_vty_ext_link_rmt_itf_addr(vty
, tlvh
);
1713 sum
+= show_vty_unknown_tlv(vty
, tlvh
);
1718 return sum
+ sizeof(struct ext_tlv_link
);
1721 /* Extended Link TLVs */
1722 static void ospf_ext_link_show_info(struct vty
*vty
, struct ospf_lsa
*lsa
)
1724 struct lsa_header
*lsah
= lsa
->data
;
1725 struct tlv_header
*tlvh
;
1726 uint16_t length
= 0, sum
= 0;
1728 /* Initialize TLV browsing */
1729 length
= ntohs(lsah
->length
) - OSPF_LSA_HEADER_SIZE
;
1731 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
;
1732 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1733 switch (ntohs(tlvh
->type
)) {
1735 sum
+= show_vty_link_info(vty
, tlvh
);
1738 sum
+= show_vty_unknown_tlv(vty
, tlvh
);
1744 /* Prefix SID SubTLV */
1745 static uint16_t show_vty_ext_pref_pref_sid(struct vty
*vty
,
1746 struct tlv_header
*tlvh
)
1748 struct ext_subtlv_prefix_sid
*top
=
1749 (struct ext_subtlv_prefix_sid
*)tlvh
;
1752 " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: "
1753 "%u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
1754 ntohs(top
->header
.length
), top
->algorithm
, top
->flags
,
1756 CHECK_FLAG(top
->flags
, EXT_SUBTLV_PREFIX_SID_VFLG
) ? "Label"
1758 CHECK_FLAG(top
->flags
, EXT_SUBTLV_PREFIX_SID_VFLG
)
1759 ? GET_LABEL(ntohl(top
->value
))
1760 : ntohl(top
->value
));
1762 return TLV_SIZE(tlvh
);
1765 /* Extended Prefix SubTLVs */
1766 static uint16_t show_vty_pref_info(struct vty
*vty
, struct tlv_header
*ext
)
1768 struct ext_tlv_prefix
*top
= (struct ext_tlv_prefix
*)ext
;
1769 struct tlv_header
*tlvh
;
1770 uint16_t length
= ntohs(top
->header
.length
) - 2 * sizeof(uint32_t);
1774 " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
1775 "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %s/%u\n",
1776 ntohs(top
->header
.length
), top
->route_type
, top
->af
, top
->flags
,
1777 inet_ntoa(top
->address
), top
->pref_length
);
1779 tlvh
= (struct tlv_header
*)((char *)(ext
) + TLV_HDR_SIZE
1780 + EXT_TLV_PREFIX_SIZE
);
1781 for (; sum
< length
; tlvh
= TLV_HDR_NEXT(tlvh
)) {
1782 switch (ntohs(tlvh
->type
)) {
1783 case EXT_SUBTLV_PREFIX_SID
:
1784 sum
+= show_vty_ext_pref_pref_sid(vty
, tlvh
);
1787 sum
+= show_vty_unknown_tlv(vty
, tlvh
);
1792 return sum
+ sizeof(struct ext_tlv_prefix
);
1795 /* Extended Prefix TLVs */
1796 static void ospf_ext_pref_show_info(struct vty
*vty
, struct ospf_lsa
*lsa
)
1798 struct lsa_header
*lsah
= lsa
->data
;
1799 struct tlv_header
*tlvh
;
1800 uint16_t length
= 0, sum
= 0;
1802 /* Initialize TLV browsing */
1803 length
= ntohs(lsah
->length
) - OSPF_LSA_HEADER_SIZE
;
1805 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
;
1806 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1807 switch (ntohs(tlvh
->type
)) {
1808 case EXT_TLV_PREFIX
:
1809 sum
+= show_vty_pref_info(vty
, tlvh
);
1812 sum
+= show_vty_unknown_tlv(vty
, tlvh
);