2 * IS-IS Rout(e)ing protocol - BFD support
4 * Copyright (C) 2018 Christian Franke
6 * This file is part of FreeRangeRouting (FRR)
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "isisd/isis_bfd.h"
28 #include "isisd/isis_zebra.h"
29 #include "isisd/isis_common.h"
30 #include "isisd/isis_constants.h"
31 #include "isisd/isis_adjacency.h"
32 #include "isisd/isis_circuit.h"
33 #include "isisd/isisd.h"
34 #include "isisd/fabricd.h"
36 DEFINE_MTYPE_STATIC(ISISD
, BFD_SESSION
, "ISIS BFD Session")
39 struct in_addr dst_ip
;
40 struct in_addr src_ip
;
44 static struct bfd_session
*bfd_session_new(struct in_addr
*dst_ip
,
45 struct in_addr
*src_ip
)
47 struct bfd_session
*rv
;
49 rv
= XCALLOC(MTYPE_BFD_SESSION
, sizeof(*rv
));
55 static void bfd_session_free(struct bfd_session
**session
)
60 XFREE(MTYPE_BFD_SESSION
, *session
);
64 static void bfd_adj_event(struct isis_adjacency
*adj
, struct prefix
*dst
,
67 if (!adj
->bfd_session
)
70 if (adj
->bfd_session
->dst_ip
.s_addr
!= dst
->u
.prefix4
.s_addr
)
73 int old_status
= adj
->bfd_session
->status
;
75 adj
->bfd_session
->status
= new_status
;
76 if (old_status
== new_status
)
79 if (isis
->debugs
& DEBUG_BFD
) {
80 char dst_str
[INET6_ADDRSTRLEN
];
82 inet_ntop(AF_INET
, &adj
->bfd_session
->dst_ip
,
83 dst_str
, sizeof(dst_str
));
84 zlog_debug("ISIS-BFD: Peer %s on %s changed from %s to %s",
85 dst_str
, adj
->circuit
->interface
->name
,
86 bfd_get_status_str(old_status
),
87 bfd_get_status_str(new_status
));
90 if (old_status
!= BFD_STATUS_UP
91 || new_status
!= BFD_STATUS_DOWN
) {
95 isis_adj_state_change(adj
, ISIS_ADJ_DOWN
, "bfd session went down");
98 static int isis_bfd_interface_dest_update(int command
, struct zclient
*zclient
,
99 zebra_size_t length
, vrf_id_t vrf_id
)
101 struct interface
*ifp
;
102 struct prefix dst_ip
;
105 ifp
= bfd_get_peer_info(zclient
->ibuf
, &dst_ip
, NULL
, &status
, vrf_id
);
106 if (!ifp
|| dst_ip
.family
!= AF_INET
)
109 if (isis
->debugs
& DEBUG_BFD
) {
110 char dst_buf
[INET6_ADDRSTRLEN
];
112 inet_ntop(AF_INET
, &dst_ip
.u
.prefix4
,
113 dst_buf
, sizeof(dst_buf
));
115 zlog_debug("ISIS-BFD: Received update for %s on %s: Changed state to %s",
116 dst_buf
, ifp
->name
, bfd_get_status_str(status
));
119 struct isis_circuit
*circuit
= circuit_scan_by_ifp(ifp
);
124 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
125 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
126 struct list
*adjdb
= circuit
->u
.bc
.adjdb
[level
- 1];
128 struct listnode
*node
, *nnode
;
129 struct isis_adjacency
*adj
;
131 for (ALL_LIST_ELEMENTS(adjdb
, node
, nnode
, adj
))
132 bfd_adj_event(adj
, &dst_ip
, status
);
134 } else if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
135 if (circuit
->u
.p2p
.neighbor
) {
136 bfd_adj_event(circuit
->u
.p2p
.neighbor
,
144 static int isis_bfd_nbr_replay(int command
, struct zclient
*zclient
,
145 zebra_size_t length
, vrf_id_t vrf_id
)
147 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
149 struct listnode
*anode
;
150 struct isis_area
*area
;
152 if (isis
->debugs
& DEBUG_BFD
)
153 zlog_debug("ISIS-BFD: Got neighbor replay request, resending neighbors.");
155 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
, area
)) {
156 struct listnode
*cnode
;
157 struct isis_circuit
*circuit
;
159 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
160 isis_bfd_circuit_cmd(circuit
, ZEBRA_BFD_DEST_UPDATE
);
163 if (isis
->debugs
& DEBUG_BFD
)
164 zlog_debug("ISIS-BFD: Done with replay.");
169 static void (*orig_zebra_connected
)(struct zclient
*);
170 static void isis_bfd_zebra_connected(struct zclient
*zclient
)
172 if (orig_zebra_connected
)
173 orig_zebra_connected(zclient
);
175 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
178 static void bfd_debug(struct in_addr
*dst
, struct in_addr
*src
,
179 const char *interface
, int command
)
181 if (!(isis
->debugs
& DEBUG_BFD
))
184 char dst_str
[INET6_ADDRSTRLEN
];
185 char src_str
[INET6_ADDRSTRLEN
];
187 inet_ntop(AF_INET
, dst
, dst_str
, sizeof(dst_str
));
188 inet_ntop(AF_INET
, src
, src_str
, sizeof(src_str
));
190 const char *command_str
;
193 case ZEBRA_BFD_DEST_REGISTER
:
194 command_str
= "Register";
196 case ZEBRA_BFD_DEST_DEREGISTER
:
197 command_str
= "Deregister";
199 case ZEBRA_BFD_DEST_UPDATE
:
200 command_str
= "Update";
203 command_str
= "Unknown-Cmd";
207 zlog_debug("ISIS-BFD: %s peer %s on %s (src %s)",
208 command_str
, dst_str
, interface
, src_str
);
211 static void bfd_handle_adj_down(struct isis_adjacency
*adj
)
213 if (!adj
->bfd_session
)
216 bfd_debug(&adj
->bfd_session
->dst_ip
, &adj
->bfd_session
->src_ip
,
217 adj
->circuit
->interface
->name
, ZEBRA_BFD_DEST_DEREGISTER
);
219 bfd_peer_sendmsg(zclient
, NULL
, AF_INET
,
220 &adj
->bfd_session
->dst_ip
,
221 &adj
->bfd_session
->src_ip
,
222 adj
->circuit
->interface
->name
,
225 ZEBRA_BFD_DEST_DEREGISTER
,
228 bfd_session_free(&adj
->bfd_session
);
231 static void bfd_handle_adj_up(struct isis_adjacency
*adj
, int command
)
233 struct isis_circuit
*circuit
= adj
->circuit
;
235 if (!circuit
->bfd_info
236 || !circuit
->ip_router
237 || !adj
->ipv4_address_count
)
240 struct list
*local_ips
= fabricd_ip_addrs(adj
->circuit
);
245 struct in_addr
*dst_ip
= &adj
->ipv4_addresses
[0];
246 struct prefix_ipv4
*local_ip
= listgetdata(listhead(local_ips
));
247 struct in_addr
*src_ip
= &local_ip
->prefix
;
249 if (adj
->bfd_session
) {
250 if (adj
->bfd_session
->dst_ip
.s_addr
!= dst_ip
->s_addr
251 || adj
->bfd_session
->src_ip
.s_addr
!= src_ip
->s_addr
)
252 bfd_handle_adj_down(adj
);
255 if (!adj
->bfd_session
)
256 adj
->bfd_session
= bfd_session_new(dst_ip
, src_ip
);
258 bfd_debug(&adj
->bfd_session
->dst_ip
, &adj
->bfd_session
->src_ip
,
259 circuit
->interface
->name
, command
);
260 bfd_peer_sendmsg(zclient
, circuit
->bfd_info
, AF_INET
,
261 &adj
->bfd_session
->dst_ip
,
262 &adj
->bfd_session
->src_ip
,
263 circuit
->interface
->name
,
271 bfd_handle_adj_down(adj
);
274 static int bfd_handle_adj_state_change(struct isis_adjacency
*adj
)
276 if (adj
->adj_state
== ISIS_ADJ_UP
)
277 bfd_handle_adj_up(adj
, ZEBRA_BFD_DEST_REGISTER
);
279 bfd_handle_adj_down(adj
);
283 static void bfd_adj_cmd(struct isis_adjacency
*adj
, int command
)
285 if (adj
->adj_state
== ISIS_ADJ_UP
286 && command
!= ZEBRA_BFD_DEST_DEREGISTER
) {
287 bfd_handle_adj_up(adj
, command
);
289 bfd_handle_adj_down(adj
);
293 void isis_bfd_circuit_cmd(struct isis_circuit
*circuit
, int command
)
295 switch (circuit
->circ_type
) {
296 case CIRCUIT_T_BROADCAST
:
297 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
298 struct list
*adjdb
= circuit
->u
.bc
.adjdb
[level
- 1];
300 struct listnode
*node
;
301 struct isis_adjacency
*adj
;
303 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
))
304 bfd_adj_cmd(adj
, command
);
308 if (circuit
->u
.p2p
.neighbor
)
309 bfd_adj_cmd(circuit
->u
.p2p
.neighbor
, command
);
316 void isis_bfd_circuit_param_set(struct isis_circuit
*circuit
,
317 uint32_t min_rx
, uint32_t min_tx
,
318 uint32_t detect_mult
, int defaults
)
322 bfd_set_param(&circuit
->bfd_info
, min_rx
,
323 min_tx
, detect_mult
, defaults
, &command
);
326 isis_bfd_circuit_cmd(circuit
, command
);
329 static int bfd_circuit_write_settings(struct isis_circuit
*circuit
,
332 struct bfd_info
*bfd_info
= circuit
->bfd_info
;
337 vty_out(vty
, " %s bfd\n", PROTO_NAME
);
341 void isis_bfd_init(void)
345 orig_zebra_connected
= zclient
->zebra_connected
;
346 zclient
->zebra_connected
= isis_bfd_zebra_connected
;
347 zclient
->interface_bfd_dest_update
= isis_bfd_interface_dest_update
;
348 zclient
->bfd_dest_replay
= isis_bfd_nbr_replay
;
349 hook_register(isis_adj_state_change_hook
,
350 bfd_handle_adj_state_change
);
351 hook_register(isis_circuit_config_write
,
352 bfd_circuit_write_settings
);