]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1cbf96a8 | 2 | /** |
3 | * isis_ldp_sync.c: ISIS LDP-IGP Sync handling routines | |
4 | * Copyright (C) 2020 Volta Networks, Inc. | |
1cbf96a8 | 5 | */ |
6 | ||
7 | #include <zebra.h> | |
8 | #include <string.h> | |
9 | ||
10 | #include "monotime.h" | |
11 | #include "memory.h" | |
24a58196 | 12 | #include "frrevent.h" |
1cbf96a8 | 13 | #include "prefix.h" |
14 | #include "table.h" | |
15 | #include "vty.h" | |
16 | #include "command.h" | |
17 | #include "plist.h" | |
18 | #include "log.h" | |
19 | #include "zclient.h" | |
20 | #include <lib/json.h> | |
21 | #include "defaults.h" | |
22 | #include "ldp_sync.h" | |
23 | ||
24 | #include "isisd/isis_constants.h" | |
25 | #include "isisd/isis_common.h" | |
26 | #include "isisd/isis_flags.h" | |
27 | #include "isisd/isis_circuit.h" | |
28 | #include "isisd/isis_lsp.h" | |
29 | #include "isisd/isis_pdu.h" | |
30 | #include "isisd/isis_network.h" | |
31 | #include "isisd/isis_misc.h" | |
32 | #include "isisd/isis_constants.h" | |
33 | #include "isisd/isis_adjacency.h" | |
34 | #include "isisd/isis_dr.h" | |
35 | #include "isisd/isisd.h" | |
36 | #include "isisd/isis_csm.h" | |
37 | #include "isisd/isis_events.h" | |
38 | #include "isisd/isis_te.h" | |
39 | #include "isisd/isis_mt.h" | |
40 | #include "isisd/isis_errors.h" | |
41 | #include "isisd/isis_tx_queue.h" | |
42 | #include "isisd/isis_nb.h" | |
43 | #include "isisd/isis_ldp_sync.h" | |
44 | ||
45 | extern struct zclient *zclient; | |
46 | ||
47 | /* | |
48 | * LDP-SYNC msg between IGP and LDP | |
49 | */ | |
50 | int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state) | |
51 | { | |
52 | struct interface *ifp; | |
53 | struct isis_circuit *circuit = NULL; | |
54 | struct isis_area *area; | |
1cbf96a8 | 55 | |
56 | /* lookup circuit */ | |
57 | ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT); | |
58 | if (ifp == NULL) | |
59 | return 0; | |
60 | ||
ec62fbaa IR |
61 | circuit = ifp->info; |
62 | if (circuit == NULL) | |
63 | return 0; | |
1cbf96a8 | 64 | |
65 | /* if isis is not enabled or LDP-SYNC is not configured ignore */ | |
ec62fbaa IR |
66 | area = circuit->area; |
67 | if (area == NULL | |
68 | || !CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
1cbf96a8 | 69 | return 0; |
70 | ||
71 | /* received ldp-sync interface state from LDP */ | |
11106e28 | 72 | ils_debug("%s: rcvd %s from LDP if %s", __func__, |
1cbf96a8 | 73 | state.sync_start ? "sync-start" : "sync-complete", ifp->name); |
74 | if (state.sync_start) | |
75 | isis_ldp_sync_if_start(circuit, false); | |
76 | else | |
77 | isis_ldp_sync_if_complete(circuit); | |
78 | ||
79 | return 0; | |
80 | } | |
81 | ||
82 | int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce) | |
83 | { | |
84 | struct isis_area *area; | |
ec62fbaa | 85 | struct listnode *anode, *cnode; |
1cbf96a8 | 86 | struct isis_circuit *circuit; |
87 | struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); | |
88 | ||
ec62fbaa IR |
89 | /* if isis is not enabled ignore */ |
90 | if (!isis) | |
1cbf96a8 | 91 | return 0; |
92 | ||
93 | if (announce.proto != ZEBRA_ROUTE_LDP) | |
94 | return 0; | |
95 | ||
11106e28 | 96 | ils_debug("%s: rcvd announce from LDP", __func__); |
1cbf96a8 | 97 | |
98 | /* LDP just started up: | |
99 | * set cost to LSInfinity | |
100 | * send request to LDP for LDP-SYNC state for each interface | |
1cbf96a8 | 101 | */ |
ec62fbaa IR |
102 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { |
103 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
104 | continue; | |
105 | ||
106 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) | |
1cbf96a8 | 107 | isis_ldp_sync_if_start(circuit, true); |
1cbf96a8 | 108 | } |
109 | ||
1cbf96a8 | 110 | return 0; |
111 | } | |
112 | ||
113 | void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit) | |
114 | { | |
115 | struct ldp_igp_sync_if_state_req request; | |
116 | struct interface *ifp = circuit->interface; | |
117 | ||
11106e28 | 118 | ils_debug("%s: send state request to LDP for %s", __func__, ifp->name); |
1cbf96a8 | 119 | |
f735c2e8 | 120 | memset(&request, 0, sizeof(request)); |
1cbf96a8 | 121 | strlcpy(request.name, ifp->name, sizeof(ifp->name)); |
122 | request.proto = LDP_IGP_SYNC_IF_STATE_REQUEST; | |
123 | request.ifindex = ifp->ifindex; | |
124 | ||
125 | zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST, | |
126 | (uint8_t *)&request, sizeof(request)); | |
127 | } | |
128 | ||
129 | /* | |
130 | * LDP-SYNC general interface routines | |
131 | */ | |
1cbf96a8 | 132 | void isis_ldp_sync_if_start(struct isis_circuit *circuit, |
133 | bool send_state_req) | |
134 | { | |
135 | struct ldp_sync_info *ldp_sync_info; | |
136 | ||
137 | ldp_sync_info = circuit->ldp_sync_info; | |
138 | ||
139 | /* Start LDP-SYNC on this interface: | |
140 | * set cost of interface to LSInfinity so traffic will use different | |
141 | * interface until LDP has learned all labels from peer | |
142 | * start holddown timer if configured | |
143 | * send msg to LDP to get LDP-SYNC state | |
144 | */ | |
145 | if (ldp_sync_info && | |
146 | ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED && | |
147 | ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) { | |
11106e28 | 148 | ils_debug("%s: start on if %s state: %s", __func__, |
1cbf96a8 | 149 | circuit->interface->name, "Holding down until Sync"); |
150 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
151 | isis_ldp_sync_set_if_metric(circuit, true); | |
152 | isis_ldp_sync_holddown_timer_add(circuit); | |
153 | ||
154 | if (send_state_req) | |
155 | isis_ldp_sync_state_req_msg(circuit); | |
156 | } | |
157 | } | |
158 | ||
159 | void isis_ldp_sync_if_complete(struct isis_circuit *circuit) | |
160 | { | |
161 | struct ldp_sync_info *ldp_sync_info; | |
162 | ||
163 | ldp_sync_info = circuit->ldp_sync_info; | |
164 | ||
165 | /* received sync-complete from LDP: | |
166 | * set state to up | |
167 | * stop timer | |
168 | * restore interface cost to original value | |
169 | */ | |
170 | if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) { | |
171 | if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP) | |
172 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP; | |
50478845 | 173 | |
e16d030c | 174 | EVENT_OFF(ldp_sync_info->t_holddown); |
50478845 | 175 | |
1cbf96a8 | 176 | isis_ldp_sync_set_if_metric(circuit, true); |
177 | } | |
178 | } | |
179 | ||
180 | void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit) | |
181 | { | |
182 | struct ldp_sync_info *ldp_sync_info; | |
183 | ||
184 | ldp_sync_info = circuit->ldp_sync_info; | |
185 | ||
cb135cc9 | 186 | /* LDP client close detected: |
1cbf96a8 | 187 | * stop holddown timer |
188 | * set cost of interface to LSInfinity so traffic will use different | |
189 | * interface until LDP restarts and has learned all labels from peer | |
190 | */ | |
191 | if (ldp_sync_info && | |
192 | ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED && | |
193 | ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) { | |
e16d030c | 194 | EVENT_OFF(ldp_sync_info->t_holddown); |
1cbf96a8 | 195 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; |
196 | isis_ldp_sync_set_if_metric(circuit, true); | |
197 | } | |
198 | } | |
199 | ||
1cbf96a8 | 200 | static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj) |
201 | { | |
202 | struct isis_circuit *circuit = adj->circuit; | |
ec62fbaa IR |
203 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; |
204 | struct isis_area *area = circuit->area; | |
1cbf96a8 | 205 | |
ec62fbaa | 206 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) |
096f7609 | 207 | || circuit->interface->vrf->vrf_id != VRF_DEFAULT |
ec62fbaa | 208 | || if_is_loopback(circuit->interface)) |
1cbf96a8 | 209 | return 0; |
210 | ||
1cbf96a8 | 211 | if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED) |
212 | return 0; | |
213 | ||
214 | if (adj->adj_state == ISIS_ADJ_UP) { | |
215 | if (circuit->circ_type == CIRCUIT_T_P2P || | |
216 | if_is_pointopoint(circuit->interface)) { | |
217 | /* If LDP-SYNC is configure on interface then start */ | |
218 | ldp_sync_info->state = | |
219 | LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
220 | isis_ldp_sync_if_start(circuit, true); | |
221 | } else { | |
222 | /* non ptop link so don't run ldp-sync */ | |
223 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; | |
224 | isis_ldp_sync_set_if_metric(circuit, true); | |
225 | } | |
226 | } else { | |
227 | /* If LDP-SYNC is configure on this interface then stop it */ | |
228 | if (circuit->circ_type == CIRCUIT_T_P2P || | |
229 | if_is_pointopoint(circuit->interface)) | |
230 | ldp_sync_info->state = | |
231 | LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
232 | else | |
233 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; | |
234 | ||
11106e28 | 235 | ils_debug("%s: down on if %s", __func__, |
236 | circuit->interface->name); | |
1cbf96a8 | 237 | ldp_sync_if_down(circuit->ldp_sync_info); |
238 | } | |
239 | ||
240 | return 0; | |
241 | } | |
242 | ||
243 | bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit, int level, | |
244 | int metric) | |
245 | { | |
246 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; | |
ec62fbaa | 247 | struct isis_area *area = circuit->area; |
1cbf96a8 | 248 | |
249 | /* configured interface metric has been changed: | |
250 | * if LDP-IGP Sync is running and metric has been set to LSInfinity | |
251 | * change saved value so when ldp-sync completes proper metric is | |
252 | * restored | |
253 | */ | |
ec62fbaa IR |
254 | if (area && CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) |
255 | && ldp_sync_info != NULL) { | |
1cbf96a8 | 256 | |
257 | if (CHECK_FLAG(ldp_sync_info->flags, | |
258 | LDP_SYNC_FLAG_SET_METRIC)) { | |
259 | ldp_sync_info->metric[level-1] = metric; | |
260 | ldp_sync_info->metric[level-1] = metric; | |
261 | return false; | |
262 | } | |
263 | } | |
264 | return true; | |
265 | } | |
266 | ||
267 | void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen) | |
268 | { | |
269 | struct ldp_sync_info *ldp_sync_info; | |
270 | ||
271 | /* set interface metric: | |
272 | * if LDP-IGP Sync is starting set metric so interface | |
273 | * is used only as last resort | |
274 | * else restore metric to original value | |
275 | */ | |
276 | if (circuit->ldp_sync_info == NULL || circuit->area == NULL) | |
277 | return; | |
278 | ||
279 | ldp_sync_info = circuit->ldp_sync_info; | |
280 | if (ldp_sync_if_is_enabled(ldp_sync_info)) { | |
281 | /* if metric already set to LSInfinity just return */ | |
282 | if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC)) | |
283 | return; | |
284 | ||
285 | SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC); | |
286 | if (circuit->is_type & IS_LEVEL_1) { | |
287 | if (circuit->area->newmetric) { | |
288 | ldp_sync_info->metric[0] = | |
289 | circuit->te_metric[0]; | |
35f70ed3 RW |
290 | circuit->te_metric[0] = |
291 | ISIS_WIDE_METRIC_INFINITY; | |
1cbf96a8 | 292 | } else { |
293 | ldp_sync_info->metric[0] = circuit->metric[0]; | |
35f70ed3 RW |
294 | circuit->metric[0] = |
295 | ISIS_NARROW_METRIC_INFINITY; | |
1cbf96a8 | 296 | } |
297 | } | |
298 | if (circuit->is_type & IS_LEVEL_2) { | |
299 | if (circuit->area->newmetric) { | |
300 | ldp_sync_info->metric[1] = | |
301 | circuit->te_metric[1]; | |
35f70ed3 RW |
302 | circuit->te_metric[1] = |
303 | ISIS_WIDE_METRIC_INFINITY; | |
1cbf96a8 | 304 | } else { |
305 | ldp_sync_info->metric[1] = circuit->metric[1]; | |
35f70ed3 RW |
306 | circuit->metric[1] = |
307 | ISIS_NARROW_METRIC_INFINITY; | |
1cbf96a8 | 308 | } |
309 | } | |
310 | } else { | |
311 | /* if metric already restored just return */ | |
312 | if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC)) | |
313 | return; | |
314 | ||
315 | UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC); | |
316 | if (circuit->is_type & IS_LEVEL_1) { | |
317 | circuit->te_metric[0] = ldp_sync_info->metric[0]; | |
318 | circuit->metric[0] = ldp_sync_info->metric[0]; | |
319 | } | |
320 | if (circuit->is_type & IS_LEVEL_2) { | |
321 | circuit->te_metric[1] = ldp_sync_info->metric[1]; | |
322 | circuit->metric[1] = ldp_sync_info->metric[1]; | |
323 | } | |
324 | } | |
325 | ||
326 | if (run_regen) | |
327 | lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); | |
328 | } | |
329 | ||
330 | ||
331 | /* | |
332 | * LDP-SYNC holddown timer routines | |
333 | */ | |
e6685141 | 334 | static void isis_ldp_sync_holddown_timer(struct event *thread) |
1cbf96a8 | 335 | { |
336 | struct isis_circuit *circuit; | |
337 | struct ldp_sync_info *ldp_sync_info; | |
338 | ||
339 | /* holddown timer expired: | |
340 | * didn't receive msg from LDP indicating sync-complete | |
341 | * restore interface cost to original value | |
342 | */ | |
e16d030c | 343 | circuit = EVENT_ARG(thread); |
1cbf96a8 | 344 | if (circuit->ldp_sync_info == NULL) |
cc9f21da | 345 | return; |
1cbf96a8 | 346 | |
347 | ldp_sync_info = circuit->ldp_sync_info; | |
348 | ||
349 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP; | |
350 | ldp_sync_info->t_holddown = NULL; | |
351 | ||
11106e28 | 352 | ils_debug("%s: holddown timer expired for %s state:sync achieved", |
353 | __func__, circuit->interface->name); | |
1cbf96a8 | 354 | |
355 | isis_ldp_sync_set_if_metric(circuit, true); | |
1cbf96a8 | 356 | } |
357 | ||
358 | void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit) | |
359 | { | |
360 | struct ldp_sync_info *ldp_sync_info; | |
361 | ||
362 | ldp_sync_info = circuit->ldp_sync_info; | |
363 | ||
364 | /* Start holddown timer: | |
365 | * this timer is used to keep interface cost at LSInfinity | |
366 | * once expires returns cost to original value | |
367 | * if timer is already running or holddown time is off just return | |
368 | */ | |
369 | if (ldp_sync_info->t_holddown || | |
370 | ldp_sync_info->holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT) | |
371 | return; | |
372 | ||
11106e28 | 373 | ils_debug("%s: start holddown timer for %s time %d", __func__, |
1cbf96a8 | 374 | circuit->interface->name, ldp_sync_info->holddown); |
375 | ||
907a2395 DS |
376 | event_add_timer(master, isis_ldp_sync_holddown_timer, circuit, |
377 | ldp_sync_info->holddown, &ldp_sync_info->t_holddown); | |
1cbf96a8 | 378 | } |
379 | ||
cb135cc9 KS |
380 | /* |
381 | * LDP-SYNC handle client close routine | |
382 | */ | |
383 | void isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info) | |
384 | { | |
385 | struct isis_area *area; | |
ec62fbaa | 386 | struct listnode *anode, *cnode; |
cb135cc9 | 387 | struct isis_circuit *circuit; |
cb135cc9 KS |
388 | struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); |
389 | ||
ec62fbaa IR |
390 | /* if isis is not enabled ignore */ |
391 | if (!isis) | |
cb135cc9 KS |
392 | return; |
393 | ||
394 | /* Check if the LDP main client session closed */ | |
395 | if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0) | |
396 | return; | |
397 | ||
398 | /* Handle the zebra notification that the LDP client session closed. | |
399 | * set cost to LSInfinity | |
400 | * send request to LDP for LDP-SYNC state for each interface | |
401 | */ | |
11106e28 | 402 | zlog_err("%s: LDP down", __func__); |
cb135cc9 | 403 | |
ec62fbaa IR |
404 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { |
405 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
406 | continue; | |
407 | ||
408 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) | |
c3783ac0 | 409 | isis_ldp_sync_ldp_fail(circuit); |
cb135cc9 KS |
410 | } |
411 | } | |
412 | ||
1cbf96a8 | 413 | /* |
414 | * LDP-SYNC routes used by set commands. | |
415 | */ | |
416 | ||
ec62fbaa | 417 | void isis_area_ldp_sync_enable(struct isis_area *area) |
1cbf96a8 | 418 | { |
ec62fbaa IR |
419 | struct isis_circuit *circuit; |
420 | struct listnode *node; | |
421 | ||
422 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) { | |
423 | SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE); | |
424 | ||
425 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) | |
426 | isis_if_ldp_sync_enable(circuit); | |
427 | } | |
428 | } | |
429 | ||
430 | void isis_area_ldp_sync_disable(struct isis_area *area) | |
431 | { | |
432 | struct isis_circuit *circuit; | |
433 | struct listnode *node; | |
434 | ||
435 | if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) { | |
436 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) | |
437 | isis_if_ldp_sync_disable(circuit); | |
438 | ||
439 | UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE); | |
440 | ||
441 | UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN); | |
442 | area->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT; | |
443 | } | |
444 | } | |
445 | ||
446 | void isis_area_ldp_sync_set_holddown(struct isis_area *area, uint16_t holddown) | |
447 | { | |
448 | struct isis_circuit *circuit; | |
449 | struct listnode *node; | |
450 | ||
451 | if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT) | |
452 | UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN); | |
453 | else | |
454 | SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN); | |
455 | ||
456 | area->ldp_sync_cmd.holddown = holddown; | |
457 | ||
458 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) | |
459 | isis_if_set_ldp_sync_holddown(circuit); | |
460 | } | |
461 | ||
462 | void isis_if_ldp_sync_enable(struct isis_circuit *circuit) | |
463 | { | |
464 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; | |
465 | struct isis_area *area = circuit->area; | |
1cbf96a8 | 466 | |
467 | /* called when setting LDP-SYNC at the global level: | |
bd4f51b1 | 468 | * specified on interface overrides global config |
1cbf96a8 | 469 | * if ptop link send msg to LDP indicating ldp-sync enabled |
bd4f51b1 | 470 | */ |
ec62fbaa | 471 | if (if_is_loopback(circuit->interface)) |
1cbf96a8 | 472 | return; |
473 | ||
b11f166c IR |
474 | if (circuit->interface->vrf->vrf_id != VRF_DEFAULT) |
475 | return; | |
476 | ||
11106e28 | 477 | ils_debug("%s: enable if %s", __func__, circuit->interface->name); |
1cbf96a8 | 478 | |
ec62fbaa IR |
479 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) |
480 | return; | |
1cbf96a8 | 481 | |
ec62fbaa IR |
482 | /* config on interface, overrides global config. */ |
483 | if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG)) | |
484 | if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED) | |
485 | return; | |
1cbf96a8 | 486 | |
ec62fbaa IR |
487 | if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN)) |
488 | ldp_sync_info->holddown = area->ldp_sync_cmd.holddown; | |
489 | ||
490 | if (circuit->circ_type == CIRCUIT_T_P2P | |
491 | || if_is_pointopoint(circuit->interface)) { | |
492 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
493 | isis_ldp_sync_state_req_msg(circuit); | |
494 | } else { | |
495 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; | |
11106e28 | 496 | ils_debug("%s: Sync only runs on P2P links %s", __func__, |
ec62fbaa IR |
497 | circuit->interface->name); |
498 | } | |
499 | } | |
500 | ||
501 | void isis_if_ldp_sync_disable(struct isis_circuit *circuit) | |
502 | { | |
503 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; | |
504 | struct isis_area *area = circuit->area; | |
505 | ||
506 | /* Stop LDP-SYNC on this interface: | |
507 | * if holddown timer is running stop it | |
508 | * delete ldp instance on interface | |
509 | * restore metric | |
510 | */ | |
511 | if (if_is_loopback(circuit->interface)) | |
512 | return; | |
513 | ||
11106e28 | 514 | ils_debug("%s: remove if %s", __func__, circuit->interface->name); |
ec62fbaa IR |
515 | |
516 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
517 | return; | |
518 | ||
e16d030c | 519 | EVENT_OFF(ldp_sync_info->t_holddown); |
ec62fbaa IR |
520 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; |
521 | isis_ldp_sync_set_if_metric(circuit, true); | |
1cbf96a8 | 522 | } |
523 | ||
524 | void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit) | |
525 | { | |
ec62fbaa IR |
526 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; |
527 | struct isis_area *area = circuit->area; | |
1cbf96a8 | 528 | |
529 | /* called when setting LDP-SYNC at the global level: | |
bd4f51b1 | 530 | * specified on interface overrides global config. |
1cbf96a8 | 531 | */ |
ec62fbaa | 532 | if (if_is_loopback(circuit->interface)) |
1cbf96a8 | 533 | return; |
534 | ||
1cbf96a8 | 535 | /* config on interface, overrides global config. */ |
536 | if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN)) | |
537 | return; | |
ec62fbaa IR |
538 | if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN)) |
539 | ldp_sync_info->holddown = area->ldp_sync_cmd.holddown; | |
1cbf96a8 | 540 | else |
541 | ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT; | |
542 | } | |
543 | ||
1cbf96a8 | 544 | /* |
545 | * LDP-SYNC routines used by show commands. | |
546 | */ | |
547 | ||
548 | static void isis_circuit_ldp_sync_print_vty(struct isis_circuit *circuit, | |
549 | struct vty *vty) | |
550 | { | |
551 | struct ldp_sync_info *ldp_sync_info; | |
552 | const char *ldp_state; | |
553 | ||
554 | if (circuit->ldp_sync_info == NULL || | |
555 | if_is_loopback(circuit->interface)) | |
556 | return; | |
557 | ||
558 | ldp_sync_info = circuit->ldp_sync_info; | |
eb47c1be | 559 | vty_out(vty, "%-16s\n", circuit->interface->name); |
560 | if (circuit->state == C_STATE_CONF) { | |
561 | vty_out(vty, " Interface down\n"); | |
562 | return; | |
563 | } | |
564 | ||
1cbf96a8 | 565 | vty_out(vty, " LDP-IGP Synchronization enabled: %s\n", |
566 | ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED | |
567 | ? "yes" | |
568 | : "no"); | |
569 | vty_out(vty, " holddown timer in seconds: %u\n", | |
570 | ldp_sync_info->holddown); | |
571 | ||
572 | switch (ldp_sync_info->state) { | |
573 | case LDP_IGP_SYNC_STATE_REQUIRED_UP: | |
574 | vty_out(vty, " State: Sync achieved\n"); | |
575 | break; | |
576 | case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP: | |
577 | if (ldp_sync_info->t_holddown != NULL) { | |
4f830a07 DS |
578 | struct timeval remain = |
579 | event_timer_remain(ldp_sync_info->t_holddown); | |
1cbf96a8 | 580 | vty_out(vty, |
581 | " Holddown timer is running %lld.%03lld remaining\n", | |
582 | (long long)remain.tv_sec, | |
583 | (long long)remain.tv_usec/1000); | |
584 | ||
585 | vty_out(vty, " State: Holding down until Sync\n"); | |
586 | } else | |
587 | vty_out(vty, " State: Sync not achieved\n"); | |
588 | break; | |
589 | case LDP_IGP_SYNC_STATE_NOT_REQUIRED: | |
590 | default: | |
591 | if ((circuit->circ_type != CIRCUIT_T_P2P && | |
592 | !if_is_pointopoint(circuit->interface)) && | |
593 | circuit->circ_type != CIRCUIT_T_UNKNOWN) | |
594 | ldp_state = "Sync not required: non-p2p link"; | |
595 | else | |
596 | ldp_state = "Sync not required"; | |
597 | vty_out(vty, " State: %s\n", ldp_state); | |
598 | break; | |
599 | } | |
600 | } | |
601 | ||
602 | DEFUN (show_isis_mpls_ldp_interface, | |
603 | show_isis_mpls_ldp_interface_cmd, | |
604 | "show " PROTO_NAME " mpls ldp-sync [interface <INTERFACE|all>]", | |
605 | SHOW_STR | |
606 | PROTO_HELP | |
607 | MPLS_STR | |
608 | "LDP-IGP Sync information\n" | |
31011d9c IR |
609 | "Interface information\n" |
610 | "Interface name\n" | |
611 | "All interfaces\n") | |
1cbf96a8 | 612 | { |
613 | char *ifname = NULL; | |
614 | int idx_intf = 0; | |
615 | struct listnode *anode, *cnode; | |
616 | struct isis_area *area; | |
617 | struct isis_circuit *circuit; | |
618 | struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); | |
eb47c1be | 619 | bool found = false; |
1cbf96a8 | 620 | |
621 | if (!isis) { | |
622 | vty_out(vty, "IS-IS Routing Process not enabled\n"); | |
623 | return CMD_SUCCESS; | |
624 | } | |
625 | ||
1cbf96a8 | 626 | if (argv_find(argv, argc, "INTERFACE", &idx_intf)) |
627 | ifname = argv[idx_intf]->arg; | |
628 | ||
629 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { | |
630 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) | |
631 | if (!ifname) | |
632 | isis_circuit_ldp_sync_print_vty(circuit, vty); | |
eb47c1be | 633 | else if (strcmp(circuit->interface->name, ifname) |
634 | == 0) { | |
1cbf96a8 | 635 | isis_circuit_ldp_sync_print_vty(circuit, vty); |
eb47c1be | 636 | found = true; |
637 | } | |
1cbf96a8 | 638 | } |
639 | ||
eb47c1be | 640 | if (found == false && ifname) |
641 | vty_out(vty, "%-16s\n ISIS not enabled\n", ifname); | |
642 | ||
1cbf96a8 | 643 | return CMD_SUCCESS; |
644 | } | |
645 | ||
646 | void isis_ldp_sync_init(void) | |
647 | { | |
648 | ||
649 | /* "show ip isis mpls ldp interface" commands. */ | |
650 | install_element(VIEW_NODE, &show_isis_mpls_ldp_interface_cmd); | |
651 | ||
652 | /* register for adjacency state changes */ | |
653 | hook_register(isis_adj_state_change_hook, | |
654 | isis_ldp_sync_adj_state_change); | |
655 | } |