2 * Static daemon BFD integration.
4 * Copyright (C) 2020-2022 Network Device Education Foundation, Inc. ("NetDEF")
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.
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.
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
26 #include "lib/printfrr.h"
27 #include "lib/srcdest_table.h"
29 #include "staticd/static_routes.h"
30 #include "staticd/static_zebra.h"
31 #include "staticd/static_debug.h"
33 #include "lib/openbsd-queue.h"
36 * Next hop BFD monitoring settings.
38 static void static_next_hop_bfd_change(struct static_nexthop
*sn
,
39 const struct bfd_session_status
*bss
)
43 /* FALLTHROUGH: no known state yet. */
45 /* NOTHING: we or the remote end administratively shutdown. */
48 /* Peer went down, remove this next hop. */
49 DEBUGD(&static_dbg_bfd
,
50 "%s: next hop is down, remove it from RIB", __func__
);
52 static_zebra_route_add(sn
->pn
, true);
55 /* Peer is back up, add this next hop. */
56 DEBUGD(&static_dbg_bfd
, "%s: next hop is up, add it to RIB",
58 sn
->path_down
= false;
59 static_zebra_route_add(sn
->pn
, true);
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
)
68 static_next_hop_bfd_change(arg
, bss
);
72 static_next_hop_type_to_family(const struct static_nexthop
*sn
)
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
)
86 case STATIC_BLACKHOLE
:
88 zlog_err("%s: invalid next hop type", __func__
);
95 void static_next_hop_bfd_monitor_enable(struct static_nexthop
*sn
,
96 const struct lyd_node
*dnode
)
104 struct ipaddr source
;
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");
114 family
= static_next_hop_type_to_family(sn
);
115 if (family
== AF_UNSPEC
)
118 if (sn
->type
== STATIC_IPV4_GATEWAY_IFNAME
||
119 sn
->type
== STATIC_IPV6_GATEWAY_IFNAME
)
120 use_interface
= true;
122 /* Reconfigure or allocate new memory. */
124 sn
->bsp
= bfd_sess_new(static_next_hop_bfd_updatecb
, sn
);
126 /* Configure the session. */
128 yang_dnode_get_ip(&source
, dnode
, "./source");
130 if (onlink
|| mhop
== false)
131 bfd_sess_set_auto_source(sn
->bsp
, false);
133 bfd_sess_set_auto_source(sn
->bsp
, !use_source
);
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
,
140 else if (family
== AF_INET6
)
141 bfd_sess_set_ipv6_addrs(sn
->bsp
,
142 use_source
? &source
.ip
._v6_addr
: NULL
,
145 bfd_sess_set_interface(sn
->bsp
, use_interface
? sn
->ifname
: NULL
);
147 bfd_sess_set_profile(sn
->bsp
, use_profile
? yang_dnode_get_string(
151 bfd_sess_set_hop_count(sn
->bsp
, (onlink
|| mhop
== false) ? 1 : 254);
153 /* Install or update the session. */
154 bfd_sess_install(sn
->bsp
);
156 /* Update current path status. */
157 sn
->path_down
= (bfd_sess_status(sn
->bsp
) != BSS_UP
);
160 void static_next_hop_bfd_monitor_disable(struct static_nexthop
*sn
)
162 bfd_sess_free(&sn
->bsp
);
164 /* Reset path status. */
165 sn
->path_down
= false;
168 void static_next_hop_bfd_source(struct static_nexthop
*sn
,
169 const struct ipaddr
*source
)
176 family
= static_next_hop_type_to_family(sn
);
177 if (family
== AF_UNSPEC
)
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
,
184 else if (family
== AF_INET6
)
185 bfd_sess_set_ipv6_addrs(sn
->bsp
, &source
->ip
._v6_addr
,
188 bfd_sess_install(sn
->bsp
);
191 void static_next_hop_bfd_auto_source(struct static_nexthop
*sn
)
196 bfd_sess_set_auto_source(sn
->bsp
, true);
197 bfd_sess_install(sn
->bsp
);
200 void static_next_hop_bfd_multi_hop(struct static_nexthop
*sn
, bool mhop
)
205 bfd_sess_set_hop_count(sn
->bsp
, mhop
? 254 : 1);
206 bfd_sess_install(sn
->bsp
);
209 void static_next_hop_bfd_profile(struct static_nexthop
*sn
, const char *name
)
214 bfd_sess_set_profile(sn
->bsp
, name
);
215 bfd_sess_install(sn
->bsp
);
218 void static_bfd_initialize(struct zclient
*zc
, struct thread_master
*tm
)
220 /* Initialize BFD integration library. */
221 bfd_protocol_integration_init(zc
, tm
);
227 static void static_bfd_show_nexthop_json(struct vty
*vty
,
228 struct json_object
*jo
,
229 const struct static_nexthop
*sn
)
231 const struct prefix
*dst_p
, *src_p
;
232 struct json_object
*jo_nh
;
234 jo_nh
= json_object_new_object();
236 srcdest_rnode_prefixes(sn
->rn
, &dst_p
, &src_p
);
238 json_object_string_addf(jo_nh
, "from", "%pFX", src_p
);
240 json_object_string_addf(jo_nh
, "prefix", "%pFX", dst_p
);
241 json_object_string_add(jo_nh
, "vrf", sn
->nh_vrfname
);
243 json_object_boolean_add(jo_nh
, "installed", !sn
->path_down
);
245 json_object_array_add(jo
, jo_nh
);
248 static void static_bfd_show_path_json(struct vty
*vty
, struct json_object
*jo
,
249 struct route_table
*rt
)
251 struct route_node
*rn
;
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
;
260 frr_each (static_path_list
, &si
->path_list
, sp
) {
261 struct static_nexthop
*sn
;
263 frr_each (static_nexthop_list
, &sp
->nexthop_list
, sn
) {
264 /* Skip non configured BFD sessions. */
268 static_bfd_show_nexthop_json(vty
, jo
, sn
);
274 static void static_bfd_show_json(struct vty
*vty
)
276 struct json_object
*jo
, *jo_path
, *jo_afi_safi
;
279 jo
= json_object_new_object();
280 jo_path
= json_object_new_object();
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
;
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
];
291 static_bfd_show_path_json(vty
, jo_afi_safi
, rt
);
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
];
297 static_bfd_show_path_json(vty
, jo_afi_safi
, rt
);
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
];
303 static_bfd_show_path_json(vty
, jo_afi_safi
, rt
);
306 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
307 json_object_free(jo
);
310 static void static_bfd_show_nexthop(struct vty
*vty
,
311 const struct static_nexthop
*sn
)
313 vty_out(vty
, " %pRN", sn
->rn
);
315 if (sn
->bsp
== NULL
) {
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
);
327 vty_out(vty
, " peer unknown");
329 vty_out(vty
, " (status: %s)\n",
330 sn
->path_down
? "uninstalled" : "installed");
333 static void static_bfd_show_path(struct vty
*vty
, struct route_table
*rt
)
335 struct route_node
*rn
;
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
;
344 frr_each (static_path_list
, &si
->path_list
, sp
) {
345 struct static_nexthop
*sn
;
347 frr_each (static_nexthop_list
, &sp
->nexthop_list
, sn
) {
348 /* Skip non configured BFD sessions. */
352 static_bfd_show_nexthop(vty
, sn
);
358 void static_bfd_show(struct vty
*vty
, bool json
)
363 static_bfd_show_json(vty
);
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
;
373 vty_out(vty
, " VRF %s IPv4 Unicast:\n", vrf
->name
);
374 rt
= svrf
->stable
[AFI_IP
][SAFI_UNICAST
];
376 static_bfd_show_path(vty
, rt
);
378 vty_out(vty
, "\n VRF %s IPv4 Multicast:\n", vrf
->name
);
379 rt
= svrf
->stable
[AFI_IP
][SAFI_MULTICAST
];
381 static_bfd_show_path(vty
, rt
);
383 vty_out(vty
, "\n VRF %s IPv6 Unicast:\n", vrf
->name
);
384 rt
= svrf
->stable
[AFI_IP6
][SAFI_UNICAST
];
386 static_bfd_show_path(vty
, rt
);