1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Static daemon BFD integration.
5 * Copyright (C) 2020-2022 Network Device Education Foundation, Inc. ("NetDEF")
12 #include "lib/printfrr.h"
13 #include "lib/srcdest_table.h"
15 #include "staticd/static_routes.h"
16 #include "staticd/static_zebra.h"
17 #include "staticd/static_debug.h"
19 #include "lib/openbsd-queue.h"
22 * Next hop BFD monitoring settings.
24 static void static_next_hop_bfd_change(struct static_nexthop
*sn
,
25 const struct bfd_session_status
*bss
)
29 /* FALLTHROUGH: no known state yet. */
31 /* NOTHING: we or the remote end administratively shutdown. */
34 /* Peer went down, remove this next hop. */
35 DEBUGD(&static_dbg_bfd
,
36 "%s: next hop is down, remove it from RIB", __func__
);
38 static_zebra_route_add(sn
->pn
, true);
41 /* Peer is back up, add this next hop. */
42 DEBUGD(&static_dbg_bfd
, "%s: next hop is up, add it to RIB",
44 sn
->path_down
= false;
45 static_zebra_route_add(sn
->pn
, true);
50 static void static_next_hop_bfd_updatecb(
51 __attribute__((unused
)) struct bfd_session_params
*bsp
,
52 const struct bfd_session_status
*bss
, void *arg
)
54 static_next_hop_bfd_change(arg
, bss
);
58 static_next_hop_type_to_family(const struct static_nexthop
*sn
)
61 case STATIC_IPV4_GATEWAY_IFNAME
:
62 case STATIC_IPV6_GATEWAY_IFNAME
:
63 case STATIC_IPV4_GATEWAY
:
64 case STATIC_IPV6_GATEWAY
:
65 if (sn
->type
== STATIC_IPV4_GATEWAY
||
66 sn
->type
== STATIC_IPV4_GATEWAY_IFNAME
)
72 case STATIC_BLACKHOLE
:
74 zlog_err("%s: invalid next hop type", __func__
);
81 void static_next_hop_bfd_monitor_enable(struct static_nexthop
*sn
,
82 const struct lyd_node
*dnode
)
92 use_interface
= false;
93 use_source
= yang_dnode_exists(dnode
, "./source");
94 use_profile
= yang_dnode_exists(dnode
, "./profile");
95 onlink
= yang_dnode_exists(dnode
, "../onlink") &&
96 yang_dnode_get_bool(dnode
, "../onlink");
97 mhop
= yang_dnode_get_bool(dnode
, "./multi-hop");
100 family
= static_next_hop_type_to_family(sn
);
101 if (family
== AF_UNSPEC
)
104 if (sn
->type
== STATIC_IPV4_GATEWAY_IFNAME
||
105 sn
->type
== STATIC_IPV6_GATEWAY_IFNAME
)
106 use_interface
= true;
108 /* Reconfigure or allocate new memory. */
110 sn
->bsp
= bfd_sess_new(static_next_hop_bfd_updatecb
, sn
);
112 /* Configure the session. */
114 yang_dnode_get_ip(&source
, dnode
, "./source");
116 if (onlink
|| mhop
== false)
117 bfd_sess_set_auto_source(sn
->bsp
, false);
119 bfd_sess_set_auto_source(sn
->bsp
, !use_source
);
121 /* Configure the session.*/
122 if (family
== AF_INET
)
123 bfd_sess_set_ipv4_addrs(sn
->bsp
,
124 use_source
? &source
.ip
._v4_addr
: NULL
,
126 else if (family
== AF_INET6
)
127 bfd_sess_set_ipv6_addrs(sn
->bsp
,
128 use_source
? &source
.ip
._v6_addr
: NULL
,
131 bfd_sess_set_interface(sn
->bsp
, use_interface
? sn
->ifname
: NULL
);
133 bfd_sess_set_profile(sn
->bsp
, use_profile
? yang_dnode_get_string(
137 bfd_sess_set_hop_count(sn
->bsp
, (onlink
|| mhop
== false) ? 1 : 254);
139 /* Install or update the session. */
140 bfd_sess_install(sn
->bsp
);
142 /* Update current path status. */
143 sn
->path_down
= (bfd_sess_status(sn
->bsp
) != BSS_UP
);
146 void static_next_hop_bfd_monitor_disable(struct static_nexthop
*sn
)
148 bfd_sess_free(&sn
->bsp
);
150 /* Reset path status. */
151 sn
->path_down
= false;
154 void static_next_hop_bfd_source(struct static_nexthop
*sn
,
155 const struct ipaddr
*source
)
162 family
= static_next_hop_type_to_family(sn
);
163 if (family
== AF_UNSPEC
)
166 bfd_sess_set_auto_source(sn
->bsp
, false);
167 if (family
== AF_INET
)
168 bfd_sess_set_ipv4_addrs(sn
->bsp
, &source
->ip
._v4_addr
,
170 else if (family
== AF_INET6
)
171 bfd_sess_set_ipv6_addrs(sn
->bsp
, &source
->ip
._v6_addr
,
174 bfd_sess_install(sn
->bsp
);
177 void static_next_hop_bfd_auto_source(struct static_nexthop
*sn
)
182 bfd_sess_set_auto_source(sn
->bsp
, true);
183 bfd_sess_install(sn
->bsp
);
186 void static_next_hop_bfd_multi_hop(struct static_nexthop
*sn
, bool mhop
)
191 bfd_sess_set_hop_count(sn
->bsp
, mhop
? 254 : 1);
192 bfd_sess_install(sn
->bsp
);
195 void static_next_hop_bfd_profile(struct static_nexthop
*sn
, const char *name
)
200 bfd_sess_set_profile(sn
->bsp
, name
);
201 bfd_sess_install(sn
->bsp
);
204 void static_bfd_initialize(struct zclient
*zc
, struct thread_master
*tm
)
206 /* Initialize BFD integration library. */
207 bfd_protocol_integration_init(zc
, tm
);
213 static void static_bfd_show_nexthop_json(struct vty
*vty
,
214 struct json_object
*jo
,
215 const struct static_nexthop
*sn
)
217 const struct prefix
*dst_p
, *src_p
;
218 struct json_object
*jo_nh
;
220 jo_nh
= json_object_new_object();
222 srcdest_rnode_prefixes(sn
->rn
, &dst_p
, &src_p
);
224 json_object_string_addf(jo_nh
, "from", "%pFX", src_p
);
226 json_object_string_addf(jo_nh
, "prefix", "%pFX", dst_p
);
227 json_object_string_add(jo_nh
, "vrf", sn
->nh_vrfname
);
229 json_object_boolean_add(jo_nh
, "installed", !sn
->path_down
);
231 json_object_array_add(jo
, jo_nh
);
234 static void static_bfd_show_path_json(struct vty
*vty
, struct json_object
*jo
,
235 struct route_table
*rt
)
237 struct route_node
*rn
;
239 for (rn
= route_top(rt
); rn
; rn
= srcdest_route_next(rn
)) {
240 struct static_route_info
*si
= static_route_info_from_rnode(rn
);
241 struct static_path
*sp
;
246 frr_each (static_path_list
, &si
->path_list
, sp
) {
247 struct static_nexthop
*sn
;
249 frr_each (static_nexthop_list
, &sp
->nexthop_list
, sn
) {
250 /* Skip non configured BFD sessions. */
254 static_bfd_show_nexthop_json(vty
, jo
, sn
);
260 static void static_bfd_show_json(struct vty
*vty
)
262 struct json_object
*jo
, *jo_path
, *jo_afi_safi
;
265 jo
= json_object_new_object();
266 jo_path
= json_object_new_object();
268 json_object_object_add(jo
, "path-list", jo_path
);
269 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
270 const struct static_vrf
*svrf
= vrf
->info
;
271 struct route_table
*rt
;
273 jo_afi_safi
= json_object_new_array();
274 json_object_object_add(jo_path
, "ipv4-unicast", jo_afi_safi
);
275 rt
= svrf
->stable
[AFI_IP
][SAFI_UNICAST
];
277 static_bfd_show_path_json(vty
, jo_afi_safi
, rt
);
279 jo_afi_safi
= json_object_new_array();
280 json_object_object_add(jo_path
, "ipv4-multicast", jo_afi_safi
);
281 rt
= svrf
->stable
[AFI_IP
][SAFI_MULTICAST
];
283 static_bfd_show_path_json(vty
, jo_afi_safi
, rt
);
285 jo_afi_safi
= json_object_new_array();
286 json_object_object_add(jo_path
, "ipv6-unicast", jo_afi_safi
);
287 rt
= svrf
->stable
[AFI_IP6
][SAFI_UNICAST
];
289 static_bfd_show_path_json(vty
, jo_afi_safi
, rt
);
292 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
293 json_object_free(jo
);
296 static void static_bfd_show_nexthop(struct vty
*vty
,
297 const struct static_nexthop
*sn
)
299 vty_out(vty
, " %pRN", sn
->rn
);
301 if (sn
->bsp
== NULL
) {
306 if (sn
->type
== STATIC_IPV4_GATEWAY
||
307 sn
->type
== STATIC_IPV4_GATEWAY_IFNAME
)
308 vty_out(vty
, " peer %pI4", &sn
->addr
.ipv4
);
309 else if (sn
->type
== STATIC_IPV6_GATEWAY
||
310 sn
->type
== STATIC_IPV6_GATEWAY_IFNAME
)
311 vty_out(vty
, " peer %pI6", &sn
->addr
.ipv6
);
313 vty_out(vty
, " peer unknown");
315 vty_out(vty
, " (status: %s)\n",
316 sn
->path_down
? "uninstalled" : "installed");
319 static void static_bfd_show_path(struct vty
*vty
, struct route_table
*rt
)
321 struct route_node
*rn
;
323 for (rn
= route_top(rt
); rn
; rn
= srcdest_route_next(rn
)) {
324 struct static_route_info
*si
= static_route_info_from_rnode(rn
);
325 struct static_path
*sp
;
330 frr_each (static_path_list
, &si
->path_list
, sp
) {
331 struct static_nexthop
*sn
;
333 frr_each (static_nexthop_list
, &sp
->nexthop_list
, sn
) {
334 /* Skip non configured BFD sessions. */
338 static_bfd_show_nexthop(vty
, sn
);
344 void static_bfd_show(struct vty
*vty
, bool json
)
349 static_bfd_show_json(vty
);
353 vty_out(vty
, "Showing BFD monitored static routes:\n");
354 vty_out(vty
, "\n Next hops:\n");
355 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
356 const struct static_vrf
*svrf
= vrf
->info
;
357 struct route_table
*rt
;
359 vty_out(vty
, " VRF %s IPv4 Unicast:\n", vrf
->name
);
360 rt
= svrf
->stable
[AFI_IP
][SAFI_UNICAST
];
362 static_bfd_show_path(vty
, rt
);
364 vty_out(vty
, "\n VRF %s IPv4 Multicast:\n", vrf
->name
);
365 rt
= svrf
->stable
[AFI_IP
][SAFI_MULTICAST
];
367 static_bfd_show_path(vty
, rt
);
369 vty_out(vty
, "\n VRF %s IPv6 Unicast:\n", vrf
->name
);
370 rt
= svrf
->stable
[AFI_IP6
][SAFI_UNICAST
];
372 static_bfd_show_path(vty
, rt
);