]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_bfd.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / staticd / static_bfd.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Static daemon BFD integration.
4 *
5 * Copyright (C) 2020-2022 Network Device Education Foundation, Inc. ("NetDEF")
6 * Rafael Zalamena
7 */
8
9 #include <zebra.h>
10
11 #include "lib/bfd.h"
12 #include "lib/printfrr.h"
13 #include "lib/srcdest_table.h"
14
15 #include "staticd/static_routes.h"
16 #include "staticd/static_zebra.h"
17 #include "staticd/static_debug.h"
18
19 #include "lib/openbsd-queue.h"
20
21 /*
22 * Next hop BFD monitoring settings.
23 */
24 static void static_next_hop_bfd_change(struct static_nexthop *sn,
25 const struct bfd_session_status *bss)
26 {
27 switch (bss->state) {
28 case BSS_UNKNOWN:
29 /* FALLTHROUGH: no known state yet. */
30 case BSS_ADMIN_DOWN:
31 /* NOTHING: we or the remote end administratively shutdown. */
32 break;
33 case BSS_DOWN:
34 /* Peer went down, remove this next hop. */
35 DEBUGD(&static_dbg_bfd,
36 "%s: next hop is down, remove it from RIB", __func__);
37 sn->path_down = true;
38 static_zebra_route_add(sn->pn, true);
39 break;
40 case BSS_UP:
41 /* Peer is back up, add this next hop. */
42 DEBUGD(&static_dbg_bfd, "%s: next hop is up, add it to RIB",
43 __func__);
44 sn->path_down = false;
45 static_zebra_route_add(sn->pn, true);
46 break;
47 }
48 }
49
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)
53 {
54 static_next_hop_bfd_change(arg, bss);
55 }
56
57 static inline int
58 static_next_hop_type_to_family(const struct static_nexthop *sn)
59 {
60 switch (sn->type) {
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)
67 return AF_INET;
68 else
69 return AF_INET6;
70 break;
71 case STATIC_IFNAME:
72 case STATIC_BLACKHOLE:
73 default:
74 zlog_err("%s: invalid next hop type", __func__);
75 break;
76 }
77
78 return AF_UNSPEC;
79 }
80
81 void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn,
82 const struct lyd_node *dnode)
83 {
84 bool use_interface;
85 bool use_profile;
86 bool use_source;
87 bool onlink;
88 bool mhop;
89 int family;
90 struct ipaddr source;
91
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");
98
99
100 family = static_next_hop_type_to_family(sn);
101 if (family == AF_UNSPEC)
102 return;
103
104 if (sn->type == STATIC_IPV4_GATEWAY_IFNAME ||
105 sn->type == STATIC_IPV6_GATEWAY_IFNAME)
106 use_interface = true;
107
108 /* Reconfigure or allocate new memory. */
109 if (sn->bsp == NULL)
110 sn->bsp = bfd_sess_new(static_next_hop_bfd_updatecb, sn);
111
112 /* Configure the session. */
113 if (use_source)
114 yang_dnode_get_ip(&source, dnode, "./source");
115
116 if (onlink || mhop == false)
117 bfd_sess_set_auto_source(sn->bsp, false);
118 else
119 bfd_sess_set_auto_source(sn->bsp, !use_source);
120
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,
125 &sn->addr.ipv4);
126 else if (family == AF_INET6)
127 bfd_sess_set_ipv6_addrs(sn->bsp,
128 use_source ? &source.ip._v6_addr : NULL,
129 &sn->addr.ipv6);
130
131 bfd_sess_set_interface(sn->bsp, use_interface ? sn->ifname : NULL);
132
133 bfd_sess_set_profile(sn->bsp, use_profile ? yang_dnode_get_string(
134 dnode, "./profile")
135 : NULL);
136
137 bfd_sess_set_hop_count(sn->bsp, (onlink || mhop == false) ? 1 : 254);
138
139 /* Install or update the session. */
140 bfd_sess_install(sn->bsp);
141
142 /* Update current path status. */
143 sn->path_down = (bfd_sess_status(sn->bsp) != BSS_UP);
144 }
145
146 void static_next_hop_bfd_monitor_disable(struct static_nexthop *sn)
147 {
148 bfd_sess_free(&sn->bsp);
149
150 /* Reset path status. */
151 sn->path_down = false;
152 }
153
154 void static_next_hop_bfd_source(struct static_nexthop *sn,
155 const struct ipaddr *source)
156 {
157 int family;
158
159 if (sn->bsp == NULL)
160 return;
161
162 family = static_next_hop_type_to_family(sn);
163 if (family == AF_UNSPEC)
164 return;
165
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,
169 &sn->addr.ipv4);
170 else if (family == AF_INET6)
171 bfd_sess_set_ipv6_addrs(sn->bsp, &source->ip._v6_addr,
172 &sn->addr.ipv6);
173
174 bfd_sess_install(sn->bsp);
175 }
176
177 void static_next_hop_bfd_auto_source(struct static_nexthop *sn)
178 {
179 if (sn->bsp == NULL)
180 return;
181
182 bfd_sess_set_auto_source(sn->bsp, true);
183 bfd_sess_install(sn->bsp);
184 }
185
186 void static_next_hop_bfd_multi_hop(struct static_nexthop *sn, bool mhop)
187 {
188 if (sn->bsp == NULL)
189 return;
190
191 bfd_sess_set_hop_count(sn->bsp, mhop ? 254 : 1);
192 bfd_sess_install(sn->bsp);
193 }
194
195 void static_next_hop_bfd_profile(struct static_nexthop *sn, const char *name)
196 {
197 if (sn->bsp == NULL)
198 return;
199
200 bfd_sess_set_profile(sn->bsp, name);
201 bfd_sess_install(sn->bsp);
202 }
203
204 void static_bfd_initialize(struct zclient *zc, struct thread_master *tm)
205 {
206 /* Initialize BFD integration library. */
207 bfd_protocol_integration_init(zc, tm);
208 }
209
210 /*
211 * Display functions
212 */
213 static void static_bfd_show_nexthop_json(struct vty *vty,
214 struct json_object *jo,
215 const struct static_nexthop *sn)
216 {
217 const struct prefix *dst_p, *src_p;
218 struct json_object *jo_nh;
219
220 jo_nh = json_object_new_object();
221
222 srcdest_rnode_prefixes(sn->rn, &dst_p, &src_p);
223 if (src_p)
224 json_object_string_addf(jo_nh, "from", "%pFX", src_p);
225
226 json_object_string_addf(jo_nh, "prefix", "%pFX", dst_p);
227 json_object_string_add(jo_nh, "vrf", sn->nh_vrfname);
228
229 json_object_boolean_add(jo_nh, "installed", !sn->path_down);
230
231 json_object_array_add(jo, jo_nh);
232 }
233
234 static void static_bfd_show_path_json(struct vty *vty, struct json_object *jo,
235 struct route_table *rt)
236 {
237 struct route_node *rn;
238
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;
242
243 if (si == NULL)
244 continue;
245
246 frr_each (static_path_list, &si->path_list, sp) {
247 struct static_nexthop *sn;
248
249 frr_each (static_nexthop_list, &sp->nexthop_list, sn) {
250 /* Skip non configured BFD sessions. */
251 if (sn->bsp == NULL)
252 continue;
253
254 static_bfd_show_nexthop_json(vty, jo, sn);
255 }
256 }
257 }
258 }
259
260 static void static_bfd_show_json(struct vty *vty)
261 {
262 struct json_object *jo, *jo_path, *jo_afi_safi;
263 struct vrf *vrf;
264
265 jo = json_object_new_object();
266 jo_path = json_object_new_object();
267
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;
272
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];
276 if (rt)
277 static_bfd_show_path_json(vty, jo_afi_safi, rt);
278
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];
282 if (rt)
283 static_bfd_show_path_json(vty, jo_afi_safi, rt);
284
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];
288 if (rt)
289 static_bfd_show_path_json(vty, jo_afi_safi, rt);
290 }
291
292 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
293 json_object_free(jo);
294 }
295
296 static void static_bfd_show_nexthop(struct vty *vty,
297 const struct static_nexthop *sn)
298 {
299 vty_out(vty, " %pRN", sn->rn);
300
301 if (sn->bsp == NULL) {
302 vty_out(vty, "\n");
303 return;
304 }
305
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);
312 else
313 vty_out(vty, " peer unknown");
314
315 vty_out(vty, " (status: %s)\n",
316 sn->path_down ? "uninstalled" : "installed");
317 }
318
319 static void static_bfd_show_path(struct vty *vty, struct route_table *rt)
320 {
321 struct route_node *rn;
322
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;
326
327 if (si == NULL)
328 continue;
329
330 frr_each (static_path_list, &si->path_list, sp) {
331 struct static_nexthop *sn;
332
333 frr_each (static_nexthop_list, &sp->nexthop_list, sn) {
334 /* Skip non configured BFD sessions. */
335 if (sn->bsp == NULL)
336 continue;
337
338 static_bfd_show_nexthop(vty, sn);
339 }
340 }
341 }
342 }
343
344 void static_bfd_show(struct vty *vty, bool json)
345 {
346 struct vrf *vrf;
347
348 if (json) {
349 static_bfd_show_json(vty);
350 return;
351 }
352
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;
358
359 vty_out(vty, " VRF %s IPv4 Unicast:\n", vrf->name);
360 rt = svrf->stable[AFI_IP][SAFI_UNICAST];
361 if (rt)
362 static_bfd_show_path(vty, rt);
363
364 vty_out(vty, "\n VRF %s IPv4 Multicast:\n", vrf->name);
365 rt = svrf->stable[AFI_IP][SAFI_MULTICAST];
366 if (rt)
367 static_bfd_show_path(vty, rt);
368
369 vty_out(vty, "\n VRF %s IPv6 Unicast:\n", vrf->name);
370 rt = svrf->stable[AFI_IP6][SAFI_UNICAST];
371 if (rt)
372 static_bfd_show_path(vty, rt);
373 }
374
375 vty_out(vty, "\n");
376 }