]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_bfd.c
Support of BFD status in Quagga
[mirror_frr.git] / ospf6d / ospf6_bfd.c
1 /**
2 * ospf6_bfd.c: IPv6 OSPF BFD handling routines
3 *
4 * @copyright Copyright (C) 2015 Cumulus Networks, Inc.
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra 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 * GNU Zebra 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
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24 #include <zebra.h>
25
26 #include "command.h"
27 #include "linklist.h"
28 #include "memory.h"
29 #include "prefix.h"
30 #include "thread.h"
31 #include "buffer.h"
32 #include "stream.h"
33 #include "zclient.h"
34 #include "vty.h"
35 #include "table.h"
36 #include "bfd.h"
37 #include "if.h"
38 #include "ospf6d.h"
39 #include "ospf6_message.h"
40 #include "ospf6_neighbor.h"
41 #include "ospf6_interface.h"
42 #include "ospf6_route.h"
43 #include "ospf6_zebra.h"
44 #include "ospf6_bfd.h"
45
46 extern struct zclient *zclient;
47
48 /*
49 * ospf6_bfd_info_free - Free BFD info structure
50 */
51 void
52 ospf6_bfd_info_free(void **bfd_info)
53 {
54 bfd_info_free((struct bfd_info **) bfd_info);
55 }
56
57 /*
58 * ospf6_bfd_show_info - Show BFD info structure
59 */
60 void
61 ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only)
62 {
63 if (param_only)
64 bfd_show_param(vty, bfd_info, 1, 0, 0, NULL);
65 else
66 bfd_show_info(vty, bfd_info, 0, 1, 0, NULL);
67 }
68
69 /*
70 * ospf6_bfd_reg_dereg_nbr - Register/Deregister a neighbor with BFD through
71 * zebra for starting/stopping the monitoring of
72 * the neighbor rechahability.
73 */
74 static void
75 ospf6_bfd_reg_dereg_nbr (struct ospf6_neighbor *on, int command)
76 {
77 struct ospf6_interface *oi = on->ospf6_if;
78 struct interface *ifp = oi->interface;
79 struct bfd_info *bfd_info;
80 char src[64];
81
82 if (!oi->bfd_info)
83 return;
84 bfd_info = (struct bfd_info *)oi->bfd_info;
85
86 if (IS_OSPF6_DEBUG_ZEBRA(SEND))
87 {
88 inet_ntop (AF_INET6, &on->linklocal_addr, src, sizeof (src));
89 zlog_debug ("%s nbr (%s) with BFD",
90 bfd_get_command_dbg_str(command), src);
91 }
92
93 bfd_peer_sendmsg (zclient, bfd_info, AF_INET6, &on->linklocal_addr,
94 on->ospf6_if->linklocal_addr, ifp->name,
95 0, 0, command, 0);
96 }
97
98 /*
99 * ospf6_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
100 * neighbor state is changed to/from 2way.
101 */
102 void
103 ospf6_bfd_trigger_event(struct ospf6_neighbor *on, int old_state, int state)
104 {
105 if ((old_state < OSPF6_NEIGHBOR_TWOWAY) && (state >= OSPF6_NEIGHBOR_TWOWAY))
106 ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_REGISTER);
107 else if ((old_state >= OSPF6_NEIGHBOR_TWOWAY) &&
108 (state < OSPF6_NEIGHBOR_TWOWAY))
109 ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_DEREGISTER);
110 }
111
112 /*
113 * ospf6_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated
114 * with a interface with BFD through
115 * zebra for starting/stopping the monitoring of
116 * the neighbor rechahability.
117 */
118 static void
119 ospf6_bfd_reg_dereg_all_nbr (struct ospf6_interface *oi, int command)
120 {
121 struct ospf6_neighbor *on;
122 struct listnode *node;
123
124 for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, node, on))
125 {
126 if (command != ZEBRA_BFD_DEST_DEREGISTER)
127 ospf6_bfd_info_nbr_create(oi, on);
128 else
129 bfd_info_free((struct bfd_info **)&on->bfd_info);
130
131 if (on->state < OSPF6_NEIGHBOR_TWOWAY)
132 continue;
133
134 ospf6_bfd_reg_dereg_nbr(on, command);
135 }
136 }
137
138 /*
139 * ospf6_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
140 * to zebra
141 */
142 static int
143 ospf6_bfd_nbr_replay (int command, struct zclient *client, zebra_size_t length)
144 {
145 struct listnode *inode, *nnode;
146 struct interface *ifp;
147 struct ospf6_interface *oi;
148 struct ospf6_neighbor *on;
149 char dst[64];
150
151 if (IS_OSPF6_DEBUG_ZEBRA(RECV))
152 zlog_debug("Zebra: BFD Dest replay request");
153
154 /* Replay the neighbor, if BFD is enabled on the interface*/
155 for (ALL_LIST_ELEMENTS_RO (iflist, inode, ifp))
156 {
157 oi = (struct ospf6_interface *) ifp->info;
158
159 if (!oi || !oi->bfd_info)
160 continue;
161
162 for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, nnode, on))
163 {
164 if (on->state < OSPF6_NEIGHBOR_TWOWAY)
165 continue;
166
167 if (IS_OSPF6_DEBUG_ZEBRA(SEND))
168 {
169 inet_ntop (AF_INET6, &on->linklocal_addr, dst, sizeof (dst));
170 zlog_debug ("Replaying nbr (%s) to BFD", dst);
171 }
172
173 ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_UPDATE);
174 }
175 }
176 return 0;
177 }
178
179 /*
180 * ospf6_bfd_interface_dest_update - Find the neighbor for which the BFD status
181 * has changed and bring down the neighbor
182 * connectivity if BFD down is received.
183 */
184 static int
185 ospf6_bfd_interface_dest_update (int command, struct zclient *zclient,
186 zebra_size_t length)
187 {
188 struct interface *ifp;
189 struct ospf6_interface *oi;
190 struct ospf6_neighbor *on;
191 struct prefix dp;
192 struct prefix sp;
193 struct listnode *node, *nnode;
194 char dst[64];
195 int status;
196 int old_status;
197 struct bfd_info *bfd_info;
198 struct timeval tv;
199
200 ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status);
201
202 if ((ifp == NULL) || (dp.family != AF_INET6))
203 return 0;
204
205 if (IS_OSPF6_DEBUG_ZEBRA (RECV))
206 {
207 char buf[128];
208 prefix2str(&dp, buf, sizeof(buf));
209 zlog_debug("Zebra: interface %s bfd destination %s %s", ifp->name, buf,
210 bfd_get_status_str(status));
211 }
212
213
214 oi = (struct ospf6_interface *) ifp->info;
215 if (!oi || !oi->bfd_info)
216 return 0;
217
218 for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on))
219 {
220 if (memcmp(&(on->linklocal_addr), &dp.u.prefix6, sizeof(struct in6_addr)))
221 continue;
222
223 if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
224 {
225 inet_ntop (AF_INET6, &on->linklocal_addr, dst, sizeof (dst));
226 zlog_debug ("[%s:%s]: BFD %s", ifp->name, dst,
227 bfd_get_status_str(status));
228 }
229
230 if (!on->bfd_info)
231 continue;
232
233 bfd_info = (struct bfd_info *)on->bfd_info;
234 if (bfd_info->status == status)
235 continue;
236
237 old_status = bfd_info->status;
238 bfd_info->status = status;
239 quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv);
240 bfd_info->last_update = tv.tv_sec;
241
242 if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP))
243 {
244 THREAD_OFF (on->inactivity_timer);
245 thread_add_event (master, inactivity_timer, on, 0);
246 }
247 }
248
249 return 0;
250 }
251
252 /*
253 * ospf6_bfd_info_nbr_create - Create/update BFD information for a neighbor.
254 */
255 void
256 ospf6_bfd_info_nbr_create (struct ospf6_interface *oi,
257 struct ospf6_neighbor *on)
258 {
259 struct bfd_info *oi_bfd_info;
260 struct bfd_info *on_bfd_info;
261
262 if (!oi->bfd_info)
263 return;
264
265 oi_bfd_info = (struct bfd_info *)oi->bfd_info;
266
267 if (!on->bfd_info)
268 on->bfd_info = bfd_info_create();
269
270 on_bfd_info = (struct bfd_info *)on->bfd_info;
271 on_bfd_info->detect_mult = oi_bfd_info->detect_mult;
272 on_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx;
273 on_bfd_info->required_min_rx = oi_bfd_info->required_min_rx;
274 }
275
276 /*
277 * ospf6_bfd_write_config - Write the interface BFD configuration.
278 */
279 void
280 ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
281 {
282 struct bfd_info *bfd_info;
283
284 if (!oi->bfd_info)
285 return;
286
287 bfd_info = (struct bfd_info *)oi->bfd_info;
288
289 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
290 vty_out (vty, " ipv6 ospf6 bfd %d %d %d%s",
291 bfd_info->detect_mult, bfd_info->required_min_rx,
292 bfd_info->desired_min_tx, VTY_NEWLINE);
293 else
294 vty_out (vty, " ipv6 ospf6 bfd%s", VTY_NEWLINE);
295 }
296
297 /*
298 * ospf6_bfd_if_param_set - Set the configured BFD paramter values for
299 * interface.
300 */
301 static void
302 ospf6_bfd_if_param_set (struct ospf6_interface *oi, u_int32_t min_rx,
303 u_int32_t min_tx, u_int8_t detect_mult,
304 int defaults)
305 {
306 int command = 0;
307
308 bfd_set_param((struct bfd_info **)&(oi->bfd_info), min_rx, min_tx, detect_mult,
309 defaults, &command);
310 if (command)
311 ospf6_bfd_reg_dereg_all_nbr(oi, command);
312 }
313
314 DEFUN (ipv6_ospf6_bfd,
315 ipv6_ospf6_bfd_cmd,
316 "ipv6 ospf6 bfd",
317 IP6_STR
318 OSPF6_STR
319 "Enables BFD support\n"
320 )
321 {
322 struct ospf6_interface *oi;
323 struct interface *ifp;
324
325 ifp = (struct interface *) vty->index;
326 assert (ifp);
327
328 oi = (struct ospf6_interface *) ifp->info;
329 if (oi == NULL)
330 oi = ospf6_interface_create (ifp);
331 assert (oi);
332
333 ospf6_bfd_if_param_set (oi, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
334 BFD_DEF_DETECT_MULT, 1);
335 return CMD_SUCCESS;
336 }
337
338 DEFUN (ipv6_ospf6_bfd_param,
339 ipv6_ospf6_bfd_param_cmd,
340 "ipv6 ospf6 bfd " BFD_CMD_DETECT_MULT_RANGE BFD_CMD_MIN_RX_RANGE BFD_CMD_MIN_TX_RANGE,
341 IP6_STR
342 OSPF6_STR
343 "Enables BFD support\n"
344 "Detect Multiplier\n"
345 "Required min receive interval\n"
346 "Desired min transmit interval\n")
347 {
348 struct ospf6_interface *oi;
349 struct interface *ifp;
350 u_int32_t rx_val;
351 u_int32_t tx_val;
352 u_int8_t dm_val;
353 int ret;
354
355 ifp = (struct interface *) vty->index;
356 assert (ifp);
357
358 oi = (struct ospf6_interface *) ifp->info;
359 if (oi == NULL)
360 oi = ospf6_interface_create (ifp);
361 assert (oi);
362
363 if ((ret = bfd_validate_param (vty, argv[0], argv[1], argv[2], &dm_val,
364 &rx_val, &tx_val)) != CMD_SUCCESS)
365 return ret;
366
367 ospf6_bfd_if_param_set (oi, rx_val, tx_val, dm_val, 0);
368
369 return CMD_SUCCESS;
370 }
371
372 DEFUN (no_ipv6_ospf6_bfd,
373 no_ipv6_ospf6_bfd_cmd,
374 "no ipv6 ospf6 bfd",
375 NO_STR
376 IP6_STR
377 OSPF6_STR
378 "Disables BFD support\n"
379 )
380 {
381 struct ospf6_interface *oi;
382 struct interface *ifp;
383
384 ifp = (struct interface *) vty->index;
385 assert (ifp);
386
387 oi = (struct ospf6_interface *) ifp->info;
388 if (oi == NULL)
389 oi = ospf6_interface_create (ifp);
390 assert (oi);
391
392 if (oi->bfd_info)
393 {
394 ospf6_bfd_reg_dereg_all_nbr(oi, ZEBRA_BFD_DEST_DEREGISTER);
395 bfd_info_free((struct bfd_info **)&(oi->bfd_info));
396 }
397
398 return CMD_SUCCESS;
399 }
400
401 void
402 ospf6_bfd_init(void)
403 {
404 /* Initialize BFD client functions */
405 zclient->interface_bfd_dest_update = ospf6_bfd_interface_dest_update;
406 zclient->bfd_dest_replay = ospf6_bfd_nbr_replay;
407
408 /* Install BFD command */
409 install_element (INTERFACE_NODE, &ipv6_ospf6_bfd_cmd);
410 install_element (INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd);
411 install_element (INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd);
412 }