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