Line data Source code
1 : /**
2 : * ospf_bfd.c: 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 "json.h"
27 : #include "linklist.h"
28 : #include "memory.h"
29 : #include "prefix.h"
30 : #include "thread.h"
31 : #include "buffer.h"
32 : #include "stream.h"
33 : #include "zclient.h"
34 : #include "vty.h"
35 : #include "table.h"
36 : #include "bfd.h"
37 : #include "ospfd.h"
38 : #include "ospf_asbr.h"
39 : #include "ospf_lsa.h"
40 : #include "ospf_lsdb.h"
41 : #include "ospf_neighbor.h"
42 : #include "ospf_interface.h"
43 : #include "ospf_nsm.h"
44 : #include "ospf_bfd.h"
45 : #include "ospf_dump.h"
46 : #include "ospf_vty.h"
47 :
48 12 : DEFINE_MTYPE_STATIC(OSPFD, BFD_CONFIG, "BFD configuration data");
49 :
50 : /*
51 : * ospf_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
52 : * neighbor state is changed to/from 2way.
53 : */
54 0 : void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state)
55 : {
56 0 : if ((old_state < NSM_TwoWay) && (state >= NSM_TwoWay))
57 0 : bfd_sess_install(nbr->bfd_session);
58 0 : else if ((old_state >= NSM_TwoWay) && (state < NSM_TwoWay))
59 0 : bfd_sess_uninstall(nbr->bfd_session);
60 0 : }
61 :
62 0 : static void ospf_bfd_session_change(struct bfd_session_params *bsp,
63 : const struct bfd_session_status *bss,
64 : void *arg)
65 : {
66 0 : struct ospf_neighbor *nbr = arg;
67 :
68 : /* BFD peer went down. */
69 0 : if (bss->state == BFD_STATUS_DOWN
70 0 : && bss->previous_state == BFD_STATUS_UP) {
71 0 : if (IS_DEBUG_OSPF(bfd, BFD_LIB))
72 0 : zlog_debug("%s: NSM[%s:%pI4]: BFD Down", __func__,
73 : IF_NAME(nbr->oi), &nbr->address.u.prefix4);
74 :
75 0 : OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
76 : }
77 :
78 : /* BFD peer went up. */
79 0 : if (bss->state == BSS_UP && bss->previous_state == BSS_DOWN)
80 0 : if (IS_DEBUG_OSPF(bfd, BFD_LIB))
81 0 : zlog_debug("%s: NSM[%s:%pI4]: BFD Up", __func__,
82 : IF_NAME(nbr->oi), &nbr->address.u.prefix4);
83 0 : }
84 :
85 8 : void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr)
86 : {
87 8 : struct ospf_interface *oi = nbr->oi;
88 8 : struct ospf_if_params *oip = IF_DEF_PARAMS(oi->ifp);
89 :
90 : /* BFD configuration was removed. */
91 8 : if (oip->bfd_config == NULL) {
92 8 : bfd_sess_free(&nbr->bfd_session);
93 8 : return;
94 : }
95 :
96 : /* New BFD session. */
97 0 : if (nbr->bfd_session == NULL) {
98 0 : nbr->bfd_session = bfd_sess_new(ospf_bfd_session_change, nbr);
99 0 : bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src);
100 0 : bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name);
101 0 : bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id);
102 : }
103 :
104 : /* Set new configuration. */
105 0 : bfd_sess_set_timers(nbr->bfd_session,
106 0 : oip->bfd_config->detection_multiplier,
107 0 : oip->bfd_config->min_rx, oip->bfd_config->min_tx);
108 0 : bfd_sess_set_profile(nbr->bfd_session, oip->bfd_config->profile);
109 :
110 : /* Don't start sessions on down OSPF sessions. */
111 0 : if (nbr->state < NSM_TwoWay)
112 : return;
113 :
114 0 : bfd_sess_install(nbr->bfd_session);
115 : }
116 :
117 0 : static void ospf_interface_bfd_apply(struct interface *ifp)
118 : {
119 0 : struct ospf_interface *oi;
120 0 : struct route_table *nbrs;
121 0 : struct ospf_neighbor *nbr;
122 0 : struct route_node *irn;
123 0 : struct route_node *nrn;
124 :
125 : /* Iterate over all interfaces and set neighbors BFD session. */
126 0 : for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) {
127 0 : if ((oi = irn->info) == NULL)
128 0 : continue;
129 0 : if ((nbrs = oi->nbrs) == NULL)
130 0 : continue;
131 0 : for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) {
132 0 : if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self)
133 0 : continue;
134 :
135 0 : ospf_neighbor_bfd_apply(nbr);
136 : }
137 : }
138 0 : }
139 :
140 0 : static void ospf_interface_enable_bfd(struct interface *ifp)
141 : {
142 0 : struct ospf_if_params *oip = IF_DEF_PARAMS(ifp);
143 :
144 0 : if (oip->bfd_config)
145 : return;
146 :
147 : /* Allocate memory for configurations and set defaults. */
148 0 : oip->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*oip->bfd_config));
149 0 : oip->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT;
150 0 : oip->bfd_config->min_rx = BFD_DEF_MIN_RX;
151 0 : oip->bfd_config->min_tx = BFD_DEF_MIN_TX;
152 : }
153 :
154 0 : void ospf_interface_disable_bfd(struct interface *ifp,
155 : struct ospf_if_params *oip)
156 : {
157 0 : XFREE(MTYPE_BFD_CONFIG, oip->bfd_config);
158 0 : ospf_interface_bfd_apply(ifp);
159 0 : }
160 :
161 : /*
162 : * ospf_bfd_write_config - Write the interface BFD configuration.
163 : */
164 0 : void ospf_bfd_write_config(struct vty *vty, const struct ospf_if_params *params
165 : __attribute__((unused)))
166 : {
167 : #if HAVE_BFDD == 0
168 : if (params->bfd_config->detection_multiplier != BFD_DEF_DETECT_MULT
169 : || params->bfd_config->min_rx != BFD_DEF_MIN_RX
170 : || params->bfd_config->min_tx != BFD_DEF_MIN_TX)
171 : vty_out(vty, " ip ospf bfd %d %d %d\n",
172 : params->bfd_config->detection_multiplier,
173 : params->bfd_config->min_rx, params->bfd_config->min_tx);
174 : else
175 : #endif /* ! HAVE_BFDD */
176 0 : vty_out(vty, " ip ospf bfd\n");
177 :
178 0 : if (params->bfd_config->profile[0])
179 0 : vty_out(vty, " ip ospf bfd profile %s\n",
180 0 : params->bfd_config->profile);
181 0 : }
182 :
183 0 : void ospf_interface_bfd_show(struct vty *vty, const struct interface *ifp,
184 : struct json_object *json)
185 : {
186 0 : struct ospf_if_params *params = IF_DEF_PARAMS(ifp);
187 0 : struct bfd_configuration *bfd_config = params->bfd_config;
188 0 : struct json_object *json_bfd;
189 :
190 0 : if (bfd_config == NULL)
191 : return;
192 :
193 0 : if (json) {
194 0 : json_bfd = json_object_new_object();
195 0 : json_object_int_add(json_bfd, "detectionMultiplier",
196 0 : bfd_config->detection_multiplier);
197 0 : json_object_int_add(json_bfd, "rxMinInterval",
198 0 : bfd_config->min_rx);
199 0 : json_object_int_add(json_bfd, "txMinInterval",
200 0 : bfd_config->min_tx);
201 0 : json_object_object_add(json, "peerBfdInfo", json_bfd);
202 : } else
203 0 : vty_out(vty,
204 : " BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
205 0 : bfd_config->detection_multiplier, bfd_config->min_rx,
206 : bfd_config->min_tx);
207 : }
208 :
209 0 : DEFUN (ip_ospf_bfd,
210 : ip_ospf_bfd_cmd,
211 : "ip ospf bfd",
212 : "IP Information\n"
213 : "OSPF interface commands\n"
214 : "Enables BFD support\n")
215 : {
216 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
217 0 : ospf_interface_enable_bfd(ifp);
218 0 : ospf_interface_bfd_apply(ifp);
219 0 : return CMD_SUCCESS;
220 : }
221 :
222 : #if HAVE_BFDD > 0
223 0 : DEFUN_HIDDEN(
224 : #else
225 : DEFUN(
226 : #endif /* HAVE_BFDD */
227 : ip_ospf_bfd_param,
228 : ip_ospf_bfd_param_cmd,
229 : "ip ospf bfd (2-255) (50-60000) (50-60000)",
230 : "IP Information\n"
231 : "OSPF interface commands\n"
232 : "Enables BFD support\n"
233 : "Detect Multiplier\n"
234 : "Required min receive interval\n"
235 : "Desired min transmit interval\n")
236 : {
237 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
238 0 : struct ospf_if_params *params;
239 0 : int idx_number = 3;
240 0 : int idx_number_2 = 4;
241 0 : int idx_number_3 = 5;
242 :
243 0 : ospf_interface_enable_bfd(ifp);
244 :
245 0 : params = IF_DEF_PARAMS(ifp);
246 0 : params->bfd_config->detection_multiplier =
247 0 : strtol(argv[idx_number]->arg, NULL, 10);
248 0 : params->bfd_config->min_rx = strtol(argv[idx_number_2]->arg, NULL, 10);
249 0 : params->bfd_config->min_tx = strtol(argv[idx_number_3]->arg, NULL, 10);
250 :
251 0 : ospf_interface_bfd_apply(ifp);
252 :
253 0 : return CMD_SUCCESS;
254 : }
255 :
256 0 : DEFUN (ip_ospf_bfd_prof,
257 : ip_ospf_bfd_prof_cmd,
258 : "ip ospf bfd profile BFDPROF",
259 : "IP Information\n"
260 : "OSPF interface commands\n"
261 : "Enables BFD support\n"
262 : BFD_PROFILE_STR
263 : BFD_PROFILE_NAME_STR)
264 : {
265 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
266 0 : struct ospf_if_params *params;
267 0 : int idx_prof = 4;
268 :
269 0 : params = IF_DEF_PARAMS(ifp);
270 0 : if (!params->bfd_config) {
271 0 : vty_out(vty, "ip ospf bfd has not been set\n");
272 0 : return CMD_WARNING;
273 : }
274 :
275 0 : strlcpy(params->bfd_config->profile, argv[idx_prof]->arg,
276 : sizeof(params->bfd_config->profile));
277 0 : ospf_interface_bfd_apply(ifp);
278 :
279 0 : return CMD_SUCCESS;
280 : }
281 :
282 0 : DEFUN (no_ip_ospf_bfd_prof,
283 : no_ip_ospf_bfd_prof_cmd,
284 : "no ip ospf bfd profile [BFDPROF]",
285 : NO_STR
286 : "IP Information\n"
287 : "OSPF interface commands\n"
288 : "Enables BFD support\n"
289 : BFD_PROFILE_STR
290 : BFD_PROFILE_NAME_STR)
291 : {
292 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
293 0 : struct ospf_if_params *params;
294 :
295 0 : params = IF_DEF_PARAMS(ifp);
296 0 : if (!params->bfd_config)
297 : return CMD_SUCCESS;
298 :
299 0 : params->bfd_config->profile[0] = 0;
300 0 : ospf_interface_bfd_apply(ifp);
301 :
302 0 : return CMD_SUCCESS;
303 : }
304 :
305 0 : DEFUN (no_ip_ospf_bfd,
306 : no_ip_ospf_bfd_cmd,
307 : #if HAVE_BFDD > 0
308 : "no ip ospf bfd",
309 : #else
310 : "no ip ospf bfd [(2-255) (50-60000) (50-60000)]",
311 : #endif /* HAVE_BFDD */
312 : NO_STR
313 : "IP Information\n"
314 : "OSPF interface commands\n"
315 : "Disables BFD support\n"
316 : #if HAVE_BFDD == 0
317 : "Detect Multiplier\n"
318 : "Required min receive interval\n"
319 : "Desired min transmit interval\n"
320 : #endif /* !HAVE_BFDD */
321 : )
322 : {
323 0 : VTY_DECLVAR_CONTEXT(interface, ifp);
324 0 : ospf_interface_disable_bfd(ifp, IF_DEF_PARAMS(ifp));
325 0 : return CMD_SUCCESS;
326 : }
327 :
328 4 : void ospf_bfd_init(struct thread_master *tm)
329 : {
330 4 : bfd_protocol_integration_init(zclient, tm);
331 :
332 : /* Install BFD command */
333 4 : install_element(INTERFACE_NODE, &ip_ospf_bfd_cmd);
334 4 : install_element(INTERFACE_NODE, &ip_ospf_bfd_param_cmd);
335 4 : install_element(INTERFACE_NODE, &ip_ospf_bfd_prof_cmd);
336 4 : install_element(INTERFACE_NODE, &no_ip_ospf_bfd_prof_cmd);
337 4 : install_element(INTERFACE_NODE, &no_ip_ospf_bfd_cmd);
338 4 : }
|