]>
Commit | Line | Data |
---|---|---|
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_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 | } |