]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_bfd.c
Merge pull request #964 from opensourcerouting/plist-trie-corruption-3.0
[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
78 if (!oi->bfd_info || !on->bfd_info)
79 return;
80 bfd_info = (struct bfd_info *)oi->bfd_info;
81
82 if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
83 inet_ntop(AF_INET6, &on->linklocal_addr, src, sizeof(src));
84 zlog_debug("%s nbr (%s) with BFD",
85 bfd_get_command_dbg_str(command), src);
86 }
87
88 bfd_peer_sendmsg(zclient, bfd_info, AF_INET6, &on->linklocal_addr,
89 on->ospf6_if->linklocal_addr, ifp->name, 0, 0, command,
90 0, VRF_DEFAULT);
91
92 if (command == ZEBRA_BFD_DEST_DEREGISTER)
93 bfd_info_free((struct bfd_info **)&on->bfd_info);
94 }
95
96 /*
97 * ospf6_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
98 * neighbor state is changed to/from 2way.
99 */
100 void ospf6_bfd_trigger_event(struct ospf6_neighbor *on, int old_state,
101 int state)
102 {
103 if ((old_state < OSPF6_NEIGHBOR_TWOWAY)
104 && (state >= OSPF6_NEIGHBOR_TWOWAY))
105 ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_REGISTER);
106 else if ((old_state >= OSPF6_NEIGHBOR_TWOWAY)
107 && (state < OSPF6_NEIGHBOR_TWOWAY))
108 ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_DEREGISTER);
109 }
110
111 /*
112 * ospf6_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated
113 * with a interface with BFD through
114 * zebra for starting/stopping the monitoring of
115 * the neighbor rechahability.
116 */
117 static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi, int command)
118 {
119 struct ospf6_neighbor *on;
120 struct listnode *node;
121
122 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
123 if (command == ZEBRA_BFD_DEST_REGISTER)
124 ospf6_bfd_info_nbr_create(oi, on);
125
126 if (on->state < OSPF6_NEIGHBOR_TWOWAY) {
127 if (command == ZEBRA_BFD_DEST_DEREGISTER)
128 bfd_info_free(
129 (struct bfd_info **)&on->bfd_info);
130 continue;
131 }
132
133 ospf6_bfd_reg_dereg_nbr(on, command);
134 }
135 }
136
137 /*
138 * ospf6_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
139 * to zebra
140 */
141 static int ospf6_bfd_nbr_replay(int command, struct zclient *zclient,
142 zebra_size_t length, vrf_id_t vrf_id)
143 {
144 struct listnode *inode, *nnode;
145 struct interface *ifp;
146 struct ospf6_interface *oi;
147 struct ospf6_neighbor *on;
148 char dst[64];
149
150 if (IS_OSPF6_DEBUG_ZEBRA(RECV))
151 zlog_debug("Zebra: BFD Dest replay request");
152
153 /* Send the client registration */
154 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
155
156 /* Replay the neighbor, if BFD is enabled on the interface*/
157 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), inode, ifp)) {
158 oi = (struct ospf6_interface *)ifp->info;
159
160 if (!oi || !oi->bfd_info)
161 continue;
162
163 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, nnode, on)) {
164 if (on->state < OSPF6_NEIGHBOR_TWOWAY)
165 continue;
166
167 if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
168 inet_ntop(AF_INET6, &on->linklocal_addr, dst,
169 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 ospf6_bfd_interface_dest_update(int command, struct zclient *zclient,
185 zebra_size_t length, vrf_id_t vrf_id)
186 {
187 struct interface *ifp;
188 struct ospf6_interface *oi;
189 struct ospf6_neighbor *on;
190 struct prefix dp;
191 struct prefix sp;
192 struct listnode *node, *nnode;
193 char dst[64];
194 int status;
195 int old_status;
196 struct bfd_info *bfd_info;
197 struct timeval tv;
198
199 ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, vrf_id);
200
201 if ((ifp == NULL) || (dp.family != AF_INET6))
202 return 0;
203
204 if (IS_OSPF6_DEBUG_ZEBRA(RECV)) {
205 char buf[PREFIX2STR_BUFFER];
206 prefix2str(&dp, buf, sizeof(buf));
207 zlog_debug("Zebra: interface %s bfd destination %s %s",
208 ifp->name, buf, bfd_get_status_str(status));
209 }
210
211
212 oi = (struct ospf6_interface *)ifp->info;
213 if (!oi || !oi->bfd_info)
214 return 0;
215
216 for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
217 if (memcmp(&(on->linklocal_addr), &dp.u.prefix6,
218 sizeof(struct in6_addr)))
219 continue;
220
221 if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) {
222 inet_ntop(AF_INET6, &on->linklocal_addr, dst,
223 sizeof(dst));
224 zlog_debug("[%s:%s]: BFD %s", ifp->name, dst,
225 bfd_get_status_str(status));
226 }
227
228 if (!on->bfd_info)
229 continue;
230
231 bfd_info = (struct bfd_info *)on->bfd_info;
232 if (bfd_info->status == status)
233 continue;
234
235 old_status = bfd_info->status;
236 bfd_info->status = status;
237 monotime(&tv);
238 bfd_info->last_update = tv.tv_sec;
239
240 if ((status == BFD_STATUS_DOWN)
241 && (old_status == BFD_STATUS_UP)) {
242 THREAD_OFF(on->inactivity_timer);
243 thread_add_event(master, inactivity_timer, on, 0, NULL);
244 }
245 }
246
247 return 0;
248 }
249
250 /*
251 * ospf6_bfd_info_nbr_create - Create/update BFD information for a neighbor.
252 */
253 void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi,
254 struct ospf6_neighbor *on)
255 {
256 struct bfd_info *oi_bfd_info;
257 struct bfd_info *on_bfd_info;
258
259 if (!oi->bfd_info)
260 return;
261
262 oi_bfd_info = (struct bfd_info *)oi->bfd_info;
263
264 if (!on->bfd_info)
265 on->bfd_info = bfd_info_create();
266
267 on_bfd_info = (struct bfd_info *)on->bfd_info;
268 on_bfd_info->detect_mult = oi_bfd_info->detect_mult;
269 on_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx;
270 on_bfd_info->required_min_rx = oi_bfd_info->required_min_rx;
271 }
272
273 /*
274 * ospf6_bfd_write_config - Write the interface BFD configuration.
275 */
276 void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
277 {
278 struct bfd_info *bfd_info;
279
280 if (!oi->bfd_info)
281 return;
282
283 bfd_info = (struct bfd_info *)oi->bfd_info;
284
285 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
286 vty_out(vty, " ipv6 ospf6 bfd %d %d %d\n",
287 bfd_info->detect_mult, bfd_info->required_min_rx,
288 bfd_info->desired_min_tx);
289 else
290 vty_out(vty, " ipv6 ospf6 bfd\n");
291 }
292
293 /*
294 * ospf6_bfd_if_param_set - Set the configured BFD paramter values for
295 * interface.
296 */
297 static void ospf6_bfd_if_param_set(struct ospf6_interface *oi, u_int32_t min_rx,
298 u_int32_t min_tx, u_int8_t detect_mult,
299 int defaults)
300 {
301 int command = 0;
302
303 bfd_set_param((struct bfd_info **)&(oi->bfd_info), min_rx, min_tx,
304 detect_mult, defaults, &command);
305 if (command)
306 ospf6_bfd_reg_dereg_all_nbr(oi, command);
307 }
308
309 DEFUN (ipv6_ospf6_bfd,
310 ipv6_ospf6_bfd_cmd,
311 "ipv6 ospf6 bfd",
312 IP6_STR
313 OSPF6_STR
314 "Enables BFD support\n"
315 )
316 {
317 VTY_DECLVAR_CONTEXT(interface, ifp);
318 struct ospf6_interface *oi;
319 assert(ifp);
320
321 oi = (struct ospf6_interface *)ifp->info;
322 if (oi == NULL)
323 oi = ospf6_interface_create(ifp);
324 assert(oi);
325
326 ospf6_bfd_if_param_set(oi, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
327 BFD_DEF_DETECT_MULT, 1);
328 return CMD_SUCCESS;
329 }
330
331 DEFUN (ipv6_ospf6_bfd_param,
332 ipv6_ospf6_bfd_param_cmd,
333 "ipv6 ospf6 bfd (2-255) (50-60000) (50-60000)",
334 IP6_STR
335 OSPF6_STR
336 "Enables BFD support\n"
337 "Detect Multiplier\n"
338 "Required min receive interval\n"
339 "Desired min transmit interval\n")
340 {
341 VTY_DECLVAR_CONTEXT(interface, ifp);
342 int idx_number = 3;
343 int idx_number_2 = 4;
344 int idx_number_3 = 5;
345 struct ospf6_interface *oi;
346 u_int32_t rx_val;
347 u_int32_t tx_val;
348 u_int8_t dm_val;
349 int ret;
350
351 assert(ifp);
352
353 oi = (struct ospf6_interface *)ifp->info;
354 if (oi == NULL)
355 oi = ospf6_interface_create(ifp);
356 assert(oi);
357
358 if ((ret = bfd_validate_param(
359 vty, argv[idx_number]->arg, argv[idx_number_2]->arg,
360 argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
361 != CMD_SUCCESS)
362 return ret;
363
364 ospf6_bfd_if_param_set(oi, rx_val, tx_val, dm_val, 0);
365
366 return CMD_SUCCESS;
367 }
368
369 DEFUN (no_ipv6_ospf6_bfd,
370 no_ipv6_ospf6_bfd_cmd,
371 "no ipv6 ospf6 bfd",
372 NO_STR
373 IP6_STR
374 OSPF6_STR
375 "Disables BFD support\n"
376 )
377 {
378 VTY_DECLVAR_CONTEXT(interface, ifp);
379 struct ospf6_interface *oi;
380 assert(ifp);
381
382 oi = (struct ospf6_interface *)ifp->info;
383 if (oi == NULL)
384 oi = ospf6_interface_create(ifp);
385 assert(oi);
386
387 if (oi->bfd_info) {
388 ospf6_bfd_reg_dereg_all_nbr(oi, ZEBRA_BFD_DEST_DEREGISTER);
389 bfd_info_free((struct bfd_info **)&(oi->bfd_info));
390 }
391
392 return CMD_SUCCESS;
393 }
394
395 void ospf6_bfd_init(void)
396 {
397 bfd_gbl_init();
398
399 /* Initialize BFD client functions */
400 zclient->interface_bfd_dest_update = ospf6_bfd_interface_dest_update;
401 zclient->bfd_dest_replay = ospf6_bfd_nbr_replay;
402
403 /* Install BFD command */
404 install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_cmd);
405 install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd);
406 install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd);
407 }