]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_bfd.c
isisd: Address code-style warnings
[mirror_frr.git] / isisd / isis_bfd.c
1 /*
2 * IS-IS Rout(e)ing protocol - BFD support
3 *
4 * Copyright (C) 2018 Christian Franke
5 *
6 * This file is part of FreeRangeRouting (FRR)
7 *
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
11 * later version.
12 *
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.
17 *
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
21 */
22 #include <zebra.h>
23
24 #include "zclient.h"
25 #include "bfd.h"
26
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"
35
36 DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session")
37
38 struct bfd_session {
39 struct in_addr dst_ip;
40 struct in_addr src_ip;
41 int status;
42 };
43
44 static struct bfd_session *bfd_session_new(struct in_addr *dst_ip,
45 struct in_addr *src_ip)
46 {
47 struct bfd_session *rv;
48
49 rv = XCALLOC(MTYPE_BFD_SESSION, sizeof(*rv));
50 rv->dst_ip = *dst_ip;
51 rv->src_ip = *src_ip;
52 return rv;
53 }
54
55 static void bfd_session_free(struct bfd_session **session)
56 {
57 if (!*session)
58 return;
59
60 XFREE(MTYPE_BFD_SESSION, *session);
61 *session = NULL;
62 }
63
64 static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
65 int new_status)
66 {
67 if (!adj->bfd_session)
68 return;
69
70 if (adj->bfd_session->dst_ip.s_addr != dst->u.prefix4.s_addr)
71 return;
72
73 int old_status = adj->bfd_session->status;
74
75 adj->bfd_session->status = new_status;
76 if (old_status == new_status)
77 return;
78
79 if (isis->debugs & DEBUG_BFD) {
80 char dst_str[INET6_ADDRSTRLEN];
81
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));
88 }
89
90 if (old_status != BFD_STATUS_UP
91 || new_status != BFD_STATUS_DOWN) {
92 return;
93 }
94
95 isis_adj_state_change(adj, ISIS_ADJ_DOWN, "bfd session went down");
96 }
97
98 static int isis_bfd_interface_dest_update(int command, struct zclient *zclient,
99 zebra_size_t length, vrf_id_t vrf_id)
100 {
101 struct interface *ifp;
102 struct prefix dst_ip;
103 int status;
104
105 ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status, vrf_id);
106 if (!ifp || dst_ip.family != AF_INET)
107 return 0;
108
109 if (isis->debugs & DEBUG_BFD) {
110 char dst_buf[INET6_ADDRSTRLEN];
111
112 inet_ntop(AF_INET, &dst_ip.u.prefix4,
113 dst_buf, sizeof(dst_buf));
114
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));
117 }
118
119 struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
120
121 if (!circuit)
122 return 0;
123
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];
127
128 struct listnode *node, *nnode;
129 struct isis_adjacency *adj;
130
131 for (ALL_LIST_ELEMENTS(adjdb, node, nnode, adj))
132 bfd_adj_event(adj, &dst_ip, status);
133 }
134 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
135 if (circuit->u.p2p.neighbor) {
136 bfd_adj_event(circuit->u.p2p.neighbor,
137 &dst_ip, status);
138 }
139 }
140
141 return 0;
142 }
143
144 static int isis_bfd_nbr_replay(int command, struct zclient *zclient,
145 zebra_size_t length, vrf_id_t vrf_id)
146 {
147 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
148
149 struct listnode *anode;
150 struct isis_area *area;
151
152 if (isis->debugs & DEBUG_BFD)
153 zlog_debug("ISIS-BFD: Got neighbor replay request, resending neighbors.");
154
155 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
156 struct listnode *cnode;
157 struct isis_circuit *circuit;
158
159 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
160 isis_bfd_circuit_cmd(circuit, ZEBRA_BFD_DEST_UPDATE);
161 }
162
163 if (isis->debugs & DEBUG_BFD)
164 zlog_debug("ISIS-BFD: Done with replay.");
165
166 return 0;
167 }
168
169 static void (*orig_zebra_connected)(struct zclient *);
170 static void isis_bfd_zebra_connected(struct zclient *zclient)
171 {
172 if (orig_zebra_connected)
173 orig_zebra_connected(zclient);
174
175 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
176 }
177
178 static void bfd_debug(struct in_addr *dst, struct in_addr *src,
179 const char *interface, int command)
180 {
181 if (!(isis->debugs & DEBUG_BFD))
182 return;
183
184 char dst_str[INET6_ADDRSTRLEN];
185 char src_str[INET6_ADDRSTRLEN];
186
187 inet_ntop(AF_INET, dst, dst_str, sizeof(dst_str));
188 inet_ntop(AF_INET, src, src_str, sizeof(src_str));
189
190 const char *command_str;
191
192 switch (command) {
193 case ZEBRA_BFD_DEST_REGISTER:
194 command_str = "Register";
195 break;
196 case ZEBRA_BFD_DEST_DEREGISTER:
197 command_str = "Deregister";
198 break;
199 case ZEBRA_BFD_DEST_UPDATE:
200 command_str = "Update";
201 break;
202 default:
203 command_str = "Unknown-Cmd";
204 break;
205 }
206
207 zlog_debug("ISIS-BFD: %s peer %s on %s (src %s)",
208 command_str, dst_str, interface, src_str);
209 }
210
211 static void bfd_handle_adj_down(struct isis_adjacency *adj)
212 {
213 if (!adj->bfd_session)
214 return;
215
216 bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
217 adj->circuit->interface->name, ZEBRA_BFD_DEST_DEREGISTER);
218
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,
223 0, /* ttl */
224 0, /* multihop */
225 ZEBRA_BFD_DEST_DEREGISTER,
226 0, /* set_flag */
227 VRF_DEFAULT);
228 bfd_session_free(&adj->bfd_session);
229 }
230
231 static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
232 {
233 struct isis_circuit *circuit = adj->circuit;
234
235 if (!circuit->bfd_info
236 || !circuit->ip_router
237 || !adj->ipv4_address_count)
238 goto out;
239
240 struct list *local_ips = fabricd_ip_addrs(adj->circuit);
241
242 if (!local_ips)
243 goto out;
244
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;
248
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);
253 }
254
255 if (!adj->bfd_session)
256 adj->bfd_session = bfd_session_new(dst_ip, src_ip);
257
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,
264 0, /* ttl */
265 0, /* multihop */
266 command,
267 0, /* set flag */
268 VRF_DEFAULT);
269 return;
270 out:
271 bfd_handle_adj_down(adj);
272 }
273
274 static int bfd_handle_adj_state_change(struct isis_adjacency *adj)
275 {
276 if (adj->adj_state == ISIS_ADJ_UP)
277 bfd_handle_adj_up(adj, ZEBRA_BFD_DEST_REGISTER);
278 else
279 bfd_handle_adj_down(adj);
280 return 0;
281 }
282
283 static void bfd_adj_cmd(struct isis_adjacency *adj, int command)
284 {
285 if (adj->adj_state == ISIS_ADJ_UP
286 && command != ZEBRA_BFD_DEST_DEREGISTER) {
287 bfd_handle_adj_up(adj, command);
288 } else {
289 bfd_handle_adj_down(adj);
290 }
291 }
292
293 void isis_bfd_circuit_cmd(struct isis_circuit *circuit, int command)
294 {
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];
299
300 struct listnode *node;
301 struct isis_adjacency *adj;
302
303 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
304 bfd_adj_cmd(adj, command);
305 }
306 break;
307 case CIRCUIT_T_P2P:
308 if (circuit->u.p2p.neighbor)
309 bfd_adj_cmd(circuit->u.p2p.neighbor, command);
310 break;
311 default:
312 break;
313 }
314 }
315
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)
319 {
320 int command = 0;
321
322 bfd_set_param(&circuit->bfd_info, min_rx,
323 min_tx, detect_mult, defaults, &command);
324
325 if (command)
326 isis_bfd_circuit_cmd(circuit, command);
327 }
328
329 static int bfd_circuit_write_settings(struct isis_circuit *circuit,
330 struct vty *vty)
331 {
332 struct bfd_info *bfd_info = circuit->bfd_info;
333
334 if (!bfd_info)
335 return 0;
336
337 vty_out(vty, " %s bfd\n", PROTO_NAME);
338 return 1;
339 }
340
341 void isis_bfd_init(void)
342 {
343 bfd_gbl_init();
344
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);
353 }