1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*********************************************************************
3 * Copyright 2022 Hiroki Shirokura, LINE Corporation
4 * Copyright 2022 Masakazu Asama
5 * Copyright 2022 6WIND S.A.
7 * isis_flex_algo.c: IS-IS Flexible Algorithm
25 #include "isisd/isisd.h"
26 #include "isisd/isis_tlvs.h"
27 #include "isisd/isis_common.h"
28 #include "isisd/isis_mt.h"
29 #include "isisd/isis_misc.h"
30 #include "isisd/isis_adjacency.h"
31 #include "isisd/isis_circuit.h"
32 #include "isisd/isis_pdu.h"
33 #include "isisd/isis_lsp.h"
34 #include "isisd/isis_spf.h"
35 #include "isisd/isis_te.h"
36 #include "isisd/isis_sr.h"
37 #include "isisd/isis_spf_private.h"
38 #include "isisd/isis_flex_algo.h"
41 DEFINE_MTYPE_STATIC(ISISD
, FLEX_ALGO
, "ISIS Flex Algo");
43 void *isis_flex_algo_data_alloc(void *voidarg
)
45 struct isis_flex_algo_alloc_arg
*arg
= voidarg
;
46 struct isis_flex_algo_data
*data
;
48 data
= XCALLOC(MTYPE_FLEX_ALGO
, sizeof(struct isis_flex_algo_data
));
50 for (int tree
= SPFTREE_IPV4
; tree
< SPFTREE_COUNT
; tree
++) {
51 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
52 if (!(arg
->area
->is_type
& level
))
54 data
->spftree
[tree
][level
- 1] = isis_spftree_new(
55 arg
->area
, &arg
->area
->lspdb
[level
- 1],
56 arg
->area
->isis
->sysid
, level
, tree
,
57 SPF_TYPE_FORWARD
, 0, arg
->algorithm
);
64 void isis_flex_algo_data_free(void *voiddata
)
66 struct isis_flex_algo_data
*data
= voiddata
;
68 for (int tree
= SPFTREE_IPV4
; tree
< SPFTREE_COUNT
; tree
++)
69 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++)
70 if (data
->spftree
[tree
][level
- 1])
72 data
->spftree
[tree
][level
- 1]);
73 XFREE(MTYPE_FLEX_ALGO
, data
);
76 static struct isis_router_cap_fad
*
77 isis_flex_algo_definition_cmp(struct isis_router_cap_fad
*elected
,
78 struct isis_router_cap_fad
*fa
)
80 if (!elected
|| fa
->fad
.priority
> elected
->fad
.priority
||
81 (fa
->fad
.priority
== elected
->fad
.priority
&&
82 lsp_id_cmp(fa
->sysid
, elected
->sysid
) > 0))
89 * @brief Look up the flex-algo definition with the highest priority in the LSP
90 * Database (LSDB). If the value of priority is the same, the flex-algo
91 * definition with the highest sysid will be selected.
92 * @param algorithm flex-algo algorithm number
94 * @param local router capability Flex-Algo Definition (FAD) double pointer.
95 * - fad is NULL: use the local router capability FAD from LSDB for the
97 * - fad is not NULL and *fad is NULL: use no local router capability FAD for
99 * - fad and *fad are not NULL: uses the *fad local definition instead of the
100 * local definition from LSDB for the election.
101 * @return elected flex-algo-definition object if exist, else NULL
103 static struct isis_router_cap_fad
*
104 _isis_flex_algo_elected(int algorithm
, const struct isis_area
*area
,
105 struct isis_router_cap_fad
**fad
)
107 struct flex_algo
*flex_ago
;
108 const struct isis_lsp
*lsp
;
109 struct isis_router_cap_fad
*fa
, *elected
= NULL
;
111 if (!flex_algo_id_valid(algorithm
))
114 /* No elected FAD if the algorithm is not locally configured */
115 flex_ago
= flex_algo_lookup(area
->flex_algos
, algorithm
);
119 /* No elected FAD if no data-plane is enabled
120 * Currently, only Segment-Routing MPLS is supported.
121 * Segment-Routing SRv6 and IP will be configured in the future.
123 if (!CHECK_FLAG(flex_ago
->dataplanes
, FLEX_ALGO_SR_MPLS
))
127 * Perform FAD comparison. First, compare the priority, and if they are
128 * the same, compare the sys-id.
130 /* clang-format off */
131 frr_each_const(lspdb
, &area
->lspdb
[ISIS_LEVEL1
- 1], lsp
) {
132 /* clang-format on */
134 if (!lsp
->tlvs
|| !lsp
->tlvs
->router_cap
)
137 if (lsp
->own_lsp
&& fad
)
140 fa
= lsp
->tlvs
->router_cap
->fads
[algorithm
];
145 assert(algorithm
== fa
->fad
.algorithm
);
147 memcpy(fa
->sysid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
149 elected
= isis_flex_algo_definition_cmp(elected
, fa
);
153 elected
= isis_flex_algo_definition_cmp(elected
, *fad
);
158 struct isis_router_cap_fad
*isis_flex_algo_elected(int algorithm
,
159 const struct isis_area
*area
)
161 return _isis_flex_algo_elected(algorithm
, area
, NULL
);
165 * @brief Check the Flex-Algo Definition is supported by the current FRR version
167 * @return true if supported else false
169 bool isis_flex_algo_supported(struct flex_algo
*fad
)
171 if (fad
->calc_type
!= CALC_TYPE_SPF
)
173 if (fad
->metric_type
!= MT_IGP
)
177 if (fad
->exclude_srlg
)
179 if (fad
->unsupported_subtlv
)
186 * @brief Look for the elected Flex-Algo Definition and check that it is
187 * supported by the current FRR version
188 * @param algorithm flex-algo algorithm number
189 * @param area pointer
190 * @param local router capability Flex-Algo Definition (FAD) double pointer.
191 * @return elected flex-algo-definition object if exist and supported, else NULL
193 static struct isis_router_cap_fad
*
194 _isis_flex_algo_elected_supported(int algorithm
, const struct isis_area
*area
,
195 struct isis_router_cap_fad
**fad
)
197 struct isis_router_cap_fad
*elected_fad
;
199 elected_fad
= _isis_flex_algo_elected(algorithm
, area
, fad
);
203 if (isis_flex_algo_supported(&elected_fad
->fad
))
209 struct isis_router_cap_fad
*
210 isis_flex_algo_elected_supported(int algorithm
, const struct isis_area
*area
)
212 return _isis_flex_algo_elected_supported(algorithm
, area
, NULL
);
215 struct isis_router_cap_fad
*
216 isis_flex_algo_elected_supported_local_fad(int algorithm
,
217 const struct isis_area
*area
,
218 struct isis_router_cap_fad
**fad
)
220 return _isis_flex_algo_elected_supported(algorithm
, area
, fad
);
224 * Check LSP is participating specified SR Algorithm
226 * @param lsp IS-IS lsp
227 * @param algorithm SR Algorithm
228 * @return Return true if sr-algorithm tlv includes specified
229 * algorithm in router capability tlv
231 bool sr_algorithm_participated(const struct isis_lsp
*lsp
, uint8_t algorithm
)
233 if (!lsp
|| !lsp
->tlvs
|| !lsp
->tlvs
->router_cap
)
235 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
236 if (lsp
->tlvs
->router_cap
->algo
[i
] == algorithm
)
241 bool isis_flex_algo_constraint_drop(struct isis_spftree
*spftree
,
242 struct isis_lsp
*lsp
,
243 struct isis_extended_reach
*reach
)
246 struct isis_ext_subtlvs
*subtlvs
= reach
->subtlvs
;
247 struct isis_router_cap_fad
*fad
;
248 struct isis_asla_subtlvs
*asla
;
249 struct listnode
*node
;
250 uint32_t *link_admin_group
= NULL
;
251 uint32_t link_ext_admin_group_bitmap0
;
252 struct admin_group
*link_ext_admin_group
= NULL
;
254 fad
= isis_flex_algo_elected_supported(spftree
->algorithm
,
259 for (ALL_LIST_ELEMENTS_RO(subtlvs
->aslas
, node
, asla
)) {
260 if (!CHECK_FLAG(asla
->standard_apps
, ISIS_SABM_FLAG_X
))
263 if (IS_SUBTLV(subtlvs
, EXT_ADM_GRP
))
264 link_admin_group
= &subtlvs
->adm_group
;
266 if (IS_SUBTLV(subtlvs
, EXT_EXTEND_ADM_GRP
) &&
267 admin_group_nb_words(&subtlvs
->ext_admin_group
) !=
269 link_ext_admin_group
=
270 &subtlvs
->ext_admin_group
;
272 if (IS_SUBTLV(asla
, EXT_ADM_GRP
))
273 link_admin_group
= &asla
->admin_group
;
274 if (IS_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
) &&
275 admin_group_nb_words(&asla
->ext_admin_group
) != 0)
276 link_ext_admin_group
= &asla
->ext_admin_group
;
281 /* RFC7308 section 2.3.1
282 * A receiving node that notices that the AG differs from the first 32
283 * bits of the EAG SHOULD report this mismatch to the operator.
285 if (link_admin_group
&& link_ext_admin_group
) {
286 link_ext_admin_group_bitmap0
=
287 admin_group_get_offset(link_ext_admin_group
, 0);
288 if (*link_admin_group
!= link_ext_admin_group_bitmap0
)
290 "ISIS-SPF: LSP from %pPN neighbor %pPN. Admin-group 0x%08x differs from ext admin-group 0x%08x.",
291 lsp
->hdr
.lsp_id
, reach
->id
, *link_admin_group
,
292 link_ext_admin_group_bitmap0
);
298 if (!admin_group_zero(&fad
->fad
.admin_group_exclude_any
)) {
299 ret
= admin_group_match_any(&fad
->fad
.admin_group_exclude_any
,
301 link_ext_admin_group
);
309 if (!admin_group_zero(&fad
->fad
.admin_group_include_any
)) {
310 ret
= admin_group_match_any(&fad
->fad
.admin_group_include_any
,
312 link_ext_admin_group
);
320 if (!admin_group_zero(&fad
->fad
.admin_group_include_all
)) {
321 ret
= admin_group_match_all(&fad
->fad
.admin_group_include_all
,
323 link_ext_admin_group
);
331 #endif /* ifndef FABRICD */