2 * IS-IS Rout(e)ing protocol - BFD support
3 * Copyright (C) 2018 Christian Franke
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "lib_errors.h"
26 #include "isisd/isis_bfd.h"
27 #include "isisd/isis_zebra.h"
28 #include "isisd/isis_common.h"
29 #include "isisd/isis_constants.h"
30 #include "isisd/isis_adjacency.h"
31 #include "isisd/isis_circuit.h"
32 #include "isisd/isisd.h"
33 #include "isisd/fabricd.h"
35 DEFINE_MTYPE_STATIC(ISISD
, BFD_SESSION
, "ISIS BFD Session");
37 static void adj_bfd_cb(struct bfd_session_params
*bsp
,
38 const struct bfd_session_status
*bss
, void *arg
)
40 struct isis_adjacency
*adj
= arg
;
44 "ISIS-BFD: BFD changed status for adjacency %s old %s new %s",
46 bfd_get_status_str(bss
->previous_state
),
47 bfd_get_status_str(bss
->state
));
49 if (bss
->state
== BFD_STATUS_DOWN
50 && bss
->previous_state
== BFD_STATUS_UP
) {
51 adj
->circuit
->area
->bfd_signalled_down
= true;
52 isis_adj_state_change(&adj
, ISIS_ADJ_DOWN
,
53 "bfd session went down");
57 static void bfd_handle_adj_down(struct isis_adjacency
*adj
)
59 bfd_sess_free(&adj
->bfd_session
);
62 static void bfd_handle_adj_up(struct isis_adjacency
*adj
)
64 struct isis_circuit
*circuit
= adj
->circuit
;
68 struct list
*local_ips
;
69 struct prefix
*local_ip
;
71 if (!circuit
->bfd_config
.enabled
) {
74 "ISIS-BFD: skipping BFD initialization on adjacency with %s because BFD is not enabled for the circuit",
79 /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed
80 * before starting up BFD
82 if (circuit
->ipv6_router
83 && (listcount(circuit
->ipv6_link
) == 0
84 || adj
->ipv6_address_count
== 0)) {
87 "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready",
93 * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
94 * creating a BFD session over IPv6.
96 if (circuit
->ipv6_router
&& adj
->ipv6_address_count
) {
98 dst_ip
.ipv6
= adj
->ipv6_addresses
[0];
99 local_ips
= circuit
->ipv6_link
;
100 if (!local_ips
|| list_isempty(local_ips
)) {
103 "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses");
106 local_ip
= listgetdata(listhead(local_ips
));
107 src_ip
.ipv6
= local_ip
->u
.prefix6
;
108 } else if (circuit
->ip_router
&& adj
->ipv4_address_count
) {
110 dst_ip
.ipv4
= adj
->ipv4_addresses
[0];
111 local_ips
= fabricd_ip_addrs(adj
->circuit
);
112 if (!local_ips
|| list_isempty(local_ips
)) {
115 "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses");
118 local_ip
= listgetdata(listhead(local_ips
));
119 src_ip
.ipv4
= local_ip
->u
.prefix4
;
123 if (adj
->bfd_session
== NULL
)
124 adj
->bfd_session
= bfd_sess_new(adj_bfd_cb
, adj
);
126 bfd_sess_set_timers(adj
->bfd_session
, BFD_DEF_DETECT_MULT
,
127 BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
);
128 if (family
== AF_INET
)
129 bfd_sess_set_ipv4_addrs(adj
->bfd_session
, &src_ip
.ipv4
,
132 bfd_sess_set_ipv6_addrs(adj
->bfd_session
, &src_ip
.ipv6
,
134 bfd_sess_set_interface(adj
->bfd_session
, adj
->circuit
->interface
->name
);
135 bfd_sess_set_profile(adj
->bfd_session
, circuit
->bfd_config
.profile
);
136 bfd_sess_install(adj
->bfd_session
);
139 bfd_handle_adj_down(adj
);
142 static int bfd_handle_adj_state_change(struct isis_adjacency
*adj
)
144 if (adj
->adj_state
== ISIS_ADJ_UP
)
145 bfd_handle_adj_up(adj
);
147 bfd_handle_adj_down(adj
);
151 static void bfd_adj_cmd(struct isis_adjacency
*adj
)
153 if (adj
->adj_state
== ISIS_ADJ_UP
&& adj
->circuit
->bfd_config
.enabled
)
154 bfd_handle_adj_up(adj
);
156 bfd_handle_adj_down(adj
);
159 void isis_bfd_circuit_cmd(struct isis_circuit
*circuit
)
161 switch (circuit
->circ_type
) {
162 case CIRCUIT_T_BROADCAST
:
163 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
164 struct list
*adjdb
= circuit
->u
.bc
.adjdb
[level
- 1];
166 struct listnode
*node
;
167 struct isis_adjacency
*adj
;
169 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
))
174 if (circuit
->u
.p2p
.neighbor
)
175 bfd_adj_cmd(circuit
->u
.p2p
.neighbor
);
182 static int bfd_handle_adj_ip_enabled(struct isis_adjacency
*adj
, int family
)
185 if (family
!= AF_INET6
)
188 if (adj
->bfd_session
)
191 if (adj
->adj_state
!= ISIS_ADJ_UP
)
194 bfd_handle_adj_up(adj
);
199 static int bfd_handle_circuit_add_addr(struct isis_circuit
*circuit
)
201 struct isis_adjacency
*adj
;
202 struct listnode
*node
;
204 if (circuit
->area
== 0)
207 for (ALL_LIST_ELEMENTS_RO(circuit
->area
->adjacency_list
, node
, adj
)) {
208 if (adj
->bfd_session
)
211 if (adj
->adj_state
!= ISIS_ADJ_UP
)
214 bfd_handle_adj_up(adj
);
220 void isis_bfd_init(struct thread_master
*tm
)
222 bfd_protocol_integration_init(zclient
, tm
);
224 hook_register(isis_adj_state_change_hook
, bfd_handle_adj_state_change
);
225 hook_register(isis_adj_ip_enabled_hook
, bfd_handle_adj_ip_enabled
);
226 hook_register(isis_circuit_add_addr_hook
, bfd_handle_circuit_add_addr
);