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