1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS Rout(e)ing protocol - BFD support
4 * Copyright (C) 2018 Christian Franke
11 #include "lib_errors.h"
13 #include "isisd/isis_bfd.h"
14 #include "isisd/isis_zebra.h"
15 #include "isisd/isis_common.h"
16 #include "isisd/isis_constants.h"
17 #include "isisd/isis_adjacency.h"
18 #include "isisd/isis_circuit.h"
19 #include "isisd/isisd.h"
20 #include "isisd/fabricd.h"
22 DEFINE_MTYPE_STATIC(ISISD
, BFD_SESSION
, "ISIS BFD Session");
24 static void adj_bfd_cb(struct bfd_session_params
*bsp
,
25 const struct bfd_session_status
*bss
, void *arg
)
27 struct isis_adjacency
*adj
= arg
;
31 "ISIS-BFD: BFD changed status for adjacency %s old %s new %s",
33 bfd_get_status_str(bss
->previous_state
),
34 bfd_get_status_str(bss
->state
));
36 if (bss
->state
== BFD_STATUS_DOWN
37 && bss
->previous_state
== BFD_STATUS_UP
) {
38 adj
->circuit
->area
->bfd_signalled_down
= true;
39 isis_adj_state_change(&adj
, ISIS_ADJ_DOWN
,
40 "bfd session went down");
44 static void bfd_handle_adj_down(struct isis_adjacency
*adj
)
46 bfd_sess_free(&adj
->bfd_session
);
49 static void bfd_handle_adj_up(struct isis_adjacency
*adj
)
51 struct isis_circuit
*circuit
= adj
->circuit
;
55 struct list
*local_ips
;
56 struct prefix
*local_ip
;
58 if (!circuit
->bfd_config
.enabled
) {
61 "ISIS-BFD: skipping BFD initialization on adjacency with %s because BFD is not enabled for the circuit",
66 /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed
67 * before starting up BFD
69 if (circuit
->ipv6_router
70 && (listcount(circuit
->ipv6_link
) == 0
71 || adj
->ll_ipv6_count
== 0)) {
74 "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready",
80 * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
81 * creating a BFD session over IPv6.
83 if (circuit
->ipv6_router
&& adj
->ll_ipv6_count
) {
85 dst_ip
.ipv6
= adj
->ll_ipv6_addrs
[0];
86 local_ips
= circuit
->ipv6_link
;
87 if (list_isempty(local_ips
)) {
90 "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses");
93 local_ip
= listgetdata(listhead(local_ips
));
94 src_ip
.ipv6
= local_ip
->u
.prefix6
;
95 } else if (circuit
->ip_router
&& adj
->ipv4_address_count
) {
97 dst_ip
.ipv4
= adj
->ipv4_addresses
[0];
98 local_ips
= fabricd_ip_addrs(adj
->circuit
);
99 if (!local_ips
|| list_isempty(local_ips
)) {
102 "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses");
105 local_ip
= listgetdata(listhead(local_ips
));
106 src_ip
.ipv4
= local_ip
->u
.prefix4
;
110 if (adj
->bfd_session
== NULL
)
111 adj
->bfd_session
= bfd_sess_new(adj_bfd_cb
, adj
);
113 bfd_sess_set_timers(adj
->bfd_session
, BFD_DEF_DETECT_MULT
,
114 BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
);
115 if (family
== AF_INET
)
116 bfd_sess_set_ipv4_addrs(adj
->bfd_session
, &src_ip
.ipv4
,
119 bfd_sess_set_ipv6_addrs(adj
->bfd_session
, &src_ip
.ipv6
,
121 bfd_sess_set_interface(adj
->bfd_session
, adj
->circuit
->interface
->name
);
122 bfd_sess_set_vrf(adj
->bfd_session
,
123 adj
->circuit
->interface
->vrf
->vrf_id
);
124 bfd_sess_set_profile(adj
->bfd_session
, circuit
->bfd_config
.profile
);
125 bfd_sess_install(adj
->bfd_session
);
128 bfd_handle_adj_down(adj
);
131 static int bfd_handle_adj_state_change(struct isis_adjacency
*adj
)
133 if (adj
->adj_state
== ISIS_ADJ_UP
)
134 bfd_handle_adj_up(adj
);
136 bfd_handle_adj_down(adj
);
140 static void bfd_adj_cmd(struct isis_adjacency
*adj
)
142 if (adj
->adj_state
== ISIS_ADJ_UP
&& adj
->circuit
->bfd_config
.enabled
)
143 bfd_handle_adj_up(adj
);
145 bfd_handle_adj_down(adj
);
148 void isis_bfd_circuit_cmd(struct isis_circuit
*circuit
)
150 switch (circuit
->circ_type
) {
151 case CIRCUIT_T_BROADCAST
:
152 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
153 struct list
*adjdb
= circuit
->u
.bc
.adjdb
[level
- 1];
155 struct listnode
*node
;
156 struct isis_adjacency
*adj
;
160 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
))
165 if (circuit
->u
.p2p
.neighbor
)
166 bfd_adj_cmd(circuit
->u
.p2p
.neighbor
);
173 static int bfd_handle_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
177 if (family
!= AF_INET6
|| global
)
180 if (adj
->bfd_session
)
183 if (adj
->adj_state
!= ISIS_ADJ_UP
)
186 bfd_handle_adj_up(adj
);
191 static int bfd_handle_circuit_add_addr(struct isis_circuit
*circuit
)
193 struct isis_adjacency
*adj
;
194 struct listnode
*node
;
196 if (circuit
->area
== NULL
)
199 for (ALL_LIST_ELEMENTS_RO(circuit
->area
->adjacency_list
, node
, adj
)) {
200 if (adj
->bfd_session
)
203 if (adj
->adj_state
!= ISIS_ADJ_UP
)
206 bfd_handle_adj_up(adj
);
212 void isis_bfd_init(struct event_loop
*tm
)
214 bfd_protocol_integration_init(zclient
, tm
);
216 hook_register(isis_adj_state_change_hook
, bfd_handle_adj_state_change
);
217 hook_register(isis_adj_ip_enabled_hook
, bfd_handle_adj_ip_enabled
);
218 hook_register(isis_circuit_add_addr_hook
, bfd_handle_circuit_add_addr
);