]>
Commit | Line | Data |
---|---|---|
52df8228 CF |
1 | /* |
2 | * IS-IS Rout(e)ing protocol - BFD support | |
52df8228 CF |
3 | * Copyright (C) 2018 Christian Franke |
4 | * | |
d04f9fbf CF |
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) | |
8 | * any later version. | |
52df8228 | 9 | * |
d04f9fbf CF |
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 | |
13 | * more details. | |
52df8228 CF |
14 | * |
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 | |
18 | */ | |
19 | #include <zebra.h> | |
20 | ||
21 | #include "zclient.h" | |
e782cca7 | 22 | #include "nexthop.h" |
52df8228 | 23 | #include "bfd.h" |
e782cca7 | 24 | #include "lib_errors.h" |
52df8228 CF |
25 | |
26 | #include "isisd/isis_bfd.h" | |
27 | #include "isisd/isis_zebra.h" | |
215eccb0 CF |
28 | #include "isisd/isis_common.h" |
29 | #include "isisd/isis_constants.h" | |
30 | #include "isisd/isis_adjacency.h" | |
31 | #include "isisd/isis_circuit.h" | |
3015e3d1 | 32 | #include "isisd/isisd.h" |
215eccb0 | 33 | #include "isisd/fabricd.h" |
52df8228 | 34 | |
bf8d3d6a | 35 | DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session"); |
20a42f01 CF |
36 | |
37 | struct bfd_session { | |
e782cca7 RW |
38 | int family; |
39 | union g_addr dst_ip; | |
40 | union g_addr src_ip; | |
a5eba4e9 | 41 | int status; |
20a42f01 CF |
42 | }; |
43 | ||
e782cca7 RW |
44 | static struct bfd_session *bfd_session_new(int family, union g_addr *dst_ip, |
45 | union g_addr *src_ip) | |
20a42f01 CF |
46 | { |
47 | struct bfd_session *rv; | |
48 | ||
a5eba4e9 | 49 | rv = XCALLOC(MTYPE_BFD_SESSION, sizeof(*rv)); |
e782cca7 | 50 | rv->family = family; |
20a42f01 CF |
51 | rv->dst_ip = *dst_ip; |
52 | rv->src_ip = *src_ip; | |
53 | return rv; | |
54 | } | |
55 | ||
56 | static void bfd_session_free(struct bfd_session **session) | |
57 | { | |
58 | if (!*session) | |
59 | return; | |
60 | ||
61 | XFREE(MTYPE_BFD_SESSION, *session); | |
20a42f01 CF |
62 | } |
63 | ||
e782cca7 RW |
64 | static bool bfd_session_same(const struct bfd_session *session, int family, |
65 | const union g_addr *src, const union g_addr *dst) | |
66 | { | |
67 | if (session->family != family) | |
68 | return false; | |
69 | ||
70 | switch (session->family) { | |
71 | case AF_INET: | |
72 | if (!IPV4_ADDR_SAME(&session->dst_ip.ipv4, &dst->ipv4)) | |
73 | return false; | |
74 | if (!IPV4_ADDR_SAME(&session->src_ip.ipv4, &src->ipv4)) | |
75 | return false; | |
76 | break; | |
77 | case AF_INET6: | |
78 | if (!IPV6_ADDR_SAME(&session->dst_ip.ipv6, &dst->ipv6)) | |
79 | return false; | |
80 | if (!IPV6_ADDR_SAME(&session->src_ip.ipv6, &src->ipv6)) | |
81 | return false; | |
82 | break; | |
83 | default: | |
84 | flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u", | |
85 | __func__, session->family); | |
86 | exit(1); | |
87 | } | |
88 | ||
89 | return true; | |
90 | } | |
91 | ||
a5eba4e9 CF |
92 | static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst, |
93 | int new_status) | |
94 | { | |
980390ce EDP |
95 | if (!adj->bfd_session) { |
96 | if (IS_DEBUG_BFD) | |
97 | zlog_debug( | |
98 | "ISIS-BFD: Ignoring update for adjacency with %s, could not find bfd session on the adjacency", | |
99 | isis_adj_name(adj)); | |
a5eba4e9 | 100 | return; |
980390ce | 101 | } |
a5eba4e9 | 102 | |
980390ce EDP |
103 | if (adj->bfd_session->family != dst->family) { |
104 | if (IS_DEBUG_BFD) | |
105 | zlog_debug( | |
106 | "ISIS-BFD: Ignoring update for adjacency with %s, address family does not match the family on the adjacency", | |
107 | isis_adj_name(adj)); | |
a5eba4e9 | 108 | return; |
980390ce | 109 | } |
a5eba4e9 | 110 | |
e782cca7 RW |
111 | switch (adj->bfd_session->family) { |
112 | case AF_INET: | |
113 | if (!IPV4_ADDR_SAME(&adj->bfd_session->dst_ip.ipv4, | |
980390ce EDP |
114 | &dst->u.prefix4)) { |
115 | if (IS_DEBUG_BFD) | |
116 | zlog_debug( | |
117 | "ISIS-BFD: Ignoring update for adjacency with %s, IPv4 address does not match", | |
118 | isis_adj_name(adj)); | |
e782cca7 | 119 | return; |
980390ce | 120 | } |
e782cca7 RW |
121 | break; |
122 | case AF_INET6: | |
123 | if (!IPV6_ADDR_SAME(&adj->bfd_session->dst_ip.ipv6, | |
980390ce EDP |
124 | &dst->u.prefix6)) { |
125 | if (IS_DEBUG_BFD) | |
126 | zlog_debug( | |
127 | "ISIS-BFD: Ignoring update for adjacency with %s, IPv6 address does not match", | |
128 | isis_adj_name(adj)); | |
e782cca7 | 129 | return; |
980390ce | 130 | } |
e782cca7 RW |
131 | break; |
132 | default: | |
133 | flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u", | |
134 | __func__, adj->bfd_session->family); | |
135 | exit(1); | |
136 | } | |
137 | ||
a5eba4e9 | 138 | int old_status = adj->bfd_session->status; |
a5eba4e9 | 139 | |
7555dc61 S |
140 | BFD_SET_CLIENT_STATUS(adj->bfd_session->status, new_status); |
141 | ||
980390ce EDP |
142 | if (old_status == new_status) { |
143 | if (IS_DEBUG_BFD) | |
144 | zlog_debug( | |
145 | "ISIS-BFD: Ignoring update for adjacency with %s, new status matches current known status", | |
146 | isis_adj_name(adj)); | |
a5eba4e9 | 147 | return; |
980390ce | 148 | } |
a5eba4e9 | 149 | |
e740f9c1 | 150 | if (IS_DEBUG_BFD) { |
a5eba4e9 CF |
151 | char dst_str[INET6_ADDRSTRLEN]; |
152 | ||
e782cca7 | 153 | inet_ntop(adj->bfd_session->family, &adj->bfd_session->dst_ip, |
a5eba4e9 CF |
154 | dst_str, sizeof(dst_str)); |
155 | zlog_debug("ISIS-BFD: Peer %s on %s changed from %s to %s", | |
156 | dst_str, adj->circuit->interface->name, | |
157 | bfd_get_status_str(old_status), | |
158 | bfd_get_status_str(new_status)); | |
159 | } | |
160 | ||
161 | if (old_status != BFD_STATUS_UP | |
162 | || new_status != BFD_STATUS_DOWN) { | |
163 | return; | |
164 | } | |
165 | ||
690497fb G |
166 | adj->circuit->area->bfd_signalled_down = true; |
167 | ||
16167b31 | 168 | isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "bfd session went down"); |
a5eba4e9 CF |
169 | } |
170 | ||
121f9dee | 171 | static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) |
52df8228 | 172 | { |
2815f817 | 173 | struct interface *ifp; |
37a74717 | 174 | struct prefix dst_ip, src_ip; |
2815f817 CF |
175 | int status; |
176 | ||
37a74717 DS |
177 | ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, &src_ip, &status, NULL, |
178 | vrf_id); | |
e782cca7 | 179 | if (!ifp || (dst_ip.family != AF_INET && dst_ip.family != AF_INET6)) |
2815f817 CF |
180 | return 0; |
181 | ||
e740f9c1 | 182 | if (IS_DEBUG_BFD) { |
2815f817 | 183 | char dst_buf[INET6_ADDRSTRLEN]; |
5489eb45 | 184 | |
e782cca7 RW |
185 | inet_ntop(dst_ip.family, &dst_ip.u.prefix, dst_buf, |
186 | sizeof(dst_buf)); | |
2815f817 CF |
187 | |
188 | zlog_debug("ISIS-BFD: Received update for %s on %s: Changed state to %s", | |
189 | dst_buf, ifp->name, bfd_get_status_str(status)); | |
190 | } | |
191 | ||
a5eba4e9 | 192 | struct isis_circuit *circuit = circuit_scan_by_ifp(ifp); |
5489eb45 | 193 | |
980390ce EDP |
194 | if (!circuit) { |
195 | if (IS_DEBUG_BFD) | |
196 | zlog_debug( | |
197 | "ISIS-BFD: Ignoring update, could not find circuit"); | |
a5eba4e9 | 198 | return 0; |
980390ce | 199 | } |
a5eba4e9 CF |
200 | |
201 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
202 | for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { | |
203 | struct list *adjdb = circuit->u.bc.adjdb[level - 1]; | |
204 | ||
205 | struct listnode *node, *nnode; | |
206 | struct isis_adjacency *adj; | |
207 | ||
208 | for (ALL_LIST_ELEMENTS(adjdb, node, nnode, adj)) | |
209 | bfd_adj_event(adj, &dst_ip, status); | |
210 | } | |
211 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { | |
212 | if (circuit->u.p2p.neighbor) { | |
213 | bfd_adj_event(circuit->u.p2p.neighbor, | |
214 | &dst_ip, status); | |
215 | } | |
216 | } | |
217 | ||
52df8228 CF |
218 | return 0; |
219 | } | |
220 | ||
121f9dee | 221 | static int isis_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) |
52df8228 | 222 | { |
0945d5ed | 223 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); |
ab880eaf CF |
224 | |
225 | struct listnode *anode; | |
226 | struct isis_area *area; | |
eab88f36 K |
227 | struct isis *isis = NULL; |
228 | ||
229 | isis = isis_lookup_by_vrfid(vrf_id); | |
230 | ||
231 | if (isis == NULL) { | |
232 | zlog_warn(" %s : ISIS routing instance not found", __func__); | |
233 | return -1; | |
234 | } | |
ab880eaf | 235 | |
e740f9c1 | 236 | if (IS_DEBUG_BFD) |
2815f817 CF |
237 | zlog_debug("ISIS-BFD: Got neighbor replay request, resending neighbors."); |
238 | ||
ab880eaf CF |
239 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { |
240 | struct listnode *cnode; | |
241 | struct isis_circuit *circuit; | |
242 | ||
243 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) | |
244 | isis_bfd_circuit_cmd(circuit, ZEBRA_BFD_DEST_UPDATE); | |
245 | } | |
246 | ||
e740f9c1 | 247 | if (IS_DEBUG_BFD) |
2815f817 CF |
248 | zlog_debug("ISIS-BFD: Done with replay."); |
249 | ||
52df8228 CF |
250 | return 0; |
251 | } | |
252 | ||
253 | static void (*orig_zebra_connected)(struct zclient *); | |
254 | static void isis_bfd_zebra_connected(struct zclient *zclient) | |
255 | { | |
256 | if (orig_zebra_connected) | |
257 | orig_zebra_connected(zclient); | |
258 | ||
0945d5ed | 259 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); |
52df8228 CF |
260 | } |
261 | ||
e782cca7 | 262 | static void bfd_debug(int family, union g_addr *dst, union g_addr *src, |
2815f817 CF |
263 | const char *interface, int command) |
264 | { | |
e740f9c1 | 265 | if (!(IS_DEBUG_BFD)) |
2815f817 CF |
266 | return; |
267 | ||
268 | char dst_str[INET6_ADDRSTRLEN]; | |
269 | char src_str[INET6_ADDRSTRLEN]; | |
270 | ||
e782cca7 RW |
271 | inet_ntop(family, dst, dst_str, sizeof(dst_str)); |
272 | inet_ntop(family, src, src_str, sizeof(src_str)); | |
2815f817 CF |
273 | |
274 | const char *command_str; | |
275 | ||
276 | switch (command) { | |
277 | case ZEBRA_BFD_DEST_REGISTER: | |
278 | command_str = "Register"; | |
279 | break; | |
280 | case ZEBRA_BFD_DEST_DEREGISTER: | |
281 | command_str = "Deregister"; | |
282 | break; | |
283 | case ZEBRA_BFD_DEST_UPDATE: | |
284 | command_str = "Update"; | |
285 | break; | |
286 | default: | |
287 | command_str = "Unknown-Cmd"; | |
288 | break; | |
289 | } | |
290 | ||
291 | zlog_debug("ISIS-BFD: %s peer %s on %s (src %s)", | |
292 | command_str, dst_str, interface, src_str); | |
293 | } | |
294 | ||
bb99eb5d G |
295 | static void bfd_command(int command, struct bfd_info *bfd_info, int family, |
296 | const void *dst_ip, const void *src_ip, | |
297 | const char *if_name) | |
298 | { | |
299 | struct bfd_session_arg args = {}; | |
300 | size_t addrlen; | |
301 | ||
302 | args.cbit = 1; | |
303 | args.family = family; | |
304 | args.vrf_id = VRF_DEFAULT; | |
305 | args.command = command; | |
306 | args.bfd_info = bfd_info; | |
307 | if (args.bfd_info) { | |
308 | args.min_rx = bfd_info->required_min_rx; | |
309 | args.min_tx = bfd_info->desired_min_tx; | |
310 | args.detection_multiplier = bfd_info->detect_mult; | |
311 | if (bfd_info->profile[0]) { | |
312 | args.profilelen = strlen(bfd_info->profile); | |
313 | strlcpy(args.profile, bfd_info->profile, | |
314 | sizeof(args.profile)); | |
315 | } | |
316 | } | |
317 | ||
318 | addrlen = family == AF_INET ? sizeof(struct in_addr) | |
319 | : sizeof(struct in6_addr); | |
320 | memcpy(&args.dst, dst_ip, addrlen); | |
321 | if (src_ip) | |
322 | memcpy(&args.src, src_ip, addrlen); | |
323 | ||
324 | if (if_name) { | |
325 | strlcpy(args.ifname, if_name, sizeof(args.ifname)); | |
326 | args.ifnamelen = strlen(args.ifname); | |
327 | } | |
328 | ||
329 | zclient_bfd_command(zclient, &args); | |
330 | } | |
331 | ||
20a42f01 CF |
332 | static void bfd_handle_adj_down(struct isis_adjacency *adj) |
333 | { | |
334 | if (!adj->bfd_session) | |
335 | return; | |
336 | ||
e782cca7 RW |
337 | bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip, |
338 | &adj->bfd_session->src_ip, adj->circuit->interface->name, | |
339 | ZEBRA_BFD_DEST_DEREGISTER); | |
2815f817 | 340 | |
bb99eb5d G |
341 | bfd_command(ZEBRA_BFD_DEST_DEREGISTER, NULL, adj->bfd_session->family, |
342 | &adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, | |
343 | (adj->circuit->interface) ? adj->circuit->interface->name | |
344 | : NULL); | |
345 | ||
20a42f01 CF |
346 | bfd_session_free(&adj->bfd_session); |
347 | } | |
348 | ||
349 | static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) | |
215eccb0 | 350 | { |
20a42f01 | 351 | struct isis_circuit *circuit = adj->circuit; |
e782cca7 RW |
352 | int family; |
353 | union g_addr dst_ip; | |
354 | union g_addr src_ip; | |
355 | struct list *local_ips; | |
356 | struct prefix *local_ip; | |
20a42f01 | 357 | |
980390ce EDP |
358 | if (!circuit->bfd_info) { |
359 | if (IS_DEBUG_BFD) | |
360 | zlog_debug( | |
361 | "ISIS-BFD: skipping BFD initialization on adjacency with %s because there is no bfd_info in the circuit", | |
362 | isis_adj_name(adj)); | |
20a42f01 | 363 | goto out; |
980390ce | 364 | } |
20a42f01 | 365 | |
2bec0447 KS |
366 | /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed |
367 | * before starting up BFD | |
368 | */ | |
0d5b1a3a EDP |
369 | if (circuit->ipv6_router |
370 | && (listcount(circuit->ipv6_link) == 0 | |
371 | || adj->ipv6_address_count == 0)) { | |
372 | if (IS_DEBUG_BFD) | |
373 | zlog_debug( | |
374 | "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready", | |
375 | isis_adj_name(adj)); | |
2bec0447 | 376 | return; |
0d5b1a3a | 377 | } |
2bec0447 | 378 | |
e782cca7 RW |
379 | /* |
380 | * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer | |
381 | * creating a BFD session over IPv6. | |
382 | */ | |
383 | if (circuit->ipv6_router && adj->ipv6_address_count) { | |
384 | family = AF_INET6; | |
385 | dst_ip.ipv6 = adj->ipv6_addresses[0]; | |
386 | local_ips = circuit->ipv6_link; | |
980390ce EDP |
387 | if (!local_ips || list_isempty(local_ips)) { |
388 | if (IS_DEBUG_BFD) | |
389 | zlog_debug( | |
390 | "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses"); | |
e782cca7 | 391 | goto out; |
980390ce | 392 | } |
e782cca7 RW |
393 | local_ip = listgetdata(listhead(local_ips)); |
394 | src_ip.ipv6 = local_ip->u.prefix6; | |
395 | } else if (circuit->ip_router && adj->ipv4_address_count) { | |
396 | family = AF_INET; | |
397 | dst_ip.ipv4 = adj->ipv4_addresses[0]; | |
398 | local_ips = fabricd_ip_addrs(adj->circuit); | |
980390ce EDP |
399 | if (!local_ips || list_isempty(local_ips)) { |
400 | if (IS_DEBUG_BFD) | |
401 | zlog_debug( | |
402 | "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses"); | |
e782cca7 | 403 | goto out; |
980390ce | 404 | } |
e782cca7 RW |
405 | local_ip = listgetdata(listhead(local_ips)); |
406 | src_ip.ipv4 = local_ip->u.prefix4; | |
407 | } else | |
20a42f01 CF |
408 | goto out; |
409 | ||
20a42f01 | 410 | if (adj->bfd_session) { |
e782cca7 RW |
411 | if (bfd_session_same(adj->bfd_session, family, &src_ip, |
412 | &dst_ip)) | |
20a42f01 CF |
413 | bfd_handle_adj_down(adj); |
414 | } | |
415 | ||
980390ce EDP |
416 | if (!adj->bfd_session) { |
417 | if (IS_DEBUG_BFD) | |
418 | zlog_debug( | |
419 | "ISIS-BFD: creating BFD session for adjacency with %s", | |
420 | isis_adj_name(adj)); | |
e782cca7 | 421 | adj->bfd_session = bfd_session_new(family, &dst_ip, &src_ip); |
980390ce | 422 | } |
20a42f01 | 423 | |
e782cca7 RW |
424 | bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip, |
425 | &adj->bfd_session->src_ip, circuit->interface->name, command); | |
bb99eb5d G |
426 | |
427 | bfd_command(command, circuit->bfd_info, family, | |
428 | &adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, | |
429 | (adj->circuit->interface) ? adj->circuit->interface->name | |
430 | : NULL); | |
431 | ||
215eccb0 | 432 | return; |
20a42f01 CF |
433 | out: |
434 | bfd_handle_adj_down(adj); | |
435 | } | |
436 | ||
437 | static int bfd_handle_adj_state_change(struct isis_adjacency *adj) | |
438 | { | |
439 | if (adj->adj_state == ISIS_ADJ_UP) | |
440 | bfd_handle_adj_up(adj, ZEBRA_BFD_DEST_REGISTER); | |
441 | else | |
442 | bfd_handle_adj_down(adj); | |
443 | return 0; | |
444 | } | |
445 | ||
446 | static void bfd_adj_cmd(struct isis_adjacency *adj, int command) | |
447 | { | |
448 | if (adj->adj_state == ISIS_ADJ_UP | |
449 | && command != ZEBRA_BFD_DEST_DEREGISTER) { | |
450 | bfd_handle_adj_up(adj, command); | |
451 | } else { | |
452 | bfd_handle_adj_down(adj); | |
453 | } | |
454 | } | |
455 | ||
456 | void isis_bfd_circuit_cmd(struct isis_circuit *circuit, int command) | |
457 | { | |
458 | switch (circuit->circ_type) { | |
459 | case CIRCUIT_T_BROADCAST: | |
460 | for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { | |
461 | struct list *adjdb = circuit->u.bc.adjdb[level - 1]; | |
462 | ||
463 | struct listnode *node; | |
464 | struct isis_adjacency *adj; | |
5489eb45 | 465 | |
20a42f01 CF |
466 | for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) |
467 | bfd_adj_cmd(adj, command); | |
468 | } | |
469 | break; | |
470 | case CIRCUIT_T_P2P: | |
471 | if (circuit->u.p2p.neighbor) | |
472 | bfd_adj_cmd(circuit->u.p2p.neighbor, command); | |
473 | break; | |
474 | default: | |
475 | break; | |
476 | } | |
215eccb0 CF |
477 | } |
478 | ||
4affdba7 G |
479 | void isis_bfd_circuit_param_set(struct isis_circuit *circuit, uint32_t min_rx, |
480 | uint32_t min_tx, uint32_t detect_mult, | |
481 | const char *profile, int defaults) | |
215eccb0 CF |
482 | { |
483 | int command = 0; | |
484 | ||
4affdba7 G |
485 | bfd_set_param(&circuit->bfd_info, min_rx, min_tx, detect_mult, profile, |
486 | defaults, &command); | |
215eccb0 CF |
487 | |
488 | if (command) | |
489 | isis_bfd_circuit_cmd(circuit, command); | |
490 | } | |
491 | ||
05e4ec37 | 492 | #ifdef FABRICD |
3015e3d1 CF |
493 | static int bfd_circuit_write_settings(struct isis_circuit *circuit, |
494 | struct vty *vty) | |
495 | { | |
496 | struct bfd_info *bfd_info = circuit->bfd_info; | |
497 | ||
498 | if (!bfd_info) | |
499 | return 0; | |
500 | ||
490a6fc7 | 501 | vty_out(vty, " %s bfd\n", PROTO_NAME); |
3015e3d1 CF |
502 | return 1; |
503 | } | |
05e4ec37 | 504 | #endif |
3015e3d1 | 505 | |
2bec0447 KS |
506 | static int bfd_handle_adj_ip_enabled(struct isis_adjacency *adj, int family) |
507 | { | |
508 | ||
509 | if (family != AF_INET6) | |
510 | return 0; | |
511 | ||
512 | if (adj->bfd_session) | |
513 | return 0; | |
514 | ||
515 | if (adj->adj_state != ISIS_ADJ_UP) | |
516 | return 0; | |
517 | ||
518 | bfd_handle_adj_up(adj, ZEBRA_BFD_DEST_REGISTER); | |
519 | ||
520 | return 0; | |
521 | } | |
522 | ||
523 | static int bfd_handle_circuit_add_addr(struct isis_circuit *circuit) | |
524 | { | |
525 | struct isis_adjacency *adj; | |
526 | struct listnode *node; | |
527 | ||
528 | if (circuit->area == 0) | |
529 | return 0; | |
530 | ||
531 | for (ALL_LIST_ELEMENTS_RO(circuit->area->adjacency_list, node, adj)) { | |
532 | if (adj->bfd_session) | |
533 | continue; | |
534 | ||
535 | if (adj->adj_state != ISIS_ADJ_UP) | |
536 | continue; | |
537 | ||
538 | bfd_handle_adj_up(adj, ZEBRA_BFD_DEST_REGISTER); | |
539 | } | |
540 | ||
541 | return 0; | |
542 | } | |
543 | ||
52df8228 CF |
544 | void isis_bfd_init(void) |
545 | { | |
546 | bfd_gbl_init(); | |
547 | ||
548 | orig_zebra_connected = zclient->zebra_connected; | |
549 | zclient->zebra_connected = isis_bfd_zebra_connected; | |
550 | zclient->interface_bfd_dest_update = isis_bfd_interface_dest_update; | |
551 | zclient->bfd_dest_replay = isis_bfd_nbr_replay; | |
20a42f01 CF |
552 | hook_register(isis_adj_state_change_hook, |
553 | bfd_handle_adj_state_change); | |
05e4ec37 | 554 | #ifdef FABRICD |
3015e3d1 CF |
555 | hook_register(isis_circuit_config_write, |
556 | bfd_circuit_write_settings); | |
05e4ec37 | 557 | #endif |
2bec0447 KS |
558 | hook_register(isis_adj_ip_enabled_hook, bfd_handle_adj_ip_enabled); |
559 | hook_register(isis_circuit_add_addr_hook, bfd_handle_circuit_add_addr); | |
52df8228 | 560 | } |