]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_bfd.c
Merge pull request #12671 from vfreex/babel-fix-terminal
[mirror_frr.git] / staticd / static_bfd.c
1 /*
2 * Static daemon BFD integration.
3 *
4 * Copyright (C) 2020-2022 Network Device Education Foundation, Inc. ("NetDEF")
5 * Rafael Zalamena
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23 #include <zebra.h>
24
25 #include "lib/bfd.h"
26 #include "lib/printfrr.h"
27 #include "lib/srcdest_table.h"
28
29 #include "staticd/static_routes.h"
30 #include "staticd/static_zebra.h"
31 #include "staticd/static_debug.h"
32
33 #include "lib/openbsd-queue.h"
34
35 /*
36 * Next hop BFD monitoring settings.
37 */
38 static void static_next_hop_bfd_change(struct static_nexthop *sn,
39 const struct bfd_session_status *bss)
40 {
41 switch (bss->state) {
42 case BSS_UNKNOWN:
43 /* FALLTHROUGH: no known state yet. */
44 case BSS_ADMIN_DOWN:
45 /* NOTHING: we or the remote end administratively shutdown. */
46 break;
47 case BSS_DOWN:
48 /* Peer went down, remove this next hop. */
49 DEBUGD(&static_dbg_bfd,
50 "%s: next hop is down, remove it from RIB", __func__);
51 sn->path_down = true;
52 static_zebra_route_add(sn->pn, true);
53 break;
54 case BSS_UP:
55 /* Peer is back up, add this next hop. */
56 DEBUGD(&static_dbg_bfd, "%s: next hop is up, add it to RIB",
57 __func__);
58 sn->path_down = false;
59 static_zebra_route_add(sn->pn, true);
60 break;
61 }
62 }
63
64 static void static_next_hop_bfd_updatecb(
65 __attribute__((unused)) struct bfd_session_params *bsp,
66 const struct bfd_session_status *bss, void *arg)
67 {
68 static_next_hop_bfd_change(arg, bss);
69 }
70
71 static inline int
72 static_next_hop_type_to_family(const struct static_nexthop *sn)
73 {
74 switch (sn->type) {
75 case STATIC_IPV4_GATEWAY_IFNAME:
76 case STATIC_IPV6_GATEWAY_IFNAME:
77 case STATIC_IPV4_GATEWAY:
78 case STATIC_IPV6_GATEWAY:
79 if (sn->type == STATIC_IPV4_GATEWAY ||
80 sn->type == STATIC_IPV4_GATEWAY_IFNAME)
81 return AF_INET;
82 else
83 return AF_INET6;
84 break;
85 case STATIC_IFNAME:
86 case STATIC_BLACKHOLE:
87 default:
88 zlog_err("%s: invalid next hop type", __func__);
89 break;
90 }
91
92 return AF_UNSPEC;
93 }
94
95 void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn,
96 const struct lyd_node *dnode)
97 {
98 bool use_interface;
99 bool use_profile;
100 bool use_source;
101 bool onlink;
102 bool mhop;
103 int family;
104 struct ipaddr source;
105
106 use_interface = false;
107 use_source = yang_dnode_exists(dnode, "./source");
108 use_profile = yang_dnode_exists(dnode, "./profile");
109 onlink = yang_dnode_exists(dnode, "../onlink") &&
110 yang_dnode_get_bool(dnode, "../onlink");
111 mhop = yang_dnode_get_bool(dnode, "./multi-hop");
112
113
114 family = static_next_hop_type_to_family(sn);
115 if (family == AF_UNSPEC)
116 return;
117
118 if (sn->type == STATIC_IPV4_GATEWAY_IFNAME ||
119 sn->type == STATIC_IPV6_GATEWAY_IFNAME)
120 use_interface = true;
121
122 /* Reconfigure or allocate new memory. */
123 if (sn->bsp == NULL)
124 sn->bsp = bfd_sess_new(static_next_hop_bfd_updatecb, sn);
125
126 /* Configure the session. */
127 if (use_source)
128 yang_dnode_get_ip(&source, dnode, "./source");
129
130 if (onlink || mhop == false)
131 bfd_sess_set_auto_source(sn->bsp, false);
132 else
133 bfd_sess_set_auto_source(sn->bsp, !use_source);
134
135 /* Configure the session.*/
136 if (family == AF_INET)
137 bfd_sess_set_ipv4_addrs(sn->bsp,
138 use_source ? &source.ip._v4_addr : NULL,
139 &sn->addr.ipv4);
140 else if (family == AF_INET6)
141 bfd_sess_set_ipv6_addrs(sn->bsp,
142 use_source ? &source.ip._v6_addr : NULL,
143 &sn->addr.ipv6);
144
145 bfd_sess_set_interface(sn->bsp, use_interface ? sn->ifname : NULL);
146
147 bfd_sess_set_profile(sn->bsp, use_profile ? yang_dnode_get_string(
148 dnode, "./profile")
149 : NULL);
150
151 bfd_sess_set_hop_count(sn->bsp, (onlink || mhop == false) ? 1 : 254);
152
153 /* Install or update the session. */
154 bfd_sess_install(sn->bsp);
155
156 /* Update current path status. */
157 sn->path_down = (bfd_sess_status(sn->bsp) != BSS_UP);
158 }
159
160 void static_next_hop_bfd_monitor_disable(struct static_nexthop *sn)
161 {
162 bfd_sess_free(&sn->bsp);
163
164 /* Reset path status. */
165 sn->path_down = false;
166 }
167
168 void static_next_hop_bfd_source(struct static_nexthop *sn,
169 const struct ipaddr *source)
170 {
171 int family;
172
173 if (sn->bsp == NULL)
174 return;
175
176 family = static_next_hop_type_to_family(sn);
177 if (family == AF_UNSPEC)
178 return;
179
180 bfd_sess_set_auto_source(sn->bsp, false);
181 if (family == AF_INET)
182 bfd_sess_set_ipv4_addrs(sn->bsp, &source->ip._v4_addr,
183 &sn->addr.ipv4);
184 else if (family == AF_INET6)
185 bfd_sess_set_ipv6_addrs(sn->bsp, &source->ip._v6_addr,
186 &sn->addr.ipv6);
187
188 bfd_sess_install(sn->bsp);
189 }
190
191 void static_next_hop_bfd_auto_source(struct static_nexthop *sn)
192 {
193 if (sn->bsp == NULL)
194 return;
195
196 bfd_sess_set_auto_source(sn->bsp, true);
197 bfd_sess_install(sn->bsp);
198 }
199
200 void static_next_hop_bfd_multi_hop(struct static_nexthop *sn, bool mhop)
201 {
202 if (sn->bsp == NULL)
203 return;
204
205 bfd_sess_set_hop_count(sn->bsp, mhop ? 254 : 1);
206 bfd_sess_install(sn->bsp);
207 }
208
209 void static_next_hop_bfd_profile(struct static_nexthop *sn, const char *name)
210 {
211 if (sn->bsp == NULL)
212 return;
213
214 bfd_sess_set_profile(sn->bsp, name);
215 bfd_sess_install(sn->bsp);
216 }
217
218 void static_bfd_initialize(struct zclient *zc, struct thread_master *tm)
219 {
220 /* Initialize BFD integration library. */
221 bfd_protocol_integration_init(zc, tm);
222 }
223
224 /*
225 * Display functions
226 */
227 static void static_bfd_show_nexthop_json(struct vty *vty,
228 struct json_object *jo,
229 const struct static_nexthop *sn)
230 {
231 const struct prefix *dst_p, *src_p;
232 struct json_object *jo_nh;
233
234 jo_nh = json_object_new_object();
235
236 srcdest_rnode_prefixes(sn->rn, &dst_p, &src_p);
237 if (src_p)
238 json_object_string_addf(jo_nh, "from", "%pFX", src_p);
239
240 json_object_string_addf(jo_nh, "prefix", "%pFX", dst_p);
241 json_object_string_add(jo_nh, "vrf", sn->nh_vrfname);
242
243 json_object_boolean_add(jo_nh, "installed", !sn->path_down);
244
245 json_object_array_add(jo, jo_nh);
246 }
247
248 static void static_bfd_show_path_json(struct vty *vty, struct json_object *jo,
249 struct route_table *rt)
250 {
251 struct route_node *rn;
252
253 for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
254 struct static_route_info *si = static_route_info_from_rnode(rn);
255 struct static_path *sp;
256
257 if (si == NULL)
258 continue;
259
260 frr_each (static_path_list, &si->path_list, sp) {
261 struct static_nexthop *sn;
262
263 frr_each (static_nexthop_list, &sp->nexthop_list, sn) {
264 /* Skip non configured BFD sessions. */
265 if (sn->bsp == NULL)
266 continue;
267
268 static_bfd_show_nexthop_json(vty, jo, sn);
269 }
270 }
271 }
272 }
273
274 static void static_bfd_show_json(struct vty *vty)
275 {
276 struct json_object *jo, *jo_path, *jo_afi_safi;
277 struct vrf *vrf;
278
279 jo = json_object_new_object();
280 jo_path = json_object_new_object();
281
282 json_object_object_add(jo, "path-list", jo_path);
283 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
284 const struct static_vrf *svrf = vrf->info;
285 struct route_table *rt;
286
287 jo_afi_safi = json_object_new_array();
288 json_object_object_add(jo_path, "ipv4-unicast", jo_afi_safi);
289 rt = svrf->stable[AFI_IP][SAFI_UNICAST];
290 if (rt)
291 static_bfd_show_path_json(vty, jo_afi_safi, rt);
292
293 jo_afi_safi = json_object_new_array();
294 json_object_object_add(jo_path, "ipv4-multicast", jo_afi_safi);
295 rt = svrf->stable[AFI_IP][SAFI_MULTICAST];
296 if (rt)
297 static_bfd_show_path_json(vty, jo_afi_safi, rt);
298
299 jo_afi_safi = json_object_new_array();
300 json_object_object_add(jo_path, "ipv6-unicast", jo_afi_safi);
301 rt = svrf->stable[AFI_IP6][SAFI_UNICAST];
302 if (rt)
303 static_bfd_show_path_json(vty, jo_afi_safi, rt);
304 }
305
306 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
307 json_object_free(jo);
308 }
309
310 static void static_bfd_show_nexthop(struct vty *vty,
311 const struct static_nexthop *sn)
312 {
313 vty_out(vty, " %pRN", sn->rn);
314
315 if (sn->bsp == NULL) {
316 vty_out(vty, "\n");
317 return;
318 }
319
320 if (sn->type == STATIC_IPV4_GATEWAY ||
321 sn->type == STATIC_IPV4_GATEWAY_IFNAME)
322 vty_out(vty, " peer %pI4", &sn->addr.ipv4);
323 else if (sn->type == STATIC_IPV6_GATEWAY ||
324 sn->type == STATIC_IPV6_GATEWAY_IFNAME)
325 vty_out(vty, " peer %pI6", &sn->addr.ipv6);
326 else
327 vty_out(vty, " peer unknown");
328
329 vty_out(vty, " (status: %s)\n",
330 sn->path_down ? "uninstalled" : "installed");
331 }
332
333 static void static_bfd_show_path(struct vty *vty, struct route_table *rt)
334 {
335 struct route_node *rn;
336
337 for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
338 struct static_route_info *si = static_route_info_from_rnode(rn);
339 struct static_path *sp;
340
341 if (si == NULL)
342 continue;
343
344 frr_each (static_path_list, &si->path_list, sp) {
345 struct static_nexthop *sn;
346
347 frr_each (static_nexthop_list, &sp->nexthop_list, sn) {
348 /* Skip non configured BFD sessions. */
349 if (sn->bsp == NULL)
350 continue;
351
352 static_bfd_show_nexthop(vty, sn);
353 }
354 }
355 }
356 }
357
358 void static_bfd_show(struct vty *vty, bool json)
359 {
360 struct vrf *vrf;
361
362 if (json) {
363 static_bfd_show_json(vty);
364 return;
365 }
366
367 vty_out(vty, "Showing BFD monitored static routes:\n");
368 vty_out(vty, "\n Next hops:\n");
369 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
370 const struct static_vrf *svrf = vrf->info;
371 struct route_table *rt;
372
373 vty_out(vty, " VRF %s IPv4 Unicast:\n", vrf->name);
374 rt = svrf->stable[AFI_IP][SAFI_UNICAST];
375 if (rt)
376 static_bfd_show_path(vty, rt);
377
378 vty_out(vty, "\n VRF %s IPv4 Multicast:\n", vrf->name);
379 rt = svrf->stable[AFI_IP][SAFI_MULTICAST];
380 if (rt)
381 static_bfd_show_path(vty, rt);
382
383 vty_out(vty, "\n VRF %s IPv6 Unicast:\n", vrf->name);
384 rt = svrf->stable[AFI_IP6][SAFI_UNICAST];
385 if (rt)
386 static_bfd_show_path(vty, rt);
387 }
388
389 vty_out(vty, "\n");
390 }