Line data Source code
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 39 : void ospf6_bfd_trigger_event(struct ospf6_neighbor *on, int old_state,
52 : int state)
53 : {
54 39 : int family;
55 39 : struct in6_addr src, dst;
56 :
57 : /* Skip sessions without BFD. */
58 39 : if (on->bfd_session == NULL)
59 39 : return;
60 :
61 0 : if (old_state < OSPF6_NEIGHBOR_TWOWAY
62 0 : && 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 0 : bfd_sess_addresses(on->bfd_session, &family, &src, &dst);
72 0 : if (memcmp(&on->linklocal_addr, &dst, sizeof(dst))) {
73 0 : bfd_sess_set_ipv6_addrs(on->bfd_session, &src,
74 : &on->linklocal_addr);
75 : }
76 :
77 0 : bfd_sess_install(on->bfd_session);
78 0 : } else if (old_state >= OSPF6_NEIGHBOR_TWOWAY
79 0 : && state < OSPF6_NEIGHBOR_TWOWAY)
80 0 : 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 0 : static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi,
90 : bool install)
91 : {
92 0 : struct ospf6_neighbor *on;
93 0 : struct listnode *node;
94 :
95 0 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
96 : /* Remove all sessions. */
97 0 : if (!install) {
98 0 : bfd_sess_free(&on->bfd_session);
99 0 : continue;
100 : }
101 :
102 : /* Always allocate session data even if not enabled. */
103 0 : 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 0 : if (on->state < OSPF6_NEIGHBOR_TWOWAY)
110 0 : continue;
111 :
112 0 : bfd_sess_install(on->bfd_session);
113 : }
114 0 : }
115 :
116 0 : static void ospf6_bfd_callback(struct bfd_session_params *bsp,
117 : const struct bfd_session_status *bss, void *arg)
118 : {
119 0 : struct ospf6_neighbor *on = arg;
120 :
121 0 : if (bss->state == BFD_STATUS_DOWN
122 0 : && bss->previous_state == BFD_STATUS_UP) {
123 0 : THREAD_OFF(on->inactivity_timer);
124 0 : thread_add_event(master, inactivity_timer, on, 0, NULL);
125 : }
126 0 : }
127 :
128 : /*
129 : * ospf6_bfd_info_nbr_create - Create/update BFD information for a neighbor.
130 : */
131 8 : void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi,
132 : struct ospf6_neighbor *on)
133 : {
134 8 : if (!oi->bfd_config.enabled)
135 : return;
136 :
137 0 : if (on->bfd_session == NULL)
138 0 : on->bfd_session = bfd_sess_new(ospf6_bfd_callback, on);
139 :
140 0 : bfd_sess_set_timers(on->bfd_session,
141 0 : oi->bfd_config.detection_multiplier,
142 : oi->bfd_config.min_rx, oi->bfd_config.min_tx);
143 0 : bfd_sess_set_ipv6_addrs(on->bfd_session, on->ospf6_if->linklocal_addr,
144 0 : &on->linklocal_addr);
145 0 : bfd_sess_set_interface(on->bfd_session, oi->interface->name);
146 0 : bfd_sess_set_vrf(on->bfd_session, oi->interface->vrf->vrf_id);
147 0 : 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 0 : void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
154 : {
155 0 : 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 0 : vty_out(vty, " ipv6 ospf6 bfd\n");
168 :
169 0 : if (oi->bfd_config.profile)
170 0 : vty_out(vty, " ipv6 ospf6 bfd profile %s\n",
171 : oi->bfd_config.profile);
172 : }
173 :
174 0 : 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 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
182 0 : struct ospf6_interface *oi;
183 0 : int prof_idx = 4;
184 0 : assert(ifp);
185 :
186 0 : oi = (struct ospf6_interface *)ifp->info;
187 0 : if (oi == NULL)
188 0 : oi = ospf6_interface_create(ifp);
189 0 : assert(oi);
190 :
191 0 : oi->bfd_config.detection_multiplier = BFD_DEF_DETECT_MULT;
192 0 : oi->bfd_config.min_rx = BFD_DEF_MIN_RX;
193 0 : oi->bfd_config.min_tx = BFD_DEF_MIN_TX;
194 0 : oi->bfd_config.enabled = true;
195 0 : if (argc > prof_idx) {
196 0 : XFREE(MTYPE_TMP, oi->bfd_config.profile);
197 0 : oi->bfd_config.profile =
198 0 : XSTRDUP(MTYPE_TMP, argv[prof_idx]->arg);
199 : }
200 :
201 0 : ospf6_bfd_reg_dereg_all_nbr(oi, true);
202 :
203 0 : return CMD_SUCCESS;
204 : }
205 :
206 0 : 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 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
214 0 : struct ospf6_interface *oi;
215 0 : assert(ifp);
216 :
217 0 : oi = (struct ospf6_interface *)ifp->info;
218 0 : if (oi == NULL)
219 0 : oi = ospf6_interface_create(ifp);
220 0 : assert(oi);
221 :
222 : /* BFD not enabled, nothing to do. */
223 0 : if (!oi->bfd_config.enabled)
224 : return CMD_SUCCESS;
225 :
226 : /* Remove profile and apply new configuration. */
227 0 : XFREE(MTYPE_TMP, oi->bfd_config.profile);
228 0 : ospf6_bfd_reg_dereg_all_nbr(oi, true);
229 :
230 0 : return CMD_SUCCESS;
231 : }
232 :
233 : #if HAVE_BFDD > 0
234 0 : 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 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
249 0 : int idx_number = 3;
250 0 : int idx_number_2 = 4;
251 0 : int idx_number_3 = 5;
252 0 : struct ospf6_interface *oi;
253 :
254 0 : assert(ifp);
255 :
256 0 : oi = (struct ospf6_interface *)ifp->info;
257 0 : if (oi == NULL)
258 0 : oi = ospf6_interface_create(ifp);
259 0 : assert(oi);
260 :
261 0 : oi->bfd_config.detection_multiplier =
262 0 : strtoul(argv[idx_number]->arg, NULL, 10);
263 0 : oi->bfd_config.min_rx = strtoul(argv[idx_number_2]->arg, NULL, 10);
264 0 : oi->bfd_config.min_tx = strtoul(argv[idx_number_3]->arg, NULL, 10);
265 0 : oi->bfd_config.enabled = true;
266 :
267 0 : ospf6_bfd_reg_dereg_all_nbr(oi, true);
268 :
269 0 : return CMD_SUCCESS;
270 : }
271 :
272 0 : 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 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
282 0 : struct ospf6_interface *oi;
283 0 : assert(ifp);
284 :
285 0 : oi = (struct ospf6_interface *)ifp->info;
286 0 : if (oi == NULL)
287 0 : oi = ospf6_interface_create(ifp);
288 0 : assert(oi);
289 :
290 0 : oi->bfd_config.enabled = false;
291 0 : ospf6_bfd_reg_dereg_all_nbr(oi, false);
292 :
293 0 : return CMD_SUCCESS;
294 : }
295 :
296 4 : void ospf6_bfd_init(void)
297 : {
298 4 : bfd_protocol_integration_init(zclient, master);
299 :
300 : /* Install BFD command */
301 4 : install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_cmd);
302 4 : install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd);
303 4 : install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_profile_cmd);
304 4 : install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd);
305 4 : }
|