]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_bfd.c
ospfd: prevent from crashing when processing external lsa
[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_trigger_event - Neighbor is registered/deregistered with BFD when
49 * neighbor state is changed to/from 2way.
50 */
51 void ospf6_bfd_trigger_event(struct ospf6_neighbor *on, int old_state,
52 int state)
53 {
54 int family;
55 struct in6_addr src, dst;
56
57 /* Skip sessions without BFD. */
58 if (on->bfd_session == NULL)
59 return;
60
61 if (old_state < OSPF6_NEIGHBOR_TWOWAY
62 && state >= OSPF6_NEIGHBOR_TWOWAY) {
63 /*
64 * Check if neighbor address changed.
65 *
66 * When the neighbor is configured BFD before having an existing
67 * connection, then the destination address will be set to `::`
68 * which will cause session installation failure. This piece of
69 * code updates the address in that case.
70 */
71 bfd_sess_addresses(on->bfd_session, &family, &src, &dst);
72 if (memcmp(&on->linklocal_addr, &dst, sizeof(dst))) {
73 bfd_sess_set_ipv6_addrs(on->bfd_session, &src,
74 &on->linklocal_addr);
75 }
76
77 bfd_sess_install(on->bfd_session);
78 } else if (old_state >= OSPF6_NEIGHBOR_TWOWAY
79 && state < OSPF6_NEIGHBOR_TWOWAY)
80 bfd_sess_uninstall(on->bfd_session);
81 }
82
83 /*
84 * ospf6_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated
85 * with a interface with BFD through
86 * zebra for starting/stopping the monitoring of
87 * the neighbor rechahability.
88 */
89 static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi,
90 bool install)
91 {
92 struct ospf6_neighbor *on;
93 struct listnode *node;
94
95 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
96 /* Remove all sessions. */
97 if (!install) {
98 bfd_sess_free(&on->bfd_session);
99 continue;
100 }
101
102 /* Always allocate session data even if not enabled. */
103 ospf6_bfd_info_nbr_create(oi, on);
104
105 /*
106 * If not connected yet, don't create any session but defer it
107 * for later. See function `ospf6_bfd_trigger_event`.
108 */
109 if (on->state < OSPF6_NEIGHBOR_TWOWAY)
110 continue;
111
112 bfd_sess_install(on->bfd_session);
113 }
114 }
115
116 static void ospf6_bfd_callback(struct bfd_session_params *bsp,
117 const struct bfd_session_status *bss, void *arg)
118 {
119 struct ospf6_neighbor *on = arg;
120
121 if (bss->state == BFD_STATUS_DOWN
122 && bss->previous_state == BFD_STATUS_UP) {
123 THREAD_OFF(on->inactivity_timer);
124 thread_add_event(master, inactivity_timer, on, 0, NULL);
125 }
126 }
127
128 /*
129 * ospf6_bfd_info_nbr_create - Create/update BFD information for a neighbor.
130 */
131 void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi,
132 struct ospf6_neighbor *on)
133 {
134 if (!oi->bfd_config.enabled)
135 return;
136
137 if (on->bfd_session == NULL)
138 on->bfd_session = bfd_sess_new(ospf6_bfd_callback, on);
139
140 bfd_sess_set_timers(on->bfd_session,
141 oi->bfd_config.detection_multiplier,
142 oi->bfd_config.min_rx, oi->bfd_config.min_tx);
143 bfd_sess_set_ipv6_addrs(on->bfd_session, on->ospf6_if->linklocal_addr,
144 &on->linklocal_addr);
145 bfd_sess_set_interface(on->bfd_session, oi->interface->name);
146 bfd_sess_set_vrf(on->bfd_session, oi->interface->vrf->vrf_id);
147 bfd_sess_set_profile(on->bfd_session, oi->bfd_config.profile);
148 }
149
150 /*
151 * ospf6_bfd_write_config - Write the interface BFD configuration.
152 */
153 void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
154 {
155 if (!oi->bfd_config.enabled)
156 return;
157
158 #if HAVE_BFDD == 0
159 if (oi->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT
160 || oi->bfd_config.min_rx != BFD_DEF_MIN_RX
161 || oi->bfd_config.min_tx != BFD_DEF_MIN_TX)
162 vty_out(vty, " ipv6 ospf6 bfd %d %d %d\n",
163 oi->bfd_config.detection_multiplier,
164 oi->bfd_config.min_rx, oi->bfd_config.min_tx);
165 else
166 #endif /* ! HAVE_BFDD */
167 vty_out(vty, " ipv6 ospf6 bfd\n");
168
169 if (oi->bfd_config.profile)
170 vty_out(vty, " ipv6 ospf6 bfd profile %s\n",
171 oi->bfd_config.profile);
172 }
173
174 DEFUN(ipv6_ospf6_bfd, ipv6_ospf6_bfd_cmd,
175 "ipv6 ospf6 bfd [profile BFDPROF]",
176 IP6_STR OSPF6_STR
177 "Enables BFD support\n"
178 "BFD Profile selection\n"
179 "BFD Profile name\n")
180 {
181 VTY_DECLVAR_CONTEXT(interface, ifp);
182 struct ospf6_interface *oi;
183 int prof_idx = 4;
184 assert(ifp);
185
186 oi = (struct ospf6_interface *)ifp->info;
187 if (oi == NULL)
188 oi = ospf6_interface_create(ifp);
189 assert(oi);
190
191 oi->bfd_config.detection_multiplier = BFD_DEF_DETECT_MULT;
192 oi->bfd_config.min_rx = BFD_DEF_MIN_RX;
193 oi->bfd_config.min_tx = BFD_DEF_MIN_TX;
194 oi->bfd_config.enabled = true;
195 if (argc > prof_idx) {
196 XFREE(MTYPE_TMP, oi->bfd_config.profile);
197 oi->bfd_config.profile =
198 XSTRDUP(MTYPE_TMP, argv[prof_idx]->arg);
199 }
200
201 ospf6_bfd_reg_dereg_all_nbr(oi, true);
202
203 return CMD_SUCCESS;
204 }
205
206 DEFUN(no_ipv6_ospf6_bfd_profile, no_ipv6_ospf6_bfd_profile_cmd,
207 "no ipv6 ospf6 bfd profile [BFDPROF]",
208 NO_STR IP6_STR OSPF6_STR
209 "BFD support\n"
210 "BFD Profile selection\n"
211 "BFD Profile name\n")
212 {
213 VTY_DECLVAR_CONTEXT(interface, ifp);
214 struct ospf6_interface *oi;
215 assert(ifp);
216
217 oi = (struct ospf6_interface *)ifp->info;
218 if (oi == NULL)
219 oi = ospf6_interface_create(ifp);
220 assert(oi);
221
222 /* BFD not enabled, nothing to do. */
223 if (!oi->bfd_config.enabled)
224 return CMD_SUCCESS;
225
226 /* Remove profile and apply new configuration. */
227 XFREE(MTYPE_TMP, oi->bfd_config.profile);
228 ospf6_bfd_reg_dereg_all_nbr(oi, true);
229
230 return CMD_SUCCESS;
231 }
232
233 #if HAVE_BFDD > 0
234 DEFUN_HIDDEN(
235 #else
236 DEFUN(
237 #endif /* HAVE_BFDD */
238 ipv6_ospf6_bfd_param,
239 ipv6_ospf6_bfd_param_cmd,
240 "ipv6 ospf6 bfd (2-255) (50-60000) (50-60000)",
241 IP6_STR
242 OSPF6_STR
243 "Enables BFD support\n"
244 "Detect Multiplier\n"
245 "Required min receive interval\n"
246 "Desired min transmit interval\n")
247 {
248 VTY_DECLVAR_CONTEXT(interface, ifp);
249 int idx_number = 3;
250 int idx_number_2 = 4;
251 int idx_number_3 = 5;
252 struct ospf6_interface *oi;
253
254 assert(ifp);
255
256 oi = (struct ospf6_interface *)ifp->info;
257 if (oi == NULL)
258 oi = ospf6_interface_create(ifp);
259 assert(oi);
260
261 oi->bfd_config.detection_multiplier =
262 strtoul(argv[idx_number]->arg, NULL, 10);
263 oi->bfd_config.min_rx = strtoul(argv[idx_number_2]->arg, NULL, 10);
264 oi->bfd_config.min_tx = strtoul(argv[idx_number_3]->arg, NULL, 10);
265 oi->bfd_config.enabled = true;
266
267 ospf6_bfd_reg_dereg_all_nbr(oi, true);
268
269 return CMD_SUCCESS;
270 }
271
272 DEFUN (no_ipv6_ospf6_bfd,
273 no_ipv6_ospf6_bfd_cmd,
274 "no ipv6 ospf6 bfd",
275 NO_STR
276 IP6_STR
277 OSPF6_STR
278 "Disables BFD support\n"
279 )
280 {
281 VTY_DECLVAR_CONTEXT(interface, ifp);
282 struct ospf6_interface *oi;
283 assert(ifp);
284
285 oi = (struct ospf6_interface *)ifp->info;
286 if (oi == NULL)
287 oi = ospf6_interface_create(ifp);
288 assert(oi);
289
290 oi->bfd_config.enabled = false;
291 ospf6_bfd_reg_dereg_all_nbr(oi, false);
292
293 return CMD_SUCCESS;
294 }
295
296 void ospf6_bfd_init(void)
297 {
298 bfd_protocol_integration_init(zclient, master);
299
300 /* Install BFD command */
301 install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_cmd);
302 install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd);
303 install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_profile_cmd);
304 install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd);
305 }