]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
f8c06e2c OD |
2 | /* |
3 | * IS-IS Rout(e)ing protocol - isis_te.c | |
4 | * | |
68558b13 | 5 | * This is an implementation of RFC5305 & RFC 7810 |
f8c06e2c | 6 | * |
1b3f47d0 OD |
7 | * Author: Olivier Dugeon <olivier.dugeon@orange.com> |
8 | * | |
9 | * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com | |
f8c06e2c OD |
10 | */ |
11 | ||
12 | #include <zebra.h> | |
13 | #include <math.h> | |
14 | ||
15 | #include "linklist.h" | |
24a58196 | 16 | #include "frrevent.h" |
f8c06e2c OD |
17 | #include "vty.h" |
18 | #include "stream.h" | |
19 | #include "memory.h" | |
20 | #include "log.h" | |
21 | #include "prefix.h" | |
22 | #include "command.h" | |
23 | #include "hash.h" | |
24 | #include "if.h" | |
25 | #include "vrf.h" | |
26 | #include "checksum.h" | |
27 | #include "md5.h" | |
28 | #include "sockunion.h" | |
29 | #include "network.h" | |
af8ac8f9 | 30 | #include "sbuf.h" |
ed6189a9 OD |
31 | #include "link_state.h" |
32 | #include "lib/json.h" | |
f8c06e2c | 33 | |
f8c06e2c OD |
34 | #include "isisd/isis_constants.h" |
35 | #include "isisd/isis_common.h" | |
36 | #include "isisd/isis_flags.h" | |
37 | #include "isisd/isis_circuit.h" | |
1b3f47d0 | 38 | #include "isisd/isis_adjacency.h" |
f8c06e2c | 39 | #include "isisd/isisd.h" |
f8c06e2c OD |
40 | #include "isisd/isis_lsp.h" |
41 | #include "isisd/isis_pdu.h" | |
42 | #include "isisd/isis_dynhn.h" | |
43 | #include "isisd/isis_misc.h" | |
44 | #include "isisd/isis_csm.h" | |
45 | #include "isisd/isis_adjacency.h" | |
46 | #include "isisd/isis_spf.h" | |
ed6189a9 OD |
47 | #include "isisd/isis_tlvs.h" |
48 | #include "isisd/isis_mt.h" | |
f8c06e2c | 49 | #include "isisd/isis_te.h" |
1b3f47d0 | 50 | #include "isisd/isis_zebra.h" |
f8c06e2c | 51 | |
1fa63850 OD |
52 | DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters"); |
53 | ||
78d905be LS |
54 | static void isis_mpls_te_circuit_ip_update(struct isis_circuit *circuit); |
55 | ||
f8c06e2c | 56 | /*------------------------------------------------------------------------* |
78dfa0c7 | 57 | * Following are control functions for MPLS-TE parameters management. |
f8c06e2c OD |
58 | *------------------------------------------------------------------------*/ |
59 | ||
1fa63850 OD |
60 | /** |
61 | * Create MPLS Traffic Engineering structure which belongs to given area. | |
62 | * | |
63 | * @param area IS-IS Area | |
64 | */ | |
65 | void isis_mpls_te_create(struct isis_area *area) | |
66 | { | |
67 | struct listnode *node; | |
68 | struct isis_circuit *circuit; | |
69 | ||
70 | if (!area) | |
71 | return; | |
72 | ||
73 | if (area->mta == NULL) { | |
74 | ||
75 | struct mpls_te_area *new; | |
76 | ||
77 | zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering", | |
78 | area->area_tag); | |
79 | ||
80 | new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area)); | |
81 | ||
82 | /* Initialize MPLS_TE structure */ | |
83 | new->status = enable; | |
84 | new->level = 0; | |
85 | new->inter_as = off; | |
86 | new->interas_areaid.s_addr = 0; | |
87 | new->router_id.s_addr = 0; | |
88 | new->ted = ls_ted_new(1, "ISIS", 0); | |
89 | if (!new->ted) | |
90 | zlog_warn("Unable to create Link State Data Base"); | |
91 | ||
92 | area->mta = new; | |
93 | } else { | |
94 | area->mta->status = enable; | |
95 | } | |
96 | ||
97 | /* Initialize Link State Database */ | |
98 | if (area->mta->ted) | |
99 | isis_te_init_ted(area); | |
100 | ||
78d905be LS |
101 | /* Update Extended TLVs according to Interface link parameters |
102 | * and neighbor IP addresses | |
103 | */ | |
104 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { | |
1fa63850 | 105 | isis_link_params_update(circuit, circuit->interface); |
78d905be LS |
106 | isis_mpls_te_circuit_ip_update(circuit); |
107 | } | |
1fa63850 OD |
108 | } |
109 | ||
110 | /** | |
111 | * Disable MPLS Traffic Engineering structure which belongs to given area. | |
112 | * | |
113 | * @param area IS-IS Area | |
114 | */ | |
115 | void isis_mpls_te_disable(struct isis_area *area) | |
116 | { | |
117 | struct listnode *node; | |
118 | struct isis_circuit *circuit; | |
119 | ||
120 | if (!area->mta) | |
121 | return; | |
122 | ||
123 | area->mta->status = disable; | |
124 | ||
125 | /* Remove Link State Database */ | |
ca94e8d3 | 126 | ls_ted_clean(area->mta->ted); |
1fa63850 OD |
127 | |
128 | /* Disable Extended SubTLVs on all circuit */ | |
129 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { | |
130 | if (!IS_EXT_TE(circuit->ext)) | |
131 | continue; | |
132 | ||
133 | /* disable MPLS_TE Circuit keeping SR one's */ | |
134 | if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID)) | |
135 | circuit->ext->status = EXT_ADJ_SID; | |
136 | else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID)) | |
137 | circuit->ext->status = EXT_LAN_ADJ_SID; | |
138 | else | |
139 | circuit->ext->status = 0; | |
140 | } | |
141 | } | |
142 | ||
143 | void isis_mpls_te_term(struct isis_area *area) | |
144 | { | |
145 | struct listnode *node; | |
146 | struct isis_circuit *circuit; | |
147 | ||
148 | if (!area->mta) | |
149 | return; | |
150 | ||
151 | zlog_info("TE(%s): Terminate MPLS TE", __func__); | |
152 | /* Remove Link State Database */ | |
153 | ls_ted_del_all(&area->mta->ted); | |
154 | ||
155 | /* Remove Extended SubTLVs */ | |
156 | zlog_info(" |- Remove Extended SubTLVS for all circuit"); | |
157 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { | |
158 | zlog_info(" |- Call isis_del_ext_subtlvs()"); | |
159 | isis_del_ext_subtlvs(circuit->ext); | |
160 | circuit->ext = NULL; | |
161 | } | |
162 | ||
163 | zlog_info(" |- Free MTA structure at %p", area->mta); | |
164 | XFREE(MTYPE_ISIS_MPLS_TE, area->mta); | |
165 | } | |
166 | ||
5749ac83 LS |
167 | static void isis_link_params_update_asla(struct isis_circuit *circuit, |
168 | struct interface *ifp) | |
169 | { | |
170 | struct isis_asla_subtlvs *asla; | |
171 | struct listnode *node, *nnode; | |
172 | struct isis_ext_subtlvs *ext = circuit->ext; | |
173 | int i; | |
174 | ||
175 | if (!HAS_LINK_PARAMS(ifp)) { | |
176 | list_delete_all_node(ext->aslas); | |
177 | return; | |
178 | } | |
179 | ||
180 | #ifndef FABRICD | |
181 | /* RFC 8919 Application Specific Link-Attributes | |
182 | * is required by flex-algo application ISIS_SABM_FLAG_X | |
183 | */ | |
184 | if (list_isempty(circuit->area->flex_algos->flex_algos)) | |
185 | isis_tlvs_free_asla(ext, ISIS_SABM_FLAG_X); | |
186 | else | |
187 | isis_tlvs_find_alloc_asla(ext, ISIS_SABM_FLAG_X); | |
188 | #endif /* ifndef FABRICD */ | |
189 | ||
190 | if (list_isempty(ext->aslas)) | |
191 | return; | |
192 | ||
193 | for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla)) { | |
194 | asla->legacy = circuit->area->asla_legacy_flag; | |
195 | RESET_SUBTLV(asla); | |
196 | ||
197 | if (asla->legacy) | |
198 | continue; | |
199 | ||
200 | /* Fulfill ASLA subTLVs from interface link parameters */ | |
201 | if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) { | |
202 | asla->admin_group = ifp->link_params->admin_grp; | |
203 | SET_SUBTLV(asla, EXT_ADM_GRP); | |
204 | } else | |
205 | UNSET_SUBTLV(asla, EXT_ADM_GRP); | |
206 | ||
207 | if (IS_PARAM_SET(ifp->link_params, LP_EXTEND_ADM_GRP)) { | |
208 | admin_group_copy(&asla->ext_admin_group, | |
209 | &ifp->link_params->ext_admin_grp); | |
210 | SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP); | |
211 | } else | |
212 | UNSET_SUBTLV(asla, EXT_EXTEND_ADM_GRP); | |
213 | ||
214 | /* Send admin-group zero for better compatibility | |
215 | * https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2 | |
216 | */ | |
217 | if (circuit->area->admin_group_send_zero && | |
218 | !IS_SUBTLV(asla, EXT_ADM_GRP) && | |
219 | !IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP)) { | |
220 | asla->admin_group = 0; | |
221 | SET_SUBTLV(asla, EXT_ADM_GRP); | |
222 | admin_group_clear(&asla->ext_admin_group); | |
223 | admin_group_allow_explicit_zero(&asla->ext_admin_group); | |
224 | SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP); | |
225 | } | |
226 | ||
227 | if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) { | |
228 | asla->te_metric = ifp->link_params->te_metric; | |
229 | SET_SUBTLV(asla, EXT_TE_METRIC); | |
230 | } else | |
231 | UNSET_SUBTLV(asla, EXT_TE_METRIC); | |
232 | ||
233 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) { | |
234 | asla->delay = ifp->link_params->av_delay; | |
235 | SET_SUBTLV(asla, EXT_DELAY); | |
236 | } else | |
237 | UNSET_SUBTLV(asla, EXT_DELAY); | |
238 | ||
239 | if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) { | |
240 | asla->min_delay = ifp->link_params->min_delay; | |
241 | asla->max_delay = ifp->link_params->max_delay; | |
242 | SET_SUBTLV(asla, EXT_MM_DELAY); | |
243 | } else { | |
244 | UNSET_SUBTLV(asla, EXT_MM_DELAY); | |
245 | } | |
246 | ||
247 | if (asla->standard_apps == ISIS_SABM_FLAG_X) | |
248 | /* Flex-Algo ASLA does not need the following TE | |
249 | * sub-TLVs | |
250 | */ | |
251 | continue; | |
252 | ||
253 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) { | |
254 | asla->max_bw = ifp->link_params->max_bw; | |
255 | SET_SUBTLV(asla, EXT_MAX_BW); | |
256 | } else | |
257 | UNSET_SUBTLV(asla, EXT_MAX_BW); | |
258 | ||
259 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) { | |
260 | asla->max_rsv_bw = ifp->link_params->max_rsv_bw; | |
261 | SET_SUBTLV(asla, EXT_MAX_RSV_BW); | |
262 | } else | |
263 | UNSET_SUBTLV(asla, EXT_MAX_RSV_BW); | |
264 | ||
265 | if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) { | |
266 | for (i = 0; i < MAX_CLASS_TYPE; i++) | |
267 | asla->unrsv_bw[i] = | |
268 | ifp->link_params->unrsv_bw[i]; | |
269 | SET_SUBTLV(asla, EXT_UNRSV_BW); | |
270 | } else | |
271 | UNSET_SUBTLV(asla, EXT_UNRSV_BW); | |
272 | ||
273 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) { | |
274 | asla->delay_var = ifp->link_params->delay_var; | |
275 | SET_SUBTLV(asla, EXT_DELAY_VAR); | |
276 | } else | |
277 | UNSET_SUBTLV(asla, EXT_DELAY_VAR); | |
278 | ||
279 | if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) { | |
280 | asla->pkt_loss = ifp->link_params->pkt_loss; | |
281 | SET_SUBTLV(asla, EXT_PKT_LOSS); | |
282 | } else | |
283 | UNSET_SUBTLV(asla, EXT_PKT_LOSS); | |
284 | ||
285 | if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) { | |
286 | asla->res_bw = ifp->link_params->res_bw; | |
287 | SET_SUBTLV(asla, EXT_RES_BW); | |
288 | } else | |
289 | UNSET_SUBTLV(asla, EXT_RES_BW); | |
290 | ||
291 | if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) { | |
292 | asla->ava_bw = ifp->link_params->ava_bw; | |
293 | SET_SUBTLV(asla, EXT_AVA_BW); | |
294 | } else | |
295 | UNSET_SUBTLV(asla, EXT_AVA_BW); | |
296 | ||
297 | if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) { | |
298 | asla->use_bw = ifp->link_params->use_bw; | |
299 | SET_SUBTLV(asla, EXT_USE_BW); | |
300 | } else | |
301 | UNSET_SUBTLV(asla, EXT_USE_BW); | |
302 | } | |
303 | ||
304 | ||
305 | for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla)) { | |
306 | if (!asla->legacy && NO_SUBTLV(asla) && | |
307 | admin_group_nb_words(&asla->ext_admin_group) == 0) | |
308 | /* remove ASLA without info from the list of ASLAs to | |
309 | * not send void ASLA | |
310 | */ | |
311 | isis_tlvs_del_asla_flex_algo(ext, asla); | |
312 | } | |
313 | } | |
314 | ||
f8c06e2c OD |
315 | /* Main initialization / update function of the MPLS TE Circuit context */ |
316 | /* Call when interface TE Link parameters are modified */ | |
d62a17ae | 317 | void isis_link_params_update(struct isis_circuit *circuit, |
318 | struct interface *ifp) | |
f8c06e2c | 319 | { |
d62a17ae | 320 | int i; |
321 | struct prefix_ipv4 *addr; | |
1b3f47d0 OD |
322 | struct prefix_ipv6 *addr6; |
323 | struct isis_ext_subtlvs *ext; | |
324 | ||
325 | /* Check if TE is enable or not */ | |
326 | if (!circuit->area || !IS_MPLS_TE(circuit->area->mta)) | |
327 | return; | |
d62a17ae | 328 | |
329 | /* Sanity Check */ | |
b53c5f1a | 330 | if ((ifp == NULL) || (circuit->state != C_STATE_UP)) |
d62a17ae | 331 | return; |
332 | ||
ed6189a9 OD |
333 | te_debug("ISIS-TE(%s): Update circuit parameters for interface %s", |
334 | circuit->area->area_tag, ifp->name); | |
d62a17ae | 335 | |
336 | /* Check if MPLS TE Circuit context has not been already created */ | |
1b3f47d0 OD |
337 | if (circuit->ext == NULL) { |
338 | circuit->ext = isis_alloc_ext_subtlvs(); | |
ed6189a9 OD |
339 | te_debug(" |- Allocated new Ext-subTLVs for interface %s", |
340 | ifp->name); | |
1b3f47d0 | 341 | } |
d62a17ae | 342 | |
1b3f47d0 | 343 | ext = circuit->ext; |
d62a17ae | 344 | |
1b3f47d0 | 345 | /* Fulfill Extended subTLVs from interface link parameters */ |
d62a17ae | 346 | if (HAS_LINK_PARAMS(ifp)) { |
d62a17ae | 347 | /* STD_TE metrics */ |
1b3f47d0 OD |
348 | if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) { |
349 | ext->adm_group = ifp->link_params->admin_grp; | |
350 | SET_SUBTLV(ext, EXT_ADM_GRP); | |
351 | } else | |
352 | UNSET_SUBTLV(ext, EXT_ADM_GRP); | |
fa1b95c3 LS |
353 | |
354 | if (IS_PARAM_SET(ifp->link_params, LP_EXTEND_ADM_GRP)) { | |
355 | admin_group_copy(&ext->ext_admin_group, | |
356 | &ifp->link_params->ext_admin_grp); | |
357 | SET_SUBTLV(ext, EXT_EXTEND_ADM_GRP); | |
358 | } else | |
359 | UNSET_SUBTLV(ext, EXT_EXTEND_ADM_GRP); | |
1b3f47d0 | 360 | |
5749ac83 LS |
361 | /* Send admin-group zero for better compatibility |
362 | * https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2 | |
363 | */ | |
364 | if (circuit->area->admin_group_send_zero && | |
365 | !IS_SUBTLV(ext, EXT_ADM_GRP) && | |
366 | !IS_SUBTLV(ext, EXT_EXTEND_ADM_GRP)) { | |
367 | ext->adm_group = 0; | |
368 | SET_SUBTLV(ext, EXT_ADM_GRP); | |
369 | admin_group_clear(&ext->ext_admin_group); | |
370 | admin_group_allow_explicit_zero(&ext->ext_admin_group); | |
371 | SET_SUBTLV(ext, EXT_EXTEND_ADM_GRP); | |
372 | } | |
373 | ||
1b3f47d0 | 374 | /* If known, register local IPv4 addr from ip_addr list */ |
91a5bbc4 | 375 | if (listcount(circuit->ip_addrs) != 0) { |
1b3f47d0 OD |
376 | addr = (struct prefix_ipv4 *)listgetdata( |
377 | (struct listnode *)listhead(circuit->ip_addrs)); | |
378 | IPV4_ADDR_COPY(&ext->local_addr, &addr->prefix); | |
379 | SET_SUBTLV(ext, EXT_LOCAL_ADDR); | |
380 | } else | |
381 | UNSET_SUBTLV(ext, EXT_LOCAL_ADDR); | |
382 | ||
1b3f47d0 | 383 | /* If known, register local IPv6 addr from ip_addr list */ |
91a5bbc4 | 384 | if (listcount(circuit->ipv6_non_link) != 0) { |
1b3f47d0 OD |
385 | addr6 = (struct prefix_ipv6 *)listgetdata( |
386 | (struct listnode *)listhead( | |
387 | circuit->ipv6_non_link)); | |
388 | IPV6_ADDR_COPY(&ext->local_addr6, &addr6->prefix); | |
389 | SET_SUBTLV(ext, EXT_LOCAL_ADDR6); | |
390 | } else | |
391 | UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6); | |
392 | ||
ed6189a9 OD |
393 | /* |
394 | * Remote IPv4 and IPv6 addresses are now added in | |
395 | * isis_mpls_te_adj_ip_enabled() to get the right IP address | |
396 | * in particular for IPv6 to get the global IPv6 address and | |
397 | * not the link-local IPv6 address. | |
398 | */ | |
1b3f47d0 OD |
399 | |
400 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) { | |
401 | ext->max_bw = ifp->link_params->max_bw; | |
402 | SET_SUBTLV(ext, EXT_MAX_BW); | |
403 | } else | |
404 | UNSET_SUBTLV(ext, EXT_MAX_BW); | |
405 | ||
406 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) { | |
407 | ext->max_rsv_bw = ifp->link_params->max_rsv_bw; | |
408 | SET_SUBTLV(ext, EXT_MAX_RSV_BW); | |
409 | } else | |
410 | UNSET_SUBTLV(ext, EXT_MAX_RSV_BW); | |
411 | ||
412 | if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) { | |
d62a17ae | 413 | for (i = 0; i < MAX_CLASS_TYPE; i++) |
1b3f47d0 OD |
414 | ext->unrsv_bw[i] = |
415 | ifp->link_params->unrsv_bw[i]; | |
416 | SET_SUBTLV(ext, EXT_UNRSV_BW); | |
417 | } else | |
418 | UNSET_SUBTLV(ext, EXT_UNRSV_BW); | |
419 | ||
420 | if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) { | |
421 | ext->te_metric = ifp->link_params->te_metric; | |
422 | SET_SUBTLV(ext, EXT_TE_METRIC); | |
423 | } else | |
424 | UNSET_SUBTLV(ext, EXT_TE_METRIC); | |
425 | ||
426 | /* TE metric extensions */ | |
427 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) { | |
428 | ext->delay = ifp->link_params->av_delay; | |
429 | SET_SUBTLV(ext, EXT_DELAY); | |
430 | } else | |
431 | UNSET_SUBTLV(ext, EXT_DELAY); | |
432 | ||
433 | if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) { | |
434 | ext->min_delay = ifp->link_params->min_delay; | |
435 | ext->max_delay = ifp->link_params->max_delay; | |
436 | SET_SUBTLV(ext, EXT_MM_DELAY); | |
437 | } else | |
438 | UNSET_SUBTLV(ext, EXT_MM_DELAY); | |
439 | ||
440 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) { | |
441 | ext->delay_var = ifp->link_params->delay_var; | |
442 | SET_SUBTLV(ext, EXT_DELAY_VAR); | |
443 | } else | |
444 | UNSET_SUBTLV(ext, EXT_DELAY_VAR); | |
445 | ||
446 | if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) { | |
447 | ext->pkt_loss = ifp->link_params->pkt_loss; | |
448 | SET_SUBTLV(ext, EXT_PKT_LOSS); | |
449 | } else | |
450 | UNSET_SUBTLV(ext, EXT_PKT_LOSS); | |
451 | ||
452 | if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) { | |
453 | ext->res_bw = ifp->link_params->res_bw; | |
454 | SET_SUBTLV(ext, EXT_RES_BW); | |
455 | } else | |
456 | UNSET_SUBTLV(ext, EXT_RES_BW); | |
457 | ||
458 | if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) { | |
459 | ext->ava_bw = ifp->link_params->ava_bw; | |
460 | SET_SUBTLV(ext, EXT_AVA_BW); | |
461 | } else | |
462 | UNSET_SUBTLV(ext, EXT_AVA_BW); | |
463 | ||
464 | if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) { | |
465 | ext->use_bw = ifp->link_params->use_bw; | |
466 | SET_SUBTLV(ext, EXT_USE_BW); | |
467 | } else | |
468 | UNSET_SUBTLV(ext, EXT_USE_BW); | |
d62a17ae | 469 | |
1b3f47d0 OD |
470 | /* INTER_AS */ |
471 | if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) { | |
472 | ext->remote_as = ifp->link_params->rmt_as; | |
473 | ext->remote_ip = ifp->link_params->rmt_ip; | |
474 | SET_SUBTLV(ext, EXT_RMT_AS); | |
475 | SET_SUBTLV(ext, EXT_RMT_IP); | |
476 | } else { | |
477 | /* reset inter-as TE params */ | |
478 | UNSET_SUBTLV(ext, EXT_RMT_AS); | |
479 | UNSET_SUBTLV(ext, EXT_RMT_IP); | |
480 | } | |
ed6189a9 OD |
481 | te_debug(" |- New MPLS-TE link parameters status 0x%x", |
482 | ext->status); | |
1b3f47d0 | 483 | } else { |
ed6189a9 OD |
484 | te_debug(" |- Reset Extended subTLVs status 0x%x", |
485 | ext->status); | |
1b3f47d0 OD |
486 | /* Reset TE subTLVs keeping SR one's */ |
487 | if (IS_SUBTLV(ext, EXT_ADJ_SID)) | |
488 | ext->status = EXT_ADJ_SID; | |
489 | else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID)) | |
490 | ext->status = EXT_LAN_ADJ_SID; | |
d62a17ae | 491 | else |
1b3f47d0 OD |
492 | ext->status = 0; |
493 | } | |
d62a17ae | 494 | |
5749ac83 LS |
495 | isis_link_params_update_asla(circuit, ifp); |
496 | ||
1b3f47d0 OD |
497 | return; |
498 | } | |
d62a17ae | 499 | |
78d905be LS |
500 | static int _isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family, |
501 | bool global) | |
1b3f47d0 | 502 | { |
173f8887 OD |
503 | struct isis_circuit *circuit; |
504 | struct isis_ext_subtlvs *ext; | |
505 | ||
173f8887 | 506 | circuit = adj->circuit; |
d62a17ae | 507 | |
173f8887 OD |
508 | /* Check that MPLS TE is enabled */ |
509 | if (!IS_MPLS_TE(circuit->area->mta) || !circuit->ext) | |
510 | return 0; | |
511 | ||
512 | ext = circuit->ext; | |
d62a17ae | 513 | |
173f8887 OD |
514 | /* Determine nexthop IP address */ |
515 | switch (family) { | |
516 | case AF_INET: | |
517 | if (!circuit->ip_router || !adj->ipv4_address_count) | |
518 | UNSET_SUBTLV(ext, EXT_NEIGH_ADDR); | |
519 | else { | |
520 | IPV4_ADDR_COPY(&ext->neigh_addr, | |
521 | &adj->ipv4_addresses[0]); | |
522 | SET_SUBTLV(ext, EXT_NEIGH_ADDR); | |
523 | } | |
524 | break; | |
525 | case AF_INET6: | |
78d905be LS |
526 | /* Nothing to do for link-local addresses - ie. not global. |
527 | * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1 | |
528 | * Because the IPv6 traffic engineering TLVs present in LSPs are | |
529 | * propagated across networks, they MUST NOT use link-local | |
530 | * addresses. | |
531 | */ | |
173f8887 OD |
532 | if (!global) |
533 | return 0; | |
534 | ||
535 | if (!circuit->ipv6_router || !adj->global_ipv6_count) | |
536 | UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6); | |
537 | else { | |
538 | IPV6_ADDR_COPY(&ext->neigh_addr6, | |
539 | &adj->global_ipv6_addrs[0]); | |
540 | SET_SUBTLV(ext, EXT_NEIGH_ADDR6); | |
541 | } | |
542 | break; | |
543 | default: | |
544 | return 0; | |
1b3f47d0 | 545 | } |
d62a17ae | 546 | |
173f8887 OD |
547 | return 0; |
548 | } | |
549 | ||
78d905be LS |
550 | static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family, |
551 | bool global) | |
173f8887 | 552 | { |
78d905be | 553 | int ret; |
173f8887 OD |
554 | |
555 | /* Sanity Check */ | |
78d905be | 556 | if (!adj || !adj->circuit) |
173f8887 OD |
557 | return 0; |
558 | ||
78d905be LS |
559 | ret = _isis_mpls_te_adj_ip_enabled(adj, family, global); |
560 | ||
561 | /* Update LSP */ | |
562 | lsp_regenerate_schedule(adj->circuit->area, adj->circuit->is_type, 0); | |
563 | ||
564 | return ret; | |
565 | } | |
566 | ||
567 | static int _isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family, | |
568 | bool global) | |
569 | { | |
570 | struct isis_circuit *circuit; | |
571 | struct isis_ext_subtlvs *ext; | |
572 | ||
173f8887 OD |
573 | circuit = adj->circuit; |
574 | ||
575 | /* Check that MPLS TE is enabled */ | |
576 | if (!IS_MPLS_TE(circuit->area->mta) || !circuit->ext) | |
577 | return 0; | |
578 | ||
579 | ext = circuit->ext; | |
580 | ||
581 | /* Update MPLS TE IP address parameters if possible */ | |
582 | if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(ext)) | |
583 | return 0; | |
584 | ||
585 | /* Determine nexthop IP address */ | |
586 | switch (family) { | |
587 | case AF_INET: | |
588 | UNSET_SUBTLV(ext, EXT_NEIGH_ADDR); | |
589 | break; | |
590 | case AF_INET6: | |
591 | if (global) | |
592 | UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6); | |
593 | break; | |
594 | default: | |
595 | return 0; | |
1b3f47d0 | 596 | } |
d62a17ae | 597 | |
78d905be LS |
598 | return 0; |
599 | } | |
600 | ||
601 | static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family, | |
602 | bool global) | |
603 | { | |
604 | int ret; | |
605 | ||
606 | /* Sanity Check */ | |
607 | if (!adj || !adj->circuit || !adj->circuit->ext) | |
608 | return 0; | |
609 | ||
610 | ret = _isis_mpls_te_adj_ip_disabled(adj, family, global); | |
611 | ||
173f8887 | 612 | /* Update LSP */ |
78d905be | 613 | lsp_regenerate_schedule(adj->circuit->area, adj->circuit->is_type, 0); |
173f8887 | 614 | |
78d905be | 615 | return ret; |
f8c06e2c OD |
616 | } |
617 | ||
78d905be LS |
618 | static void isis_mpls_te_circuit_ip_update(struct isis_circuit *circuit) |
619 | { | |
620 | struct isis_adjacency *adj; | |
621 | ||
622 | /* https://datatracker.ietf.org/doc/html/rfc6119#section-3.2.3 | |
623 | * This sub-TLV of the Extended IS Reachability TLV is used for point- | |
624 | * to-point links | |
625 | */ | |
626 | if (circuit->circ_type != CIRCUIT_T_P2P) | |
627 | return; | |
628 | ||
629 | adj = circuit->u.p2p.neighbor; | |
630 | ||
631 | if (!adj) | |
632 | return; | |
633 | ||
634 | /* Nothing to do for link-local addresses. | |
635 | * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1 | |
636 | * Because the IPv6 traffic engineering TLVs present in LSPs are | |
637 | * propagated across networks, they MUST NOT use link-local addresses. | |
638 | */ | |
639 | if (adj->ipv4_address_count > 0) | |
640 | _isis_mpls_te_adj_ip_enabled(adj, AF_INET, false); | |
641 | else | |
642 | _isis_mpls_te_adj_ip_disabled(adj, AF_INET, false); | |
643 | ||
644 | if (adj->global_ipv6_count > 0) | |
645 | _isis_mpls_te_adj_ip_enabled(adj, AF_INET6, true); | |
646 | else | |
647 | _isis_mpls_te_adj_ip_disabled(adj, AF_INET6, true); | |
648 | } | |
649 | ||
650 | ||
1b3f47d0 | 651 | int isis_mpls_te_update(struct interface *ifp) |
f8c06e2c | 652 | { |
d62a17ae | 653 | struct isis_circuit *circuit; |
1b3f47d0 | 654 | uint8_t rc = 1; |
f8c06e2c | 655 | |
d62a17ae | 656 | /* Sanity Check */ |
657 | if (ifp == NULL) | |
1b3f47d0 | 658 | return rc; |
f8c06e2c | 659 | |
d62a17ae | 660 | /* Get circuit context from interface */ |
1b3f47d0 OD |
661 | circuit = circuit_scan_by_ifp(ifp); |
662 | if (circuit == NULL) | |
663 | return rc; | |
f8c06e2c | 664 | |
d62a17ae | 665 | /* Update TE TLVs ... */ |
666 | isis_link_params_update(circuit, ifp); | |
f8c06e2c | 667 | |
d62a17ae | 668 | /* ... and LSP */ |
5749ac83 LS |
669 | if (circuit->area && |
670 | (IS_MPLS_TE(circuit->area->mta) | |
671 | #ifndef FABRICD | |
672 | || !list_isempty(circuit->area->flex_algos->flex_algos) | |
673 | #endif /* ifndef FABRICD */ | |
674 | )) | |
d62a17ae | 675 | lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); |
f8c06e2c | 676 | |
1b3f47d0 OD |
677 | rc = 0; |
678 | return rc; | |
f8c06e2c OD |
679 | } |
680 | ||
ed6189a9 OD |
681 | |
682 | /** | |
683 | * Export Link State information to consumer daemon through ZAPI Link State | |
684 | * Opaque Message. | |
685 | * | |
686 | * @param type Type of Link State Element i.e. Vertex, Edge or Subnet | |
687 | * @param link_state Pointer to Link State Vertex, Edge or Subnet | |
688 | * | |
689 | * @return 0 if success, -1 otherwise | |
690 | */ | |
691 | static int isis_te_export(uint8_t type, void *link_state) | |
692 | { | |
693 | struct ls_message msg = {}; | |
694 | int rc = 0; | |
695 | ||
696 | switch (type) { | |
697 | case LS_MSG_TYPE_NODE: | |
698 | ls_vertex2msg(&msg, (struct ls_vertex *)link_state); | |
699 | rc = ls_send_msg(zclient, &msg, NULL); | |
700 | break; | |
701 | case LS_MSG_TYPE_ATTRIBUTES: | |
702 | ls_edge2msg(&msg, (struct ls_edge *)link_state); | |
703 | rc = ls_send_msg(zclient, &msg, NULL); | |
704 | break; | |
705 | case LS_MSG_TYPE_PREFIX: | |
706 | ls_subnet2msg(&msg, (struct ls_subnet *)link_state); | |
707 | rc = ls_send_msg(zclient, &msg, NULL); | |
708 | break; | |
709 | default: | |
710 | rc = -1; | |
711 | break; | |
712 | } | |
713 | ||
714 | return rc; | |
715 | } | |
716 | ||
717 | /** | |
718 | * Parse LSP and build corresponding vertex. If vertex doesn't exist in the | |
719 | * Link State Database it is created otherwise updated. | |
720 | * | |
721 | * @param ted Traffic Engineering Link State Database | |
722 | * @param lsp IS-IS Link State PDU | |
723 | * | |
724 | * @return Link State Vertex or NULL in case of error | |
725 | */ | |
726 | static struct ls_vertex *lsp_to_vertex(struct ls_ted *ted, struct isis_lsp *lsp) | |
727 | { | |
728 | struct ls_vertex *vertex = NULL; | |
729 | struct ls_node *old, lnode = {}; | |
730 | struct isis_tlvs *tlvs; | |
731 | const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; | |
732 | ||
733 | /* Sanity check */ | |
734 | if (!ted || !lsp) | |
735 | return NULL; | |
736 | ||
737 | /* Compute Link State Node ID from IS-IS sysID ... */ | |
738 | if (lsp->level == ISIS_LEVEL1) | |
739 | lnode.adv.origin = ISIS_L1; | |
740 | else | |
741 | lnode.adv.origin = ISIS_L2; | |
742 | memcpy(&lnode.adv.id.iso.sys_id, &lsp->hdr.lsp_id, ISIS_SYS_ID_LEN); | |
743 | lnode.adv.id.iso.level = lsp->level; | |
744 | /* ... and search the corresponding vertex */ | |
745 | vertex = ls_find_vertex_by_id(ted, lnode.adv); | |
746 | /* Create a new one if not found */ | |
747 | if (!vertex) { | |
748 | old = ls_node_new(lnode.adv, inaddr_any, in6addr_any); | |
749 | old->type = STANDARD; | |
750 | vertex = ls_vertex_add(ted, old); | |
751 | } | |
752 | old = vertex->node; | |
753 | te_debug(" |- %s Vertex (%" PRIu64 ") for node %s", | |
754 | vertex->status == NEW ? "Create" : "Found", vertex->key, | |
755 | print_sys_hostname(old->adv.id.iso.sys_id)); | |
756 | ||
757 | /* Fulfill Link State Node information */ | |
758 | tlvs = lsp->tlvs; | |
759 | if (tlvs) { | |
760 | if (tlvs->te_router_id) { | |
761 | IPV4_ADDR_COPY(&lnode.router_id, tlvs->te_router_id); | |
762 | SET_FLAG(lnode.flags, LS_NODE_ROUTER_ID); | |
763 | } | |
764 | if (tlvs->te_router_id_ipv6) { | |
765 | IPV6_ADDR_COPY(&lnode.router_id6, | |
766 | tlvs->te_router_id_ipv6); | |
767 | SET_FLAG(lnode.flags, LS_NODE_ROUTER_ID6); | |
768 | } | |
769 | if (tlvs->hostname) { | |
a976aa3c | 770 | strlcpy(lnode.name, tlvs->hostname, MAX_NAME_LENGTH); |
ed6189a9 OD |
771 | SET_FLAG(lnode.flags, LS_NODE_NAME); |
772 | } | |
773 | if (tlvs->router_cap) { | |
774 | struct isis_router_cap *cap = tlvs->router_cap; | |
775 | ||
776 | if (cap->srgb.lower_bound != 0 | |
777 | && cap->srgb.range_size != 0) { | |
778 | SET_FLAG(lnode.flags, LS_NODE_SR); | |
779 | lnode.srgb.flag = cap->srgb.flags; | |
780 | lnode.srgb.lower_bound = cap->srgb.lower_bound; | |
781 | lnode.srgb.range_size = cap->srgb.range_size; | |
81a067cd | 782 | for (int i = 0; i < LIB_LS_SR_ALGO_COUNT; i++) |
ed6189a9 OD |
783 | lnode.algo[i] = cap->algo[i]; |
784 | } | |
785 | ||
786 | if (cap->srlb.lower_bound != 0 | |
787 | && cap->srlb.range_size != 0) { | |
788 | lnode.srlb.lower_bound = cap->srlb.lower_bound; | |
789 | lnode.srlb.range_size = cap->srlb.range_size; | |
790 | SET_FLAG(lnode.flags, LS_NODE_SRLB); | |
791 | } | |
792 | if (cap->msd != 0) { | |
793 | lnode.msd = cap->msd; | |
794 | SET_FLAG(lnode.flags, LS_NODE_MSD); | |
795 | } | |
796 | } | |
797 | } | |
798 | ||
799 | /* Update Link State Node information */ | |
800 | if (!ls_node_same(old, &lnode)) { | |
801 | te_debug(" |- Update Link State Node information"); | |
802 | memcpy(old, &lnode, sizeof(struct ls_node)); | |
803 | if (vertex->status != NEW) | |
804 | vertex->status = UPDATE; | |
805 | } | |
806 | ||
807 | /* Set self TED vertex if LSP corresponds to the own router */ | |
808 | if (lsp->own_lsp) | |
809 | ted->self = vertex; | |
810 | ||
811 | return vertex; | |
812 | } | |
813 | ||
814 | /** | |
815 | * Get Link State Edge from Link State Attributes in TE Database. | |
816 | * Edge structure is dynamically allocated and fulfill with Link State | |
817 | * Attributes if not found. | |
818 | * | |
819 | * @param ted Link State Database | |
820 | * @param attr Link State Attributes | |
821 | * | |
822 | * @return New Link State Edge if success, NULL otherwise | |
823 | */ | |
824 | static struct ls_edge *get_edge(struct ls_ted *ted, struct ls_attributes *attr) | |
825 | { | |
826 | struct ls_edge *edge; | |
827 | struct ls_standard *std; | |
7564fcb8 | 828 | struct ls_edge_key key; |
ed6189a9 OD |
829 | |
830 | /* Check parameters */ | |
831 | if (!ted || !attr) | |
832 | return NULL; | |
833 | ||
834 | std = &attr->standard; | |
835 | ||
836 | /* Compute keys in function of local address (IPv4/v6) or identifier */ | |
7564fcb8 OD |
837 | if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) { |
838 | key.family = AF_INET; | |
839 | IPV4_ADDR_COPY(&key.k.addr, &std->local); | |
840 | } else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) { | |
841 | key.family = AF_INET6; | |
842 | IPV6_ADDR_COPY(&key.k.addr6, &std->local6); | |
843 | } else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) { | |
844 | key.family = AF_LOCAL; | |
845 | key.k.link_id = (((uint64_t)std->local_id) & 0xffffffff) | | |
846 | ((uint64_t)std->remote_id << 32); | |
847 | } else { | |
848 | key.family = AF_UNSPEC; | |
849 | } | |
ed6189a9 OD |
850 | |
851 | /* Stop here if we don't got a valid key */ | |
7564fcb8 | 852 | if (key.family == AF_UNSPEC) |
ed6189a9 OD |
853 | return NULL; |
854 | ||
855 | /* Get corresponding Edge by key from Link State Data Base */ | |
856 | edge = ls_find_edge_by_key(ted, key); | |
857 | ||
858 | /* and create new one if not exist */ | |
859 | if (!edge) { | |
860 | edge = ls_edge_add(ted, attr); | |
861 | /* | |
862 | * Edge could be Null if no local ID is found in Attributes. | |
863 | * Stop the processing as without any local ID it is not | |
864 | * possible to store Edge in the TED. | |
865 | */ | |
866 | if (!edge) | |
867 | return NULL; | |
868 | } | |
869 | ||
870 | if (CHECK_FLAG(edge->attributes->flags, LS_ATTR_LOCAL_ADDR)) | |
7564fcb8 OD |
871 | te_debug(" |- %s Edge (%pI4) from Extended Reach. %pI4", |
872 | edge->status == NEW ? "Create" : "Found", | |
873 | &edge->key.k.addr, &attr->standard.local); | |
ed6189a9 | 874 | else if (CHECK_FLAG(edge->attributes->flags, LS_ATTR_LOCAL_ADDR6)) |
7564fcb8 OD |
875 | te_debug(" |- %s Edge (%pI6) from Extended Reach. %pI6", |
876 | edge->status == NEW ? "Create" : "Found", | |
877 | &edge->key.k.addr6, &attr->standard.local6); | |
ed6189a9 OD |
878 | else |
879 | te_debug(" |- %s Edge (%" PRIu64 ")", | |
7564fcb8 OD |
880 | edge->status == NEW ? "Create" : "Found", |
881 | edge->key.k.link_id); | |
ed6189a9 OD |
882 | |
883 | return edge; | |
884 | } | |
885 | ||
886 | /** | |
887 | * Get Link State Attributes from IS-IS Sub-TLVs. Structure is dynamically | |
888 | * allocated and should be free once not use anymore. | |
889 | * | |
890 | * @param adv Link State Node ID | |
891 | * @param tlvs IS-IS Sub TLVs | |
892 | * | |
893 | * @return New Link State attributes if success, NULL otherwise | |
894 | */ | |
895 | static struct ls_attributes *get_attributes(struct ls_node_id adv, | |
896 | struct isis_ext_subtlvs *tlvs) | |
897 | { | |
898 | struct ls_attributes *attr; | |
899 | struct in_addr local = {.s_addr = INADDR_ANY}; | |
900 | struct in6_addr local6 = in6addr_any; | |
901 | uint32_t local_id = 0; | |
902 | ||
903 | /* Got Local identifier */ | |
904 | if (CHECK_FLAG(tlvs->status, EXT_LOCAL_ADDR)) | |
905 | local.s_addr = tlvs->local_addr.s_addr; | |
906 | ||
907 | if (CHECK_FLAG(tlvs->status, EXT_LOCAL_ADDR6)) | |
908 | memcpy(&local6, &tlvs->local_addr6, IPV6_MAX_BYTELEN); | |
909 | ||
910 | if (CHECK_FLAG(tlvs->status, EXT_LLRI)) | |
911 | local_id = tlvs->local_llri; | |
912 | ||
913 | /* Create LS Attributes */ | |
914 | attr = ls_attributes_new(adv, local, local6, local_id); | |
915 | if (!attr) | |
916 | return NULL; | |
917 | ||
918 | /* Browse sub-TLV and fulfill Link State Attributes */ | |
919 | if (CHECK_FLAG(tlvs->status, EXT_ADM_GRP)) { | |
920 | attr->standard.admin_group = tlvs->adm_group; | |
921 | SET_FLAG(attr->flags, LS_ATTR_ADM_GRP); | |
922 | } | |
bd0581e4 LS |
923 | if (CHECK_FLAG(tlvs->status, EXT_EXTEND_ADM_GRP)) { |
924 | admin_group_copy(&attr->ext_admin_group, | |
925 | &tlvs->ext_admin_group); | |
926 | SET_FLAG(attr->flags, LS_ATTR_EXT_ADM_GRP); | |
927 | } | |
ed6189a9 OD |
928 | if (CHECK_FLAG(tlvs->status, EXT_LLRI)) { |
929 | attr->standard.local_id = tlvs->local_llri; | |
930 | attr->standard.remote_id = tlvs->remote_llri; | |
931 | SET_FLAG(attr->flags, LS_ATTR_LOCAL_ID); | |
932 | SET_FLAG(attr->flags, LS_ATTR_NEIGH_ID); | |
933 | } | |
934 | if (CHECK_FLAG(tlvs->status, EXT_NEIGH_ADDR)) { | |
935 | attr->standard.remote.s_addr = tlvs->neigh_addr.s_addr; | |
936 | SET_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR); | |
937 | } | |
938 | if (CHECK_FLAG(tlvs->status, EXT_NEIGH_ADDR6)) { | |
939 | memcpy(&attr->standard.remote6, &tlvs->neigh_addr6, | |
940 | IPV6_MAX_BYTELEN); | |
941 | SET_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6); | |
942 | } | |
943 | if (CHECK_FLAG(tlvs->status, EXT_MAX_BW)) { | |
944 | attr->standard.max_bw = tlvs->max_bw; | |
945 | SET_FLAG(attr->flags, LS_ATTR_MAX_BW); | |
946 | } | |
947 | if (CHECK_FLAG(tlvs->status, EXT_MAX_RSV_BW)) { | |
948 | attr->standard.max_rsv_bw = tlvs->max_rsv_bw; | |
949 | SET_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW); | |
950 | } | |
951 | if (CHECK_FLAG(tlvs->status, EXT_UNRSV_BW)) { | |
952 | memcpy(&attr->standard.unrsv_bw, tlvs->unrsv_bw, | |
953 | ISIS_SUBTLV_UNRSV_BW_SIZE); | |
954 | SET_FLAG(attr->flags, LS_ATTR_UNRSV_BW); | |
955 | } | |
956 | if (CHECK_FLAG(tlvs->status, EXT_TE_METRIC)) { | |
957 | attr->standard.te_metric = tlvs->te_metric; | |
958 | SET_FLAG(attr->flags, LS_ATTR_TE_METRIC); | |
959 | } | |
960 | if (CHECK_FLAG(tlvs->status, EXT_RMT_AS)) { | |
961 | attr->standard.remote_as = tlvs->remote_as; | |
962 | SET_FLAG(attr->flags, LS_ATTR_REMOTE_AS); | |
963 | } | |
964 | if (CHECK_FLAG(tlvs->status, EXT_RMT_IP)) { | |
965 | attr->standard.remote_addr = tlvs->remote_ip; | |
966 | SET_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR); | |
967 | } | |
968 | if (CHECK_FLAG(tlvs->status, EXT_DELAY)) { | |
969 | attr->extended.delay = tlvs->delay; | |
970 | SET_FLAG(attr->flags, LS_ATTR_DELAY); | |
971 | } | |
972 | if (CHECK_FLAG(tlvs->status, EXT_MM_DELAY)) { | |
973 | attr->extended.min_delay = tlvs->min_delay; | |
974 | attr->extended.max_delay = tlvs->max_delay; | |
975 | SET_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY); | |
976 | } | |
977 | if (CHECK_FLAG(tlvs->status, EXT_DELAY_VAR)) { | |
978 | attr->extended.jitter = tlvs->delay_var; | |
979 | SET_FLAG(attr->flags, LS_ATTR_JITTER); | |
980 | } | |
981 | if (CHECK_FLAG(tlvs->status, EXT_PKT_LOSS)) { | |
982 | attr->extended.pkt_loss = tlvs->pkt_loss; | |
983 | SET_FLAG(attr->flags, LS_ATTR_PACKET_LOSS); | |
984 | } | |
985 | if (CHECK_FLAG(tlvs->status, EXT_AVA_BW)) { | |
986 | attr->extended.ava_bw = tlvs->ava_bw; | |
987 | SET_FLAG(attr->flags, LS_ATTR_AVA_BW); | |
988 | } | |
989 | if (CHECK_FLAG(tlvs->status, EXT_RES_BW)) { | |
990 | attr->extended.rsv_bw = tlvs->res_bw; | |
991 | SET_FLAG(attr->flags, LS_ATTR_RSV_BW); | |
992 | } | |
993 | if (CHECK_FLAG(tlvs->status, EXT_USE_BW)) { | |
994 | attr->extended.used_bw = tlvs->use_bw; | |
995 | SET_FLAG(attr->flags, LS_ATTR_USE_BW); | |
996 | } | |
997 | if (CHECK_FLAG(tlvs->status, EXT_ADJ_SID)) { | |
998 | struct isis_adj_sid *adj = | |
999 | (struct isis_adj_sid *)tlvs->adj_sid.head; | |
1000 | int i; | |
1001 | for (; adj; adj = adj->next) { | |
1002 | i = adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? 1 : 0; | |
1003 | i += adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? 2 : 0; | |
1004 | attr->adj_sid[i].flags = adj->flags; | |
1005 | attr->adj_sid[i].weight = adj->weight; | |
1006 | attr->adj_sid[i].sid = adj->sid; | |
1007 | switch (i) { | |
1008 | case ADJ_PRI_IPV4: | |
1009 | SET_FLAG(attr->flags, LS_ATTR_ADJ_SID); | |
1010 | break; | |
1011 | case ADJ_BCK_IPV4: | |
1012 | SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID); | |
1013 | break; | |
1014 | case ADJ_PRI_IPV6: | |
1015 | SET_FLAG(attr->flags, LS_ATTR_ADJ_SID6); | |
1016 | break; | |
1017 | case ADJ_BCK_IPV6: | |
1018 | SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID6); | |
1019 | break; | |
1020 | } | |
1021 | } | |
1022 | } | |
1023 | if (CHECK_FLAG(tlvs->status, EXT_LAN_ADJ_SID)) { | |
1024 | struct isis_lan_adj_sid *ladj = | |
1025 | (struct isis_lan_adj_sid *)tlvs->lan_sid.head; | |
1026 | int i; | |
1027 | for (; ladj; ladj = ladj->next) { | |
1028 | i = ladj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? 1 : 0; | |
1029 | i += ladj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? 2 : 0; | |
1030 | attr->adj_sid[i].flags = ladj->flags; | |
1031 | attr->adj_sid[i].weight = ladj->weight; | |
1032 | attr->adj_sid[i].sid = ladj->sid; | |
1033 | memcpy(&attr->adj_sid[i].neighbor.sysid, | |
1034 | &ladj->neighbor_id, ISIS_SYS_ID_LEN); | |
1035 | switch (i) { | |
1036 | case ADJ_PRI_IPV4: | |
1037 | SET_FLAG(attr->flags, LS_ATTR_ADJ_SID); | |
1038 | break; | |
1039 | case ADJ_BCK_IPV4: | |
1040 | SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID); | |
1041 | break; | |
1042 | case ADJ_PRI_IPV6: | |
1043 | SET_FLAG(attr->flags, LS_ATTR_ADJ_SID6); | |
1044 | break; | |
1045 | case ADJ_BCK_IPV6: | |
1046 | SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID6); | |
1047 | break; | |
1048 | } | |
1049 | } | |
1050 | } | |
1051 | ||
1052 | return attr; | |
1053 | } | |
1054 | ||
1055 | /** | |
1056 | * Parse Extended Reachability TLVs and create or update the corresponding | |
1057 | * Link State Edge and Attributes. Vertex connections are also updated if | |
1058 | * needed based on the remote IP address of the Edge and existing reverse Edge. | |
1059 | * | |
1060 | * @param id ID of Extended IS | |
1061 | * @param metric Metric of the link | |
1062 | * @param old_metric Boolean that indicate if it is an old metric (no TE) | |
1063 | * @param tlvs SubTlvs that contains TE information | |
1064 | * @param arg IS-IS TE argument (TED, Vertex, and export indication) | |
1065 | * | |
1066 | * @return 0 if success, -1 otherwise | |
1067 | */ | |
1068 | static int lsp_to_edge_cb(const uint8_t *id, uint32_t metric, bool old_metric, | |
1069 | struct isis_ext_subtlvs *tlvs, void *arg) | |
1070 | { | |
1071 | struct isis_te_args *args = (struct isis_te_args *)arg; | |
1072 | struct ls_vertex *vertex; | |
1073 | struct ls_edge *edge, *dst; | |
1074 | struct ls_attributes *attr; | |
1075 | ||
5d39a819 | 1076 | te_debug(" |- Process Extended IS for %pSY", id); |
ed6189a9 OD |
1077 | |
1078 | /* Check parameters */ | |
1079 | if (old_metric || !args || !tlvs) | |
1080 | return LSP_ITER_CONTINUE; | |
1081 | ||
1082 | /* Initialize Link State Attributes */ | |
1083 | vertex = args->vertex; | |
1084 | attr = get_attributes(vertex->node->adv, tlvs); | |
1085 | /* | |
1086 | * Attributes may be Null if no local ID has been found in the LSP. | |
1087 | * Stop processing here as without any local ID it is not possible to | |
1088 | * create corresponding Edge in the TED. | |
1089 | */ | |
1090 | if (!attr) | |
1091 | return LSP_ITER_CONTINUE; | |
1092 | ||
1093 | attr->metric = metric; | |
29abd4e3 | 1094 | SET_FLAG(attr->flags, LS_ATTR_METRIC); |
ed6189a9 OD |
1095 | |
1096 | /* Get corresponding Edge from Link State Data Base */ | |
1097 | edge = get_edge(args->ted, attr); | |
1098 | /* | |
1099 | * Edge could be Null if no local ID has been found in Attributes. | |
1100 | * Stop processing here as without any local ID it is not possible to | |
1101 | * create corresponding Edge in the TED. | |
1102 | */ | |
1103 | if (!edge) { | |
1104 | ls_attributes_del(attr); | |
1105 | return LSP_ITER_CONTINUE; | |
1106 | } | |
1107 | ||
1108 | /* Update Attribute fields if there are different */ | |
1109 | if (edge->status != NEW) { | |
1110 | if (!ls_attributes_same(edge->attributes, attr)) { | |
1111 | te_debug(" |- Update Edge Attributes information"); | |
1112 | ls_attributes_del(edge->attributes); | |
1113 | edge->attributes = attr; | |
1114 | edge->status = UPDATE; | |
1115 | } else { | |
1116 | if (edge->attributes != attr) | |
1117 | ls_attributes_del(attr); | |
1118 | edge->status = SYNC; | |
1119 | } | |
1120 | } | |
1121 | ||
1122 | /* Try to update remote Link from remote address or reachability ID */ | |
7564fcb8 OD |
1123 | if (edge->key.family == AF_INET) |
1124 | te_debug(" |- Link Edge (%pI4) to destination vertex (%s)", | |
1125 | &edge->key.k.addr, print_sys_hostname(id)); | |
1126 | else if (edge->key.family == AF_INET6) | |
1127 | te_debug(" |- Link Edge (%pI6) to destination vertex (%s)", | |
1128 | &edge->key.k.addr6, print_sys_hostname(id)); | |
1129 | else if (edge->key.family == AF_LOCAL) | |
1130 | te_debug(" |- Link Edge (%" PRIu64 | |
1131 | ") to destination vertex (%s)", | |
1132 | edge->key.k.link_id, print_sys_hostname(id)); | |
1133 | else | |
1134 | te_debug( | |
1135 | " |- Link Edge (Unknown) to destination vertex (%s)", | |
1136 | print_sys_hostname(id)); | |
1137 | ||
ed6189a9 OD |
1138 | dst = ls_find_edge_by_destination(args->ted, edge->attributes); |
1139 | if (dst) { | |
1140 | /* Attach remote link if not set */ | |
1141 | if (edge->source && dst->destination == NULL) { | |
1142 | vertex = edge->source; | |
1143 | if (vertex->incoming_edges) | |
1144 | listnode_add_sort_nodup(vertex->incoming_edges, | |
1145 | dst); | |
1146 | dst->destination = vertex; | |
1147 | } | |
1148 | /* and destination vertex to this edge if not set */ | |
1149 | if (dst->source && edge->destination == NULL) { | |
1150 | vertex = dst->source; | |
1151 | if (vertex->incoming_edges) | |
1152 | listnode_add_sort_nodup(vertex->incoming_edges, | |
1153 | edge); | |
1154 | edge->destination = vertex; | |
1155 | } | |
1156 | } else { | |
1157 | /* Search dst. Vertex by Extended Reach. ID if not found */ | |
1158 | if (edge->destination == NULL) { | |
1159 | vertex = ls_find_vertex_by_key(args->ted, | |
1160 | sysid_to_key(id)); | |
1161 | if (vertex && vertex->incoming_edges) | |
1162 | listnode_add_sort_nodup(vertex->incoming_edges, | |
1163 | edge); | |
1164 | edge->destination = vertex; | |
1165 | } | |
1166 | } | |
1167 | ||
1168 | /* Update status and Export Link State Edge if needed */ | |
1169 | if (edge->status != SYNC) { | |
1170 | if (args->export) | |
1171 | isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
1172 | edge->status = SYNC; | |
1173 | } | |
1174 | ||
1175 | return LSP_ITER_CONTINUE; | |
1176 | } | |
1177 | ||
1178 | /** | |
1179 | * Parse Extended IP Reachability or MT IPv6 Reachability TLVs and create or | |
1180 | * update the corresponding Link State Subnet and Prefix. | |
1181 | * | |
1182 | * @param prefix Prefix associated to this subnet | |
1183 | * @param metric Metric of this prefix | |
1184 | * @param external Boolean to indicate if the prefix is external | |
1185 | * @param subtlvs Subtlvs if any (mostly Segment Routing ID) | |
1186 | * @param arg IS-IS TE argument (TED, Vertex, and export indication) | |
1187 | * | |
1188 | * @return 0 if success, -1 otherwise | |
1189 | */ | |
1190 | static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, | |
1191 | bool external, struct isis_subtlvs *subtlvs, | |
1192 | void *arg) | |
1193 | { | |
1194 | struct isis_te_args *args = (struct isis_te_args *)arg; | |
1195 | struct ls_vertex *vertex; | |
1196 | struct ls_subnet *subnet; | |
1197 | struct ls_prefix *ls_pref; | |
1198 | struct listnode *node; | |
1199 | struct ls_edge *edge; | |
1200 | struct ls_standard *std = NULL; | |
1201 | struct prefix p; | |
1202 | ||
1203 | /* Sanity Check */ | |
1204 | if (!args || !prefix) | |
1205 | return LSP_ITER_CONTINUE; | |
1206 | ||
1207 | te_debug(" |- Process Extended %s Reachability %pFX", | |
1208 | prefix->family == AF_INET ? "IP" : "IPv6", prefix); | |
1209 | ||
1210 | vertex = args->vertex; | |
1211 | ||
1212 | /* | |
1213 | * Prefix with mask different from /32 or /128 are advertised by at | |
1214 | * least 2 nodes. To avoid subnet attached to undetermined vertex, and | |
1215 | * gives the possibility to send the information to client e.g. BGP for | |
1216 | * Link State advertisement, we adjust the prefix with the corresponding | |
1217 | * IP address of the belonging interface when it is available. Other | |
1218 | * prefixes are kept unchanged. | |
1219 | */ | |
1220 | if (prefix->family == AF_INET && prefix->prefixlen < IPV4_MAX_BITLEN) { | |
1221 | std = NULL; | |
1222 | for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) { | |
1223 | if (!CHECK_FLAG(edge->attributes->flags, | |
1224 | LS_ATTR_LOCAL_ADDR)) | |
1225 | continue; | |
1226 | ||
1227 | p.u.prefix4 = edge->attributes->standard.local; | |
1228 | p.family = AF_INET; | |
1229 | p.prefixlen = prefix->prefixlen; | |
1230 | apply_mask_ipv4((struct prefix_ipv4 *)&p); | |
1231 | if (IPV4_ADDR_SAME(&p.u.prefix4, &prefix->u.prefix4)) { | |
1232 | std = &edge->attributes->standard; | |
1233 | break; | |
1234 | } | |
1235 | } | |
1236 | if (std) | |
1237 | p.u.prefix4 = std->local; | |
1238 | ||
1239 | } else if (prefix->family == AF_INET6 | |
1240 | && prefix->prefixlen < IPV6_MAX_BITLEN) { | |
1241 | std = NULL; | |
1242 | for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) { | |
1243 | if (!CHECK_FLAG(edge->attributes->flags, | |
1244 | LS_ATTR_LOCAL_ADDR6)) | |
1245 | continue; | |
1246 | ||
1247 | p.u.prefix6 = edge->attributes->standard.local6; | |
1248 | p.family = AF_INET6; | |
1249 | p.prefixlen = prefix->prefixlen; | |
1250 | apply_mask_ipv6((struct prefix_ipv6 *)&p); | |
1251 | if (IPV6_ADDR_SAME(&p.u.prefix6, &prefix->u.prefix6)) { | |
1252 | std = &edge->attributes->standard; | |
1253 | break; | |
1254 | } | |
1255 | } | |
1256 | if (std) | |
1257 | p.u.prefix6 = std->local6; | |
1258 | } | |
1259 | if (!std) | |
14678bfa | 1260 | prefix_copy(&p, prefix); |
8ab42c42 OD |
1261 | else { |
1262 | /* Remove old subnet if any before prefix adjustment */ | |
b5894669 | 1263 | subnet = ls_find_subnet(args->ted, prefix); |
8ab42c42 OD |
1264 | if (subnet) { |
1265 | if (args->export) { | |
1266 | subnet->status = DELETE; | |
1267 | isis_te_export(LS_MSG_TYPE_PREFIX, subnet); | |
1268 | } | |
1269 | te_debug(" |- Remove subnet with prefix %pFX", | |
1270 | &subnet->key); | |
1271 | ls_subnet_del_all(args->ted, subnet); | |
1272 | } | |
ed6189a9 OD |
1273 | te_debug(" |- Adjust prefix %pFX with local address to: %pFX", |
1274 | prefix, &p); | |
8ab42c42 | 1275 | } |
ed6189a9 OD |
1276 | |
1277 | /* Search existing Subnet in TED ... */ | |
b5894669 | 1278 | subnet = ls_find_subnet(args->ted, &p); |
ed6189a9 OD |
1279 | /* ... and create a new Subnet if not found */ |
1280 | if (!subnet) { | |
b5894669 | 1281 | ls_pref = ls_prefix_new(vertex->node->adv, &p); |
ed6189a9 | 1282 | subnet = ls_subnet_add(args->ted, ls_pref); |
8ab42c42 | 1283 | /* Stop processing if we are unable to create a new subnet */ |
ed6189a9 OD |
1284 | if (!subnet) |
1285 | return LSP_ITER_CONTINUE; | |
1286 | } | |
1287 | ls_pref = subnet->ls_pref; | |
1288 | ||
1289 | te_debug(" |- %s Subnet from prefix %pFX", | |
1290 | subnet->status == NEW ? "Create" : "Found", &p); | |
1291 | ||
1292 | /* Update Metric */ | |
1293 | if (!CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC) | |
1294 | || (ls_pref->metric != metric)) { | |
1295 | ls_pref->metric = metric; | |
1296 | SET_FLAG(ls_pref->flags, LS_PREF_METRIC); | |
1297 | if (subnet->status != NEW) | |
1298 | subnet->status = UPDATE; | |
1299 | } else { | |
1300 | if (subnet->status == ORPHAN) | |
1301 | subnet->status = SYNC; | |
1302 | } | |
1303 | ||
1304 | /* Update Prefix SID if any */ | |
1305 | if (subtlvs && subtlvs->prefix_sids.count != 0) { | |
1306 | struct isis_prefix_sid *psid; | |
1307 | struct ls_sid sr = {}; | |
1308 | ||
1309 | psid = (struct isis_prefix_sid *)subtlvs->prefix_sids.head; | |
1310 | sr.algo = psid->algorithm; | |
1311 | sr.sid_flag = psid->flags; | |
1312 | sr.sid = psid->value; | |
1313 | ||
1314 | if (!CHECK_FLAG(ls_pref->flags, LS_PREF_SR) | |
1315 | || !memcmp(&ls_pref->sr, &sr, sizeof(struct ls_sid))) { | |
1316 | memcpy(&ls_pref->sr, &sr, sizeof(struct ls_sid)); | |
1317 | SET_FLAG(ls_pref->flags, LS_PREF_SR); | |
1318 | if (subnet->status != NEW) | |
1319 | subnet->status = UPDATE; | |
1320 | } else { | |
1321 | if (subnet->status == ORPHAN) | |
1322 | subnet->status = SYNC; | |
1323 | } | |
1324 | } else { | |
1325 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) { | |
1326 | UNSET_FLAG(ls_pref->flags, LS_PREF_SR); | |
1327 | if (subnet->status != NEW) | |
1328 | subnet->status = UPDATE; | |
1329 | } else { | |
1330 | if (subnet->status == ORPHAN) | |
1331 | subnet->status = SYNC; | |
1332 | } | |
1333 | } | |
1334 | ||
1335 | /* Update status and Export Link State Edge if needed */ | |
1336 | if (subnet->status != SYNC) { | |
1337 | if (args->export) | |
1338 | isis_te_export(LS_MSG_TYPE_PREFIX, subnet); | |
1339 | subnet->status = SYNC; | |
1340 | } | |
1341 | ||
1342 | return LSP_ITER_CONTINUE; | |
1343 | } | |
1344 | ||
1345 | /** | |
1346 | * Parse ISIS LSP to fulfill the Link State Database | |
1347 | * | |
1348 | * @param ted Link State Database | |
1349 | * @param lsp ISIS Link State PDU | |
1350 | */ | |
1351 | static void isis_te_parse_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp) | |
1352 | { | |
1353 | struct ls_ted *ted; | |
1354 | struct ls_vertex *vertex; | |
1355 | struct ls_edge *edge; | |
1356 | struct ls_subnet *subnet; | |
1357 | struct listnode *node; | |
1358 | struct isis_te_args args; | |
1359 | ||
1360 | /* Sanity Check */ | |
1361 | if (!IS_MPLS_TE(mta) || !mta->ted || !lsp) | |
1362 | return; | |
1363 | ||
1364 | ted = mta->ted; | |
1365 | ||
5d39a819 OD |
1366 | te_debug("ISIS-TE(%s): Parse LSP %pSY", lsp->area->area_tag, |
1367 | lsp->hdr.lsp_id); | |
ed6189a9 OD |
1368 | |
1369 | /* First parse LSP to obtain the corresponding Vertex */ | |
1370 | vertex = lsp_to_vertex(ted, lsp); | |
1371 | if (!vertex) { | |
5d39a819 OD |
1372 | zlog_warn("Unable to build Vertex from LSP %pSY. Abort!", |
1373 | lsp->hdr.lsp_id); | |
ed6189a9 OD |
1374 | return; |
1375 | } | |
1376 | ||
1377 | /* Check if Vertex has been modified */ | |
1378 | if (vertex->status != SYNC) { | |
1379 | /* Vertex is out of sync: export it if requested */ | |
1380 | if (IS_EXPORT_TE(mta)) | |
1381 | isis_te_export(LS_MSG_TYPE_NODE, vertex); | |
1382 | vertex->status = SYNC; | |
1383 | } | |
1384 | ||
1385 | /* Mark outgoing Edges and Subnets as ORPHAN to detect deletion */ | |
1386 | for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) | |
1387 | edge->status = ORPHAN; | |
1388 | ||
1389 | for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet)) | |
1390 | subnet->status = ORPHAN; | |
1391 | ||
1392 | /* Process all Extended Reachability in LSP (all fragments) */ | |
1393 | args.ted = ted; | |
1394 | args.vertex = vertex; | |
1395 | args.export = mta->export; | |
1396 | isis_lsp_iterate_is_reach(lsp, ISIS_MT_IPV4_UNICAST, lsp_to_edge_cb, | |
1397 | &args); | |
1398 | ||
1399 | isis_lsp_iterate_is_reach(lsp, ISIS_MT_IPV6_UNICAST, lsp_to_edge_cb, | |
1400 | &args); | |
1401 | ||
1402 | /* Process all Extended IP (v4 & v6) in LSP (all fragments) */ | |
1403 | isis_lsp_iterate_ip_reach(lsp, AF_INET, ISIS_MT_IPV4_UNICAST, | |
1404 | lsp_to_subnet_cb, &args); | |
1405 | isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV6_UNICAST, | |
1406 | lsp_to_subnet_cb, &args); | |
1407 | isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV4_UNICAST, | |
1408 | lsp_to_subnet_cb, &args); | |
1409 | ||
1410 | /* Clean remaining Orphan Edges or Subnets */ | |
1411 | if (IS_EXPORT_TE(mta)) | |
1412 | ls_vertex_clean(ted, vertex, zclient); | |
1413 | else | |
1414 | ls_vertex_clean(ted, vertex, NULL); | |
1415 | } | |
1416 | ||
1417 | /** | |
1418 | * Delete Link State Database Vertex, Edge & Prefix that correspond to this | |
1419 | * ISIS Link State PDU | |
1420 | * | |
1421 | * @param ted Link State Database | |
1422 | * @param lsp ISIS Link State PDU | |
1423 | */ | |
1424 | static void isis_te_delete_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp) | |
1425 | { | |
1426 | struct ls_ted *ted; | |
1427 | struct ls_vertex *vertex = NULL; | |
1428 | struct ls_node lnode = {}; | |
1429 | struct ls_edge *edge; | |
1430 | struct ls_subnet *subnet; | |
1431 | struct listnode *nnode, *node; | |
1432 | ||
1433 | /* Sanity Check */ | |
1434 | if (!IS_MPLS_TE(mta) || !mta->ted || !lsp) | |
1435 | return; | |
1436 | ||
5d39a819 OD |
1437 | te_debug("ISIS-TE(%s): Delete Link State TED objects from LSP %pSY", |
1438 | lsp->area->area_tag, lsp->hdr.lsp_id); | |
ed6189a9 OD |
1439 | |
1440 | /* Compute Link State Node ID from IS-IS sysID ... */ | |
1441 | if (lsp->level == ISIS_LEVEL1) | |
1442 | lnode.adv.origin = ISIS_L1; | |
1443 | else | |
1444 | lnode.adv.origin = ISIS_L2; | |
1445 | memcpy(&lnode.adv.id.iso.sys_id, &lsp->hdr.lsp_id, ISIS_SYS_ID_LEN); | |
1446 | lnode.adv.id.iso.level = lsp->level; | |
1447 | ted = mta->ted; | |
1448 | /* ... and search the corresponding vertex */ | |
1449 | vertex = ls_find_vertex_by_id(ted, lnode.adv); | |
1450 | if (!vertex) | |
1451 | return; | |
1452 | ||
1453 | te_debug(" |- Delete Vertex %s", vertex->node->name); | |
1454 | ||
1455 | /* | |
1456 | * We can't use the ls_vertex_del_all() function if export TE is set, | |
1457 | * as we must first advertise the client daemons of each removal. | |
1458 | */ | |
1459 | /* Remove outgoing Edges */ | |
1460 | for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) { | |
1461 | if (IS_EXPORT_TE(mta)) { | |
1462 | edge->status = DELETE; | |
1463 | isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
1464 | } | |
1465 | ls_edge_del_all(ted, edge); | |
1466 | } | |
1467 | ||
1468 | /* Disconnect incoming Edges */ | |
1469 | for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) { | |
1470 | ls_disconnect(vertex, edge, false); | |
1471 | if (edge->source == NULL) { | |
1472 | if (IS_EXPORT_TE(mta)) { | |
1473 | edge->status = DELETE; | |
1474 | isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
1475 | } | |
1476 | ls_edge_del_all(ted, edge); | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | /* Remove subnets */ | |
1481 | for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) { | |
1482 | if (IS_EXPORT_TE(mta)) { | |
1483 | subnet->status = DELETE; | |
1484 | isis_te_export(LS_MSG_TYPE_PREFIX, subnet); | |
1485 | } | |
1486 | ls_subnet_del_all(ted, subnet); | |
1487 | } | |
1488 | ||
1489 | /* Then remove Link State Node */ | |
1490 | if (IS_EXPORT_TE(mta)) { | |
1491 | vertex->status = DELETE; | |
1492 | isis_te_export(LS_MSG_TYPE_NODE, vertex); | |
1493 | } | |
1494 | ls_node_del(vertex->node); | |
1495 | ||
1496 | /* Finally, remove Vertex */ | |
1497 | ls_vertex_del(ted, vertex); | |
1498 | } | |
1499 | ||
1500 | /** | |
1501 | * Process ISIS LSP according to the event to add, update or remove | |
1502 | * corresponding vertex, edge and prefix in the Link State database. | |
1503 | * Since LSP could be fragmented, the function starts by searching the root LSP | |
1504 | * to retrieve the complete LSP, including eventual fragment before processing | |
1505 | * all of them. | |
1506 | * | |
1507 | * @param lsp ISIS Link State PDU | |
1508 | * @param event LSP event: ADD, UPD, INC & DEL (TICK are ignored) | |
1509 | * | |
1510 | */ | |
1511 | void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event) | |
1512 | { | |
1513 | struct isis_area *area; | |
1514 | struct isis_lsp *lsp0; | |
1515 | ||
1516 | /* Sanity check */ | |
1517 | if (!lsp || !lsp->area) | |
1518 | return; | |
1519 | ||
1520 | area = lsp->area; | |
1521 | if (!IS_MPLS_TE(area->mta)) | |
1522 | return; | |
1523 | ||
1524 | /* Adjust LSP0 in case of fragment */ | |
1525 | if (LSP_FRAGMENT(lsp->hdr.lsp_id)) | |
1526 | lsp0 = lsp->lspu.zero_lsp; | |
1527 | else | |
1528 | lsp0 = lsp; | |
1529 | ||
1530 | /* Then process event */ | |
1531 | switch (event) { | |
1532 | case LSP_ADD: | |
1533 | case LSP_UPD: | |
1534 | case LSP_INC: | |
1535 | isis_te_parse_lsp(area->mta, lsp0); | |
1536 | break; | |
1537 | case LSP_DEL: | |
1538 | isis_te_delete_lsp(area->mta, lsp0); | |
1539 | break; | |
a348c945 DS |
1540 | case LSP_UNKNOWN: |
1541 | case LSP_TICK: | |
ed6189a9 OD |
1542 | break; |
1543 | } | |
1544 | } | |
1545 | ||
1546 | /** | |
1547 | * Send the whole Link State Traffic Engineering Database to the consumer that | |
1548 | * request it through a ZAPI Link State Synchronous Opaque Message. | |
1549 | * | |
1550 | * @param info ZAPI Opaque message | |
1551 | * | |
1552 | * @return 0 if success, -1 otherwise | |
1553 | */ | |
1554 | int isis_te_sync_ted(struct zapi_opaque_reg_info dst) | |
1555 | { | |
1556 | struct listnode *node, *inode; | |
1557 | struct isis *isis; | |
1558 | struct isis_area *area; | |
1559 | struct mpls_te_area *mta; | |
1560 | int rc = -1; | |
1561 | ||
1562 | te_debug("ISIS-TE(%s): Received TED synchro from client %d", __func__, | |
1563 | dst.proto); | |
1564 | /* For each area, send TED if TE distribution is enabled */ | |
1565 | for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { | |
1566 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { | |
1567 | mta = area->mta; | |
1568 | if (IS_MPLS_TE(mta) && IS_EXPORT_TE(mta)) { | |
1569 | te_debug(" |- Export TED from area %s", | |
1570 | area->area_tag); | |
1571 | rc = ls_sync_ted(mta->ted, zclient, &dst); | |
1572 | if (rc != 0) | |
1573 | return rc; | |
1574 | } | |
1575 | } | |
1576 | } | |
1577 | ||
1578 | return rc; | |
1579 | } | |
1580 | ||
1581 | /** | |
1582 | * Initialize the Link State database from the LSP already stored for this area | |
1583 | * | |
1584 | * @param area ISIS area | |
1585 | */ | |
1586 | void isis_te_init_ted(struct isis_area *area) | |
1587 | { | |
1588 | struct isis_lsp *lsp; | |
1589 | ||
1590 | /* Iterate over all lsp. */ | |
1591 | for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) | |
1592 | frr_each (lspdb, &area->lspdb[level - 1], lsp) | |
1593 | isis_te_parse_lsp(area->mta, lsp); | |
1594 | } | |
1595 | ||
78dfa0c7 | 1596 | /* Following are vty command functions */ |
ef020087 CF |
1597 | #ifndef FABRICD |
1598 | ||
173f8887 OD |
1599 | static void show_router_id(struct vty *vty, struct isis_area *area) |
1600 | { | |
1601 | bool no_match = true; | |
1602 | ||
1603 | vty_out(vty, "Area %s:\n", area->area_tag); | |
1604 | if (area->mta->router_id.s_addr != 0) { | |
1605 | vty_out(vty, " MPLS-TE IPv4 Router-Address: %pI4\n", | |
1606 | &area->mta->router_id); | |
1607 | no_match = false; | |
1608 | } | |
1609 | if (!IN6_IS_ADDR_UNSPECIFIED(&area->mta->router_id_ipv6)) { | |
1610 | vty_out(vty, " MPLS-TE IPv6 Router-Address: %pI6\n", | |
1611 | &area->mta->router_id_ipv6); | |
1612 | no_match = false; | |
1613 | } | |
1614 | if (no_match) | |
1615 | vty_out(vty, " N/A\n"); | |
1616 | } | |
1617 | ||
eab88f36 K |
1618 | DEFUN(show_isis_mpls_te_router, |
1619 | show_isis_mpls_te_router_cmd, | |
1620 | "show " PROTO_NAME " [vrf <NAME|all>] mpls-te router", | |
1621 | SHOW_STR | |
1622 | PROTO_HELP | |
1623 | VRF_CMD_HELP_STR "All VRFs\n" | |
1624 | MPLS_TE_STR "Router information\n") | |
f8c06e2c | 1625 | { |
d62a17ae | 1626 | |
36944791 | 1627 | struct listnode *anode, *inode; |
2e2a8b91 | 1628 | struct isis_area *area; |
eab88f36 K |
1629 | struct isis *isis = NULL; |
1630 | const char *vrf_name = VRF_DEFAULT_NAME; | |
1631 | bool all_vrf = false; | |
1632 | int idx_vrf = 0; | |
2e2a8b91 | 1633 | |
eab88f36 | 1634 | if (!im) { |
2e2a8b91 OD |
1635 | vty_out(vty, "IS-IS Routing Process not enabled\n"); |
1636 | return CMD_SUCCESS; | |
1637 | } | |
eab88f36 K |
1638 | ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); |
1639 | if (vrf_name) { | |
1640 | if (all_vrf) { | |
36944791 | 1641 | for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { |
eab88f36 K |
1642 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, |
1643 | anode, area)) { | |
1644 | if (!IS_MPLS_TE(area->mta)) | |
1645 | continue; | |
1646 | ||
173f8887 | 1647 | show_router_id(vty, area); |
eab88f36 K |
1648 | } |
1649 | } | |
1650 | return 0; | |
1651 | } | |
1652 | isis = isis_lookup_by_vrfname(vrf_name); | |
1653 | if (isis != NULL) { | |
1654 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, | |
1655 | area)) { | |
1656 | ||
1657 | if (!IS_MPLS_TE(area->mta)) | |
1658 | continue; | |
1659 | ||
173f8887 | 1660 | show_router_id(vty, area); |
eab88f36 K |
1661 | } |
1662 | } | |
2e2a8b91 | 1663 | } |
d62a17ae | 1664 | |
1665 | return CMD_SUCCESS; | |
f8c06e2c OD |
1666 | } |
1667 | ||
1b3f47d0 OD |
1668 | static void show_ext_sub(struct vty *vty, char *name, |
1669 | struct isis_ext_subtlvs *ext) | |
f8c06e2c | 1670 | { |
af8ac8f9 | 1671 | struct sbuf buf; |
1b3f47d0 | 1672 | char ibuf[PREFIX2STR_BUFFER]; |
af8ac8f9 CF |
1673 | |
1674 | sbuf_init(&buf, NULL, 0); | |
d62a17ae | 1675 | |
1b3f47d0 | 1676 | if (!ext || ext->status == EXT_DISABLE) |
2e2a8b91 | 1677 | return; |
d62a17ae | 1678 | |
2e2a8b91 | 1679 | vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name); |
d62a17ae | 1680 | |
2e2a8b91 | 1681 | sbuf_reset(&buf); |
231e94e3 | 1682 | |
1b3f47d0 | 1683 | if (IS_SUBTLV(ext, EXT_ADM_GRP)) |
6cde4b45 | 1684 | sbuf_push(&buf, 4, "Administrative Group: 0x%x\n", |
1b3f47d0 OD |
1685 | ext->adm_group); |
1686 | if (IS_SUBTLV(ext, EXT_LLRI)) { | |
6cde4b45 | 1687 | sbuf_push(&buf, 4, "Link Local ID: %u\n", |
1b3f47d0 | 1688 | ext->local_llri); |
6cde4b45 | 1689 | sbuf_push(&buf, 4, "Link Remote ID: %u\n", |
1b3f47d0 OD |
1690 | ext->remote_llri); |
1691 | } | |
1692 | if (IS_SUBTLV(ext, EXT_LOCAL_ADDR)) | |
a854ea43 MS |
1693 | sbuf_push(&buf, 4, "Local Interface IP Address(es): %pI4\n", |
1694 | &ext->local_addr); | |
1b3f47d0 | 1695 | if (IS_SUBTLV(ext, EXT_NEIGH_ADDR)) |
a854ea43 MS |
1696 | sbuf_push(&buf, 4, "Remote Interface IP Address(es): %pI4\n", |
1697 | &ext->neigh_addr); | |
1b3f47d0 OD |
1698 | if (IS_SUBTLV(ext, EXT_LOCAL_ADDR6)) |
1699 | sbuf_push(&buf, 4, "Local Interface IPv6 Address(es): %s\n", | |
1700 | inet_ntop(AF_INET6, &ext->local_addr6, ibuf, | |
1701 | PREFIX2STR_BUFFER)); | |
1702 | if (IS_SUBTLV(ext, EXT_NEIGH_ADDR6)) | |
1703 | sbuf_push(&buf, 4, "Remote Interface IPv6 Address(es): %s\n", | |
1704 | inet_ntop(AF_INET6, &ext->local_addr6, ibuf, | |
1705 | PREFIX2STR_BUFFER)); | |
1706 | if (IS_SUBTLV(ext, EXT_MAX_BW)) | |
1707 | sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n", | |
1708 | ext->max_bw); | |
1709 | if (IS_SUBTLV(ext, EXT_MAX_RSV_BW)) | |
1710 | sbuf_push(&buf, 4, | |
1711 | "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", | |
1712 | ext->max_rsv_bw); | |
1713 | if (IS_SUBTLV(ext, EXT_UNRSV_BW)) { | |
1714 | sbuf_push(&buf, 4, "Unreserved Bandwidth:\n"); | |
1715 | for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { | |
1716 | sbuf_push(&buf, 4 + 2, | |
1717 | "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", | |
1718 | j, ext->unrsv_bw[j], | |
1719 | j + 1, ext->unrsv_bw[j + 1]); | |
1720 | } | |
1721 | } | |
1722 | if (IS_SUBTLV(ext, EXT_TE_METRIC)) | |
1723 | sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n", | |
1724 | ext->te_metric); | |
1725 | if (IS_SUBTLV(ext, EXT_RMT_AS)) | |
1726 | sbuf_push(&buf, 4, | |
6cde4b45 | 1727 | "Inter-AS TE Remote AS number: %u\n", |
1b3f47d0 OD |
1728 | ext->remote_as); |
1729 | if (IS_SUBTLV(ext, EXT_RMT_IP)) | |
1730 | sbuf_push(&buf, 4, | |
a854ea43 MS |
1731 | "Inter-AS TE Remote ASBR IP address: %pI4\n", |
1732 | &ext->remote_ip); | |
1b3f47d0 OD |
1733 | if (IS_SUBTLV(ext, EXT_DELAY)) |
1734 | sbuf_push(&buf, 4, | |
6cde4b45 | 1735 | "%s Average Link Delay: %u (micro-sec)\n", |
1b3f47d0 | 1736 | IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal", |
129ad38b | 1737 | ext->delay & TE_EXT_MASK); |
1b3f47d0 | 1738 | if (IS_SUBTLV(ext, EXT_MM_DELAY)) { |
6cde4b45 | 1739 | sbuf_push(&buf, 4, "%s Min/Max Link Delay: %u / %u (micro-sec)\n", |
1b3f47d0 OD |
1740 | IS_ANORMAL(ext->min_delay) ? "Anomalous" : "Normal", |
1741 | ext->min_delay & TE_EXT_MASK, | |
1742 | ext->max_delay & TE_EXT_MASK); | |
1743 | } | |
1744 | if (IS_SUBTLV(ext, EXT_DELAY_VAR)) | |
1745 | sbuf_push(&buf, 4, | |
6cde4b45 | 1746 | "Delay Variation: %u (micro-sec)\n", |
1b3f47d0 OD |
1747 | ext->delay_var & TE_EXT_MASK); |
1748 | if (IS_SUBTLV(ext, EXT_PKT_LOSS)) | |
1749 | sbuf_push(&buf, 4, "%s Link Packet Loss: %g (%%)\n", | |
1750 | IS_ANORMAL(ext->pkt_loss) ? "Anomalous" : "Normal", | |
1751 | (float)((ext->pkt_loss & TE_EXT_MASK) | |
1752 | * LOSS_PRECISION)); | |
1753 | if (IS_SUBTLV(ext, EXT_RES_BW)) | |
1754 | sbuf_push(&buf, 4, | |
1755 | "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", | |
1756 | ext->res_bw); | |
1757 | if (IS_SUBTLV(ext, EXT_AVA_BW)) | |
1758 | sbuf_push(&buf, 4, | |
1759 | "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", | |
1760 | ext->ava_bw); | |
1761 | if (IS_SUBTLV(ext, EXT_USE_BW)) | |
1762 | sbuf_push(&buf, 4, | |
1763 | "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", | |
1764 | ext->use_bw); | |
af8ac8f9 | 1765 | |
2e2a8b91 OD |
1766 | vty_multiline(vty, "", "%s", sbuf_buf(&buf)); |
1767 | vty_out(vty, "---------------\n\n"); | |
d62a17ae | 1768 | |
af8ac8f9 | 1769 | sbuf_free(&buf); |
d62a17ae | 1770 | return; |
f8c06e2c OD |
1771 | } |
1772 | ||
1773 | DEFUN (show_isis_mpls_te_interface, | |
1774 | show_isis_mpls_te_interface_cmd, | |
7c0cbd0e | 1775 | "show " PROTO_NAME " mpls-te interface [INTERFACE]", |
f8c06e2c | 1776 | SHOW_STR |
7c0cbd0e | 1777 | PROTO_HELP |
f8c06e2c OD |
1778 | MPLS_TE_STR |
1779 | "Interface information\n" | |
1780 | "Interface name\n") | |
1781 | { | |
36944791 | 1782 | struct listnode *anode, *cnode, *inode; |
2e2a8b91 OD |
1783 | struct isis_area *area; |
1784 | struct isis_circuit *circuit; | |
231e94e3 | 1785 | struct interface *ifp; |
2e2a8b91 | 1786 | int idx_interface = 4; |
eab88f36 | 1787 | struct isis *isis = NULL; |
d62a17ae | 1788 | |
eab88f36 | 1789 | if (!im) { |
2e2a8b91 OD |
1790 | vty_out(vty, "IS-IS Routing Process not enabled\n"); |
1791 | return CMD_SUCCESS; | |
d62a17ae | 1792 | } |
2e2a8b91 OD |
1793 | |
1794 | if (argc == idx_interface) { | |
1795 | /* Show All Interfaces. */ | |
36944791 | 1796 | for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { |
eab88f36 K |
1797 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, |
1798 | area)) { | |
2e2a8b91 | 1799 | |
eab88f36 K |
1800 | if (!IS_MPLS_TE(area->mta)) |
1801 | continue; | |
2e2a8b91 | 1802 | |
eab88f36 | 1803 | vty_out(vty, "Area %s:\n", area->area_tag); |
2e2a8b91 | 1804 | |
eab88f36 K |
1805 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, |
1806 | cnode, circuit)) | |
1807 | show_ext_sub(vty, | |
1808 | circuit->interface->name, | |
1809 | circuit->ext); | |
1810 | } | |
2e2a8b91 OD |
1811 | } |
1812 | } else { | |
1813 | /* Interface name is specified. */ | |
a36898e7 | 1814 | ifp = if_lookup_by_name(argv[idx_interface]->arg, VRF_DEFAULT); |
2e2a8b91 | 1815 | if (ifp == NULL) |
d62a17ae | 1816 | vty_out(vty, "No such interface name\n"); |
2e2a8b91 OD |
1817 | else { |
1818 | circuit = circuit_scan_by_ifp(ifp); | |
1819 | if (!circuit) | |
1820 | vty_out(vty, | |
1821 | "ISIS is not enabled on circuit %s\n", | |
1822 | ifp->name); | |
1823 | else | |
1b3f47d0 | 1824 | show_ext_sub(vty, ifp->name, circuit->ext); |
2e2a8b91 | 1825 | } |
d62a17ae | 1826 | } |
1827 | ||
1828 | return CMD_SUCCESS; | |
f8c06e2c | 1829 | } |
ed6189a9 OD |
1830 | |
1831 | /** | |
1832 | * Search Vertex in TED that corresponds to the given string that represent | |
1833 | * the ISO system ID in the forms <systemid/hostname>[.<pseudo-id>-<framenent>] | |
1834 | * | |
1835 | * @param ted Link State Database | |
1836 | * @param id ISO System ID | |
1837 | * @param isis Main reference to the isis daemon | |
1838 | * | |
1839 | * @return Vertex if found, NULL otherwise | |
1840 | */ | |
1841 | static struct ls_vertex *vertex_for_arg(struct ls_ted *ted, const char *id, | |
1842 | struct isis *isis) | |
1843 | { | |
1844 | char sysid[255] = {0}; | |
1845 | uint8_t number[3]; | |
1846 | const char *pos; | |
1847 | uint8_t lspid[ISIS_SYS_ID_LEN + 2] = {0}; | |
1848 | struct isis_dynhn *dynhn; | |
1849 | uint64_t key = 0; | |
1850 | ||
1851 | if (!id) | |
1852 | return NULL; | |
1853 | ||
1854 | /* | |
1855 | * extract fragment and pseudo id from the string argv | |
1856 | * in the forms: | |
1857 | * (a) <systemid/hostname>.<pseudo-id>-<framenent> or | |
1858 | * (b) <systemid/hostname>.<pseudo-id> or | |
1859 | * (c) <systemid/hostname> or | |
1860 | * Where systemid is in the form: | |
1861 | * xxxx.xxxx.xxxx | |
1862 | */ | |
1863 | strlcpy(sysid, id, sizeof(sysid)); | |
1864 | if (strlen(id) > 3) { | |
1865 | pos = id + strlen(id) - 3; | |
1866 | if (strncmp(pos, "-", 1) == 0) { | |
1867 | memcpy(number, ++pos, 2); | |
1868 | lspid[ISIS_SYS_ID_LEN + 1] = | |
1869 | (uint8_t)strtol((char *)number, NULL, 16); | |
1870 | pos -= 4; | |
1871 | if (strncmp(pos, ".", 1) != 0) | |
1872 | return NULL; | |
1873 | } | |
1874 | if (strncmp(pos, ".", 1) == 0) { | |
1875 | memcpy(number, ++pos, 2); | |
1876 | lspid[ISIS_SYS_ID_LEN] = | |
1877 | (uint8_t)strtol((char *)number, NULL, 16); | |
1878 | sysid[pos - id - 1] = '\0'; | |
1879 | } | |
1880 | } | |
1881 | ||
1882 | /* | |
1883 | * Try to find the lsp-id if the argv | |
1884 | * string is in | |
1885 | * the form | |
1886 | * hostname.<pseudo-id>-<fragment> | |
1887 | */ | |
1888 | if (sysid2buff(lspid, sysid)) { | |
1889 | key = sysid_to_key(lspid); | |
1890 | } else if ((dynhn = dynhn_find_by_name(isis, sysid))) { | |
1891 | memcpy(lspid, dynhn->id, ISIS_SYS_ID_LEN); | |
1892 | key = sysid_to_key(lspid); | |
1893 | } else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) { | |
1894 | memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN); | |
1895 | key = sysid_to_key(lspid); | |
1896 | } | |
1897 | ||
1898 | if (key == 0) | |
1899 | return NULL; | |
1900 | ||
1901 | return ls_find_vertex_by_key(ted, key); | |
1902 | } | |
1903 | ||
1904 | /** | |
1905 | * Show Link State Traffic Engineering Database extracted from IS-IS LSP. | |
1906 | * | |
1907 | * @param vty VTY output console | |
1908 | * @param argv Command line argument | |
1909 | * @param argc Number of command line argument | |
1910 | * @param ted Traffic Engineering Database | |
1911 | * @param isis isis Main reference to the isis daemon | |
1912 | * | |
1913 | * @return Command Success if OK, Command Warning otherwise | |
1914 | */ | |
1915 | static int show_ted(struct vty *vty, struct cmd_token *argv[], int argc, | |
1916 | struct isis_area *area, struct isis *isis) | |
1917 | { | |
1918 | int idx; | |
1919 | char *id; | |
1920 | struct in_addr ip_addr; | |
1921 | struct in6_addr ip6_addr; | |
1922 | struct prefix pref; | |
1923 | struct ls_ted *ted; | |
1924 | struct ls_vertex *vertex; | |
1925 | struct ls_edge *edge; | |
1926 | struct ls_subnet *subnet; | |
7564fcb8 | 1927 | struct ls_edge_key key; |
ed6189a9 OD |
1928 | bool detail = false; |
1929 | bool uj = use_json(argc, argv); | |
1930 | json_object *json = NULL; | |
1931 | ||
1932 | if (!IS_MPLS_TE(area->mta) || !area->mta->ted) { | |
1933 | vty_out(vty, "MPLS-TE is disabled for Area %s\n", | |
1934 | area->area_tag ? area->area_tag : "null"); | |
1935 | return CMD_SUCCESS; | |
1936 | } | |
1937 | ||
1938 | ted = area->mta->ted; | |
1939 | ||
1940 | if (uj) | |
1941 | json = json_object_new_object(); | |
1942 | else | |
1943 | vty_out(vty, "Area %s:\n", | |
1944 | area->area_tag ? area->area_tag : "null"); | |
1945 | ||
1946 | if (argv[argc - 1]->arg && strmatch(argv[argc - 1]->text, "detail")) | |
1947 | detail = true; | |
1948 | ||
1949 | idx = 4; | |
1950 | if (argv_find(argv, argc, "vertex", &idx)) { | |
1951 | /* Show Vertex */ | |
1952 | id = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg | |
1953 | : NULL; | |
1954 | if (!id) | |
1955 | vertex = NULL; | |
1956 | else if (!strncmp(id, "self", 4)) | |
1957 | vertex = ted->self; | |
1958 | else { | |
1959 | vertex = vertex_for_arg(ted, id, isis); | |
1960 | if (!vertex) { | |
1961 | vty_out(vty, "No vertex found for ID %s\n", id); | |
1962 | return CMD_WARNING; | |
1963 | } | |
1964 | } | |
1965 | ||
1966 | if (vertex) | |
1967 | ls_show_vertex(vertex, vty, json, detail); | |
1968 | else | |
1969 | ls_show_vertices(ted, vty, json, detail); | |
1970 | ||
1971 | } else if (argv_find(argv, argc, "edge", &idx)) { | |
1972 | /* Show Edge */ | |
1973 | if (argv_find(argv, argc, "A.B.C.D", &idx)) { | |
1974 | if (!inet_pton(AF_INET, argv[idx]->arg, &ip_addr)) { | |
1975 | vty_out(vty, | |
1976 | "Specified Edge ID %s is invalid\n", | |
1977 | argv[idx]->arg); | |
1978 | return CMD_WARNING_CONFIG_FAILED; | |
1979 | } | |
1980 | /* Get the Edge from the Link State Database */ | |
7564fcb8 OD |
1981 | key.family = AF_INET; |
1982 | IPV4_ADDR_COPY(&key.k.addr, &ip_addr); | |
ed6189a9 OD |
1983 | edge = ls_find_edge_by_key(ted, key); |
1984 | if (!edge) { | |
1985 | vty_out(vty, "No edge found for ID %pI4\n", | |
1986 | &ip_addr); | |
1987 | return CMD_WARNING; | |
1988 | } | |
1989 | } else if (argv_find(argv, argc, "X:X::X:X", &idx)) { | |
1990 | if (!inet_pton(AF_INET6, argv[idx]->arg, &ip6_addr)) { | |
1991 | vty_out(vty, | |
1992 | "Specified Edge ID %s is invalid\n", | |
1993 | argv[idx]->arg); | |
1994 | return CMD_WARNING_CONFIG_FAILED; | |
1995 | } | |
1996 | /* Get the Edge from the Link State Database */ | |
7564fcb8 OD |
1997 | key.family = AF_INET6; |
1998 | IPV6_ADDR_COPY(&key.k.addr6, &ip6_addr); | |
ed6189a9 OD |
1999 | edge = ls_find_edge_by_key(ted, key); |
2000 | if (!edge) { | |
2001 | vty_out(vty, "No edge found for ID %pI6\n", | |
2002 | &ip6_addr); | |
2003 | return CMD_WARNING; | |
2004 | } | |
2005 | } else | |
2006 | edge = NULL; | |
2007 | ||
2008 | if (edge) | |
2009 | ls_show_edge(edge, vty, json, detail); | |
2010 | else | |
2011 | ls_show_edges(ted, vty, json, detail); | |
2012 | ||
2013 | } else if (argv_find(argv, argc, "subnet", &idx)) { | |
2014 | /* Show Subnet */ | |
2015 | if (argv_find(argv, argc, "A.B.C.D/M", &idx)) { | |
2016 | if (!str2prefix(argv[idx]->arg, &pref)) { | |
2017 | vty_out(vty, "Invalid prefix format %s\n", | |
2018 | argv[idx]->arg); | |
2019 | return CMD_WARNING_CONFIG_FAILED; | |
2020 | } | |
2021 | /* Get the Subnet from the Link State Database */ | |
b5894669 | 2022 | subnet = ls_find_subnet(ted, &pref); |
ed6189a9 OD |
2023 | if (!subnet) { |
2024 | vty_out(vty, "No subnet found for ID %pFX\n", | |
2025 | &pref); | |
2026 | return CMD_WARNING; | |
2027 | } | |
2028 | } else if (argv_find(argv, argc, "X:X::X:X/M", &idx)) { | |
2029 | if (!str2prefix(argv[idx]->arg, &pref)) { | |
2030 | vty_out(vty, "Invalid prefix format %s\n", | |
2031 | argv[idx]->arg); | |
2032 | return CMD_WARNING_CONFIG_FAILED; | |
2033 | } | |
2034 | /* Get the Subnet from the Link State Database */ | |
b5894669 | 2035 | subnet = ls_find_subnet(ted, &pref); |
ed6189a9 OD |
2036 | if (!subnet) { |
2037 | vty_out(vty, "No subnet found for ID %pFX\n", | |
2038 | &pref); | |
2039 | return CMD_WARNING; | |
2040 | } | |
2041 | } else | |
2042 | subnet = NULL; | |
2043 | ||
2044 | if (subnet) | |
2045 | ls_show_subnet(subnet, vty, json, detail); | |
2046 | else | |
2047 | ls_show_subnets(ted, vty, json, detail); | |
2048 | ||
2049 | } else { | |
2050 | /* Show the complete TED */ | |
2051 | ls_show_ted(ted, vty, json, detail); | |
2052 | } | |
2053 | ||
3757f964 DA |
2054 | if (uj) |
2055 | vty_json(vty, json); | |
ed6189a9 OD |
2056 | |
2057 | return CMD_SUCCESS; | |
2058 | } | |
2059 | ||
2060 | /** | |
2061 | * Show ISIS Traffic Engineering Database | |
2062 | * | |
2063 | * @param vty VTY output console | |
2064 | * @param argv Command line argument | |
2065 | * @param argc Number of command line argument | |
2066 | * @param isis isis Main reference to the isis daemon | |
2067 | ||
2068 | * @return Command Success if OK, Command Warning otherwise | |
2069 | */ | |
2070 | static int show_isis_ted(struct vty *vty, struct cmd_token *argv[], int argc, | |
2071 | struct isis *isis) | |
2072 | { | |
2073 | struct listnode *node; | |
2074 | struct isis_area *area; | |
2075 | int rc; | |
2076 | ||
2077 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { | |
2078 | rc = show_ted(vty, argv, argc, area, isis); | |
2079 | if (rc != CMD_SUCCESS) | |
2080 | return rc; | |
2081 | } | |
2082 | return CMD_SUCCESS; | |
2083 | } | |
2084 | ||
2085 | DEFUN(show_isis_mpls_te_db, | |
2086 | show_isis_mpls_te_db_cmd, | |
2087 | "show " PROTO_NAME " [vrf <NAME|all>] mpls-te database [<vertex [WORD]|edge [A.B.C.D|X:X::X:X]|subnet [A.B.C.D/M|X:X::X:X/M]>] [detail|json]", | |
2088 | SHOW_STR PROTO_HELP VRF_CMD_HELP_STR | |
2089 | "All VRFs\n" | |
2090 | MPLS_TE_STR | |
2091 | "MPLS-TE database\n" | |
2092 | "MPLS-TE Vertex\n" | |
2093 | "MPLS-TE Vertex ID (as an ISO ID, hostname or \"self\")\n" | |
2094 | "MPLS-TE Edge\n" | |
2095 | "MPLS-TE Edge ID (as an IPv4 address)\n" | |
2096 | "MPLS-TE Edge ID (as an IPv6 address)\n" | |
2097 | "MPLS-TE Subnet\n" | |
2098 | "MPLS-TE Subnet ID (as an IPv4 prefix)\n" | |
2099 | "MPLS-TE Subnet ID (as an IPv6 prefix)\n" | |
2100 | "Detailed information\n" | |
2101 | JSON_STR) | |
2102 | { | |
2103 | int idx_vrf = 0; | |
2104 | const char *vrf_name = VRF_DEFAULT_NAME; | |
2105 | bool all_vrf = false; | |
2106 | struct listnode *node; | |
2107 | struct isis *isis; | |
2108 | int rc = CMD_WARNING; | |
2109 | ||
2110 | ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); | |
2111 | if (vrf_name) { | |
2112 | if (all_vrf) { | |
2113 | for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { | |
2114 | rc = show_isis_ted(vty, argv, argc, isis); | |
2115 | if (rc != CMD_SUCCESS) | |
2116 | return rc; | |
2117 | } | |
2118 | return CMD_SUCCESS; | |
2119 | } | |
2120 | isis = isis_lookup_by_vrfname(vrf_name); | |
2121 | if (isis) | |
2122 | rc = show_isis_ted(vty, argv, argc, isis); | |
2123 | } | |
2124 | ||
2125 | return rc; | |
2126 | } | |
2127 | ||
2128 | #endif /* #ifndef FRABRICD */ | |
f8c06e2c OD |
2129 | |
2130 | /* Initialize MPLS_TE */ | |
d62a17ae | 2131 | void isis_mpls_te_init(void) |
f8c06e2c OD |
2132 | { |
2133 | ||
1b3f47d0 OD |
2134 | /* Register Circuit and Adjacency hook */ |
2135 | hook_register(isis_if_new_hook, isis_mpls_te_update); | |
173f8887 OD |
2136 | hook_register(isis_adj_ip_enabled_hook, isis_mpls_te_adj_ip_enabled); |
2137 | hook_register(isis_adj_ip_disabled_hook, isis_mpls_te_adj_ip_disabled); | |
1b3f47d0 | 2138 | |
ef020087 | 2139 | #ifndef FABRICD |
d62a17ae | 2140 | /* Register new VTY commands */ |
2141 | install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd); | |
2142 | install_element(VIEW_NODE, &show_isis_mpls_te_interface_cmd); | |
ed6189a9 | 2143 | install_element(VIEW_NODE, &show_isis_mpls_te_db_cmd); |
ef020087 | 2144 | #endif |
f8c06e2c | 2145 | |
d62a17ae | 2146 | return; |
f8c06e2c | 2147 | } |