]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_bfd.c
Merge pull request #8488 from mjstapp/more_workqueue
[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_profile(on->bfd_session, oi->bfd_config.profile);
147 }
148
149 /*
150 * ospf6_bfd_write_config - Write the interface BFD configuration.
151 */
152 void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
153 {
154 if (!oi->bfd_config.enabled)
155 return;
156
157 #if HAVE_BFDD == 0
158 if (oi->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT
159 || oi->bfd_config.min_rx != BFD_DEF_MIN_RX
160 || oi->bfd_config.min_tx != BFD_DEF_MIN_TX)
161 vty_out(vty, " ipv6 ospf6 bfd %d %d %d\n",
162 oi->bfd_config.detection_multiplier,
163 oi->bfd_config.min_rx, oi->bfd_config.min_tx);
164 else
165 #endif /* ! HAVE_BFDD */
166 vty_out(vty, " ipv6 ospf6 bfd\n");
167
168 if (oi->bfd_config.profile)
169 vty_out(vty, " ipv6 ospf6 bfd profile %s\n",
170 oi->bfd_config.profile);
171 }
172
173 DEFUN(ipv6_ospf6_bfd, ipv6_ospf6_bfd_cmd,
174 "ipv6 ospf6 bfd [profile BFDPROF]",
175 IP6_STR OSPF6_STR
176 "Enables BFD support\n"
177 "BFD Profile selection\n"
178 "BFD Profile name\n")
179 {
180 VTY_DECLVAR_CONTEXT(interface, ifp);
181 struct ospf6_interface *oi;
182 int prof_idx = 4;
183 assert(ifp);
184
185 oi = (struct ospf6_interface *)ifp->info;
186 if (oi == NULL)
187 oi = ospf6_interface_create(ifp);
188 assert(oi);
189
190 oi->bfd_config.detection_multiplier = BFD_DEF_DETECT_MULT;
191 oi->bfd_config.min_rx = BFD_DEF_MIN_RX;
192 oi->bfd_config.min_tx = BFD_DEF_MIN_TX;
193 oi->bfd_config.enabled = true;
194 if (argc > prof_idx) {
195 XFREE(MTYPE_TMP, oi->bfd_config.profile);
196 oi->bfd_config.profile =
197 XSTRDUP(MTYPE_TMP, argv[prof_idx]->arg);
198 }
199
200 ospf6_bfd_reg_dereg_all_nbr(oi, true);
201
202 return CMD_SUCCESS;
203 }
204
205 DEFUN(no_ipv6_ospf6_bfd_profile, no_ipv6_ospf6_bfd_profile_cmd,
206 "no ipv6 ospf6 bfd profile [BFDPROF]",
207 NO_STR IP6_STR OSPF6_STR
208 "BFD support\n"
209 "BFD Profile selection\n"
210 "BFD Profile name\n")
211 {
212 VTY_DECLVAR_CONTEXT(interface, ifp);
213 struct ospf6_interface *oi;
214 assert(ifp);
215
216 oi = (struct ospf6_interface *)ifp->info;
217 if (oi == NULL)
218 oi = ospf6_interface_create(ifp);
219 assert(oi);
220
221 /* BFD not enabled, nothing to do. */
222 if (!oi->bfd_config.enabled)
223 return CMD_SUCCESS;
224
225 /* Remove profile and apply new configuration. */
226 XFREE(MTYPE_TMP, oi->bfd_config.profile);
227 ospf6_bfd_reg_dereg_all_nbr(oi, true);
228
229 return CMD_SUCCESS;
230 }
231
232 #if HAVE_BFDD > 0
233 DEFUN_HIDDEN(
234 #else
235 DEFUN(
236 #endif /* HAVE_BFDD */
237 ipv6_ospf6_bfd_param,
238 ipv6_ospf6_bfd_param_cmd,
239 "ipv6 ospf6 bfd (2-255) (50-60000) (50-60000)",
240 IP6_STR
241 OSPF6_STR
242 "Enables BFD support\n"
243 "Detect Multiplier\n"
244 "Required min receive interval\n"
245 "Desired min transmit interval\n")
246 {
247 VTY_DECLVAR_CONTEXT(interface, ifp);
248 int idx_number = 3;
249 int idx_number_2 = 4;
250 int idx_number_3 = 5;
251 struct ospf6_interface *oi;
252
253 assert(ifp);
254
255 oi = (struct ospf6_interface *)ifp->info;
256 if (oi == NULL)
257 oi = ospf6_interface_create(ifp);
258 assert(oi);
259
260 oi->bfd_config.detection_multiplier =
261 strtoul(argv[idx_number]->arg, NULL, 10);
262 oi->bfd_config.min_rx = strtoul(argv[idx_number_2]->arg, NULL, 10);
263 oi->bfd_config.min_tx = strtoul(argv[idx_number_3]->arg, NULL, 10);
264 oi->bfd_config.enabled = true;
265
266 ospf6_bfd_reg_dereg_all_nbr(oi, true);
267
268 return CMD_SUCCESS;
269 }
270
271 DEFUN (no_ipv6_ospf6_bfd,
272 no_ipv6_ospf6_bfd_cmd,
273 "no ipv6 ospf6 bfd",
274 NO_STR
275 IP6_STR
276 OSPF6_STR
277 "Disables BFD support\n"
278 )
279 {
280 VTY_DECLVAR_CONTEXT(interface, ifp);
281 struct ospf6_interface *oi;
282 assert(ifp);
283
284 oi = (struct ospf6_interface *)ifp->info;
285 if (oi == NULL)
286 oi = ospf6_interface_create(ifp);
287 assert(oi);
288
289 oi->bfd_config.enabled = false;
290 ospf6_bfd_reg_dereg_all_nbr(oi, false);
291
292 return CMD_SUCCESS;
293 }
294
295 void ospf6_bfd_init(void)
296 {
297 bfd_protocol_integration_init(zclient, master);
298
299 /* Install BFD command */
300 install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_cmd);
301 install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd);
302 install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_profile_cmd);
303 install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd);
304 }