]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_bfd.c
Merge pull request #5366 from ton31337/fix/addpath_total_peer_update_7.1
[mirror_frr.git] / isisd / isis_bfd.c
CommitLineData
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"
22#include "bfd.h"
23
24#include "isisd/isis_bfd.h"
25#include "isisd/isis_zebra.h"
215eccb0
CF
26#include "isisd/isis_common.h"
27#include "isisd/isis_constants.h"
28#include "isisd/isis_adjacency.h"
29#include "isisd/isis_circuit.h"
3015e3d1 30#include "isisd/isisd.h"
215eccb0 31#include "isisd/fabricd.h"
52df8228 32
20a42f01
CF
33DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session")
34
35struct bfd_session {
36 struct in_addr dst_ip;
37 struct in_addr src_ip;
a5eba4e9 38 int status;
20a42f01
CF
39};
40
41static struct bfd_session *bfd_session_new(struct in_addr *dst_ip,
42 struct in_addr *src_ip)
43{
44 struct bfd_session *rv;
45
a5eba4e9 46 rv = XCALLOC(MTYPE_BFD_SESSION, sizeof(*rv));
20a42f01
CF
47 rv->dst_ip = *dst_ip;
48 rv->src_ip = *src_ip;
49 return rv;
50}
51
52static void bfd_session_free(struct bfd_session **session)
53{
54 if (!*session)
55 return;
56
57 XFREE(MTYPE_BFD_SESSION, *session);
58 *session = NULL;
59}
60
a5eba4e9
CF
61static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
62 int new_status)
63{
64 if (!adj->bfd_session)
65 return;
66
67 if (adj->bfd_session->dst_ip.s_addr != dst->u.prefix4.s_addr)
68 return;
69
70 int old_status = adj->bfd_session->status;
a5eba4e9 71
5489eb45 72 adj->bfd_session->status = new_status;
a5eba4e9
CF
73 if (old_status == new_status)
74 return;
75
76 if (isis->debugs & DEBUG_BFD) {
77 char dst_str[INET6_ADDRSTRLEN];
78
79 inet_ntop(AF_INET, &adj->bfd_session->dst_ip,
80 dst_str, sizeof(dst_str));
81 zlog_debug("ISIS-BFD: Peer %s on %s changed from %s to %s",
82 dst_str, adj->circuit->interface->name,
83 bfd_get_status_str(old_status),
84 bfd_get_status_str(new_status));
85 }
86
87 if (old_status != BFD_STATUS_UP
88 || new_status != BFD_STATUS_DOWN) {
89 return;
90 }
91
92 isis_adj_state_change(adj, ISIS_ADJ_DOWN, "bfd session went down");
93}
94
121f9dee 95static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
52df8228 96{
2815f817
CF
97 struct interface *ifp;
98 struct prefix dst_ip;
99 int status;
100
101 ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status, vrf_id);
102 if (!ifp || dst_ip.family != AF_INET)
103 return 0;
104
105 if (isis->debugs & DEBUG_BFD) {
106 char dst_buf[INET6_ADDRSTRLEN];
5489eb45 107
2815f817
CF
108 inet_ntop(AF_INET, &dst_ip.u.prefix4,
109 dst_buf, sizeof(dst_buf));
110
111 zlog_debug("ISIS-BFD: Received update for %s on %s: Changed state to %s",
112 dst_buf, ifp->name, bfd_get_status_str(status));
113 }
114
a5eba4e9 115 struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
5489eb45 116
a5eba4e9
CF
117 if (!circuit)
118 return 0;
119
120 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
121 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
122 struct list *adjdb = circuit->u.bc.adjdb[level - 1];
123
124 struct listnode *node, *nnode;
125 struct isis_adjacency *adj;
126
127 for (ALL_LIST_ELEMENTS(adjdb, node, nnode, adj))
128 bfd_adj_event(adj, &dst_ip, status);
129 }
130 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
131 if (circuit->u.p2p.neighbor) {
132 bfd_adj_event(circuit->u.p2p.neighbor,
133 &dst_ip, status);
134 }
135 }
136
52df8228
CF
137 return 0;
138}
139
121f9dee 140static int isis_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
52df8228
CF
141{
142 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
ab880eaf
CF
143
144 struct listnode *anode;
145 struct isis_area *area;
146
2815f817
CF
147 if (isis->debugs & DEBUG_BFD)
148 zlog_debug("ISIS-BFD: Got neighbor replay request, resending neighbors.");
149
ab880eaf
CF
150 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
151 struct listnode *cnode;
152 struct isis_circuit *circuit;
153
154 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
155 isis_bfd_circuit_cmd(circuit, ZEBRA_BFD_DEST_UPDATE);
156 }
157
2815f817
CF
158 if (isis->debugs & DEBUG_BFD)
159 zlog_debug("ISIS-BFD: Done with replay.");
160
52df8228
CF
161 return 0;
162}
163
164static void (*orig_zebra_connected)(struct zclient *);
165static void isis_bfd_zebra_connected(struct zclient *zclient)
166{
167 if (orig_zebra_connected)
168 orig_zebra_connected(zclient);
169
170 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
171}
172
2815f817
CF
173static void bfd_debug(struct in_addr *dst, struct in_addr *src,
174 const char *interface, int command)
175{
176 if (!(isis->debugs & DEBUG_BFD))
177 return;
178
179 char dst_str[INET6_ADDRSTRLEN];
180 char src_str[INET6_ADDRSTRLEN];
181
182 inet_ntop(AF_INET, dst, dst_str, sizeof(dst_str));
183 inet_ntop(AF_INET, src, src_str, sizeof(src_str));
184
185 const char *command_str;
186
187 switch (command) {
188 case ZEBRA_BFD_DEST_REGISTER:
189 command_str = "Register";
190 break;
191 case ZEBRA_BFD_DEST_DEREGISTER:
192 command_str = "Deregister";
193 break;
194 case ZEBRA_BFD_DEST_UPDATE:
195 command_str = "Update";
196 break;
197 default:
198 command_str = "Unknown-Cmd";
199 break;
200 }
201
202 zlog_debug("ISIS-BFD: %s peer %s on %s (src %s)",
203 command_str, dst_str, interface, src_str);
204}
205
20a42f01
CF
206static void bfd_handle_adj_down(struct isis_adjacency *adj)
207{
208 if (!adj->bfd_session)
209 return;
210
2815f817
CF
211 bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
212 adj->circuit->interface->name, ZEBRA_BFD_DEST_DEREGISTER);
213
20a42f01
CF
214 bfd_peer_sendmsg(zclient, NULL, AF_INET,
215 &adj->bfd_session->dst_ip,
216 &adj->bfd_session->src_ip,
217 adj->circuit->interface->name,
218 0, /* ttl */
219 0, /* multihop */
220 ZEBRA_BFD_DEST_DEREGISTER,
221 0, /* set_flag */
222 VRF_DEFAULT);
223 bfd_session_free(&adj->bfd_session);
224}
225
226static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
215eccb0 227{
20a42f01
CF
228 struct isis_circuit *circuit = adj->circuit;
229
230 if (!circuit->bfd_info
231 || !circuit->ip_router
232 || !adj->ipv4_address_count)
233 goto out;
234
235 struct list *local_ips = fabricd_ip_addrs(adj->circuit);
5489eb45 236
20a42f01
CF
237 if (!local_ips)
238 goto out;
239
240 struct in_addr *dst_ip = &adj->ipv4_addresses[0];
241 struct prefix_ipv4 *local_ip = listgetdata(listhead(local_ips));
242 struct in_addr *src_ip = &local_ip->prefix;
243
244 if (adj->bfd_session) {
245 if (adj->bfd_session->dst_ip.s_addr != dst_ip->s_addr
246 || adj->bfd_session->src_ip.s_addr != src_ip->s_addr)
247 bfd_handle_adj_down(adj);
248 }
249
250 if (!adj->bfd_session)
251 adj->bfd_session = bfd_session_new(dst_ip, src_ip);
252
2815f817
CF
253 bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
254 circuit->interface->name, command);
20a42f01
CF
255 bfd_peer_sendmsg(zclient, circuit->bfd_info, AF_INET,
256 &adj->bfd_session->dst_ip,
257 &adj->bfd_session->src_ip,
258 circuit->interface->name,
259 0, /* ttl */
260 0, /* multihop */
261 command,
262 0, /* set flag */
263 VRF_DEFAULT);
215eccb0 264 return;
20a42f01
CF
265out:
266 bfd_handle_adj_down(adj);
267}
268
269static int bfd_handle_adj_state_change(struct isis_adjacency *adj)
270{
271 if (adj->adj_state == ISIS_ADJ_UP)
272 bfd_handle_adj_up(adj, ZEBRA_BFD_DEST_REGISTER);
273 else
274 bfd_handle_adj_down(adj);
275 return 0;
276}
277
278static void bfd_adj_cmd(struct isis_adjacency *adj, int command)
279{
280 if (adj->adj_state == ISIS_ADJ_UP
281 && command != ZEBRA_BFD_DEST_DEREGISTER) {
282 bfd_handle_adj_up(adj, command);
283 } else {
284 bfd_handle_adj_down(adj);
285 }
286}
287
288void isis_bfd_circuit_cmd(struct isis_circuit *circuit, int command)
289{
290 switch (circuit->circ_type) {
291 case CIRCUIT_T_BROADCAST:
292 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
293 struct list *adjdb = circuit->u.bc.adjdb[level - 1];
294
295 struct listnode *node;
296 struct isis_adjacency *adj;
5489eb45 297
20a42f01
CF
298 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
299 bfd_adj_cmd(adj, command);
300 }
301 break;
302 case CIRCUIT_T_P2P:
303 if (circuit->u.p2p.neighbor)
304 bfd_adj_cmd(circuit->u.p2p.neighbor, command);
305 break;
306 default:
307 break;
308 }
215eccb0
CF
309}
310
311void isis_bfd_circuit_param_set(struct isis_circuit *circuit,
312 uint32_t min_rx, uint32_t min_tx,
313 uint32_t detect_mult, int defaults)
314{
315 int command = 0;
316
317 bfd_set_param(&circuit->bfd_info, min_rx,
318 min_tx, detect_mult, defaults, &command);
319
320 if (command)
321 isis_bfd_circuit_cmd(circuit, command);
322}
323
3015e3d1
CF
324static int bfd_circuit_write_settings(struct isis_circuit *circuit,
325 struct vty *vty)
326{
327 struct bfd_info *bfd_info = circuit->bfd_info;
328
329 if (!bfd_info)
330 return 0;
331
490a6fc7 332 vty_out(vty, " %s bfd\n", PROTO_NAME);
3015e3d1
CF
333 return 1;
334}
335
52df8228
CF
336void isis_bfd_init(void)
337{
338 bfd_gbl_init();
339
340 orig_zebra_connected = zclient->zebra_connected;
341 zclient->zebra_connected = isis_bfd_zebra_connected;
342 zclient->interface_bfd_dest_update = isis_bfd_interface_dest_update;
343 zclient->bfd_dest_replay = isis_bfd_nbr_replay;
20a42f01
CF
344 hook_register(isis_adj_state_change_hook,
345 bfd_handle_adj_state_change);
3015e3d1
CF
346 hook_register(isis_circuit_config_write,
347 bfd_circuit_write_settings);
52df8228 348}