2 * pim_bfd.c: PIM BFD handling routines
4 * Copyright (C) 2017 Cumulus Networks, Inc.
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, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
30 #include "pim_instance.h"
33 #include "pim_iface.h"
37 #include "pim_zebra.h"
40 * pim_bfd_write_config - Write the interface BFD configuration.
42 void pim_bfd_write_config(struct vty
*vty
, struct interface
*ifp
)
44 struct pim_interface
*pim_ifp
= ifp
->info
;
45 struct bfd_info
*bfd_info
= NULL
;
50 bfd_info
= (struct bfd_info
*)pim_ifp
->bfd_info
;
55 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_PARAM_CFG
))
56 vty_out(vty
, " ip pim bfd %d %d %d\n", bfd_info
->detect_mult
,
57 bfd_info
->required_min_rx
, bfd_info
->desired_min_tx
);
59 #endif /* ! HAVE_BFDD */
60 vty_out(vty
, " ip pim bfd\n");
64 * pim_bfd_show_info - Show BFD info structure
66 void pim_bfd_show_info(struct vty
*vty
, void *bfd_info
, json_object
*json_obj
,
67 bool use_json
, int param_only
)
70 bfd_show_param(vty
, (struct bfd_info
*)bfd_info
, 1, 0, use_json
,
73 bfd_show_info(vty
, (struct bfd_info
*)bfd_info
, 0, 1, use_json
,
78 * pim_bfd_info_nbr_create - Create/update BFD information for a neighbor.
80 void pim_bfd_info_nbr_create(struct pim_interface
*pim_ifp
,
81 struct pim_neighbor
*neigh
)
83 struct bfd_info
*nbr_bfd_info
= NULL
;
85 /* Check if Pim Interface BFD is enabled */
86 if (!pim_ifp
|| !pim_ifp
->bfd_info
)
90 neigh
->bfd_info
= bfd_info_create();
95 nbr_bfd_info
= (struct bfd_info
*)neigh
->bfd_info
;
96 nbr_bfd_info
->detect_mult
= pim_ifp
->bfd_info
->detect_mult
;
97 nbr_bfd_info
->desired_min_tx
= pim_ifp
->bfd_info
->desired_min_tx
;
98 nbr_bfd_info
->required_min_rx
= pim_ifp
->bfd_info
->required_min_rx
;
102 * pim_bfd_info_free - Free BFD info structure
104 void pim_bfd_info_free(struct bfd_info
**bfd_info
)
106 bfd_info_free(bfd_info
);
109 static void pim_bfd_reg_dereg_nbr(struct pim_neighbor
*nbr
, int command
)
111 struct pim_interface
*pim_ifp
= NULL
;
112 struct bfd_info
*bfd_info
= NULL
;
113 struct zclient
*zclient
= NULL
;
116 zclient
= pim_zebra_zclient_get();
120 pim_ifp
= nbr
->interface
->info
;
121 bfd_info
= (struct bfd_info
*)pim_ifp
->bfd_info
;
124 if (PIM_DEBUG_PIM_TRACE
) {
125 char str
[INET_ADDRSTRLEN
];
126 pim_inet4_dump("<bfd_nbr?>", nbr
->source_addr
, str
,
128 zlog_debug("%s Nbr %s %s with BFD", __PRETTY_FUNCTION__
, str
,
129 bfd_get_command_dbg_str(command
));
132 cbit
= CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_CBIT_ON
);
134 bfd_peer_sendmsg(zclient
, bfd_info
, AF_INET
, &nbr
->source_addr
, NULL
,
135 nbr
->interface
->name
, 0, 0, cbit
,
136 command
, 0, VRF_DEFAULT
);
140 * pim_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated
141 * with a interface with BFD through
142 * zebra for starting/stopping the monitoring of
143 * the neighbor rechahability.
145 int pim_bfd_reg_dereg_all_nbr(struct interface
*ifp
, int command
)
147 struct pim_interface
*pim_ifp
= NULL
;
148 struct listnode
*node
= NULL
;
149 struct pim_neighbor
*neigh
= NULL
;
154 if (!pim_ifp
->bfd_info
)
157 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
158 if (command
!= ZEBRA_BFD_DEST_DEREGISTER
)
159 pim_bfd_info_nbr_create(pim_ifp
, neigh
);
161 pim_bfd_info_free((struct bfd_info
**)&neigh
->bfd_info
);
163 pim_bfd_reg_dereg_nbr(neigh
, command
);
170 * pim_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
171 * neighbor state is changed to/from 2way.
173 void pim_bfd_trigger_event(struct pim_interface
*pim_ifp
,
174 struct pim_neighbor
*nbr
, uint8_t nbr_up
)
177 pim_bfd_info_nbr_create(pim_ifp
, nbr
);
178 pim_bfd_reg_dereg_nbr(nbr
, ZEBRA_BFD_DEST_REGISTER
);
180 pim_bfd_info_free(&nbr
->bfd_info
);
181 pim_bfd_reg_dereg_nbr(nbr
, ZEBRA_BFD_DEST_DEREGISTER
);
186 * pim_bfd_if_param_set - Set the configured BFD paramter values for
189 void pim_bfd_if_param_set(struct interface
*ifp
, uint32_t min_rx
,
190 uint32_t min_tx
, uint8_t detect_mult
, int defaults
)
192 struct pim_interface
*pim_ifp
= ifp
->info
;
197 bfd_set_param((struct bfd_info
**)&(pim_ifp
->bfd_info
), min_rx
, min_tx
,
198 detect_mult
, defaults
, &command
);
200 if (pim_ifp
->bfd_info
) {
201 if (PIM_DEBUG_PIM_TRACE
)
202 zlog_debug("%s: interface %s has bfd_info",
203 __PRETTY_FUNCTION__
, ifp
->name
);
206 pim_bfd_reg_dereg_all_nbr(ifp
, command
);
211 * pim_bfd_interface_dest_update - Find the neighbor for which the BFD status
212 * has changed and bring down the neighbor
213 * connectivity if the BFD status changed to
216 static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS
)
218 struct interface
*ifp
= NULL
;
219 struct pim_interface
*pim_ifp
= NULL
;
224 struct bfd_info
*bfd_info
= NULL
;
226 struct listnode
*neigh_node
= NULL
;
227 struct listnode
*neigh_nextnode
= NULL
;
228 struct pim_neighbor
*neigh
= NULL
;
230 ifp
= bfd_get_peer_info(zclient
->ibuf
, &p
, NULL
, &status
,
233 if ((ifp
== NULL
) || (p
.family
!= AF_INET
))
240 if (!pim_ifp
->bfd_info
) {
241 if (PIM_DEBUG_PIM_TRACE
)
242 zlog_debug("%s: pim interface %s BFD is disabled ",
243 __PRETTY_FUNCTION__
, ifp
->name
);
247 if (PIM_DEBUG_PIM_TRACE
) {
248 char buf
[PREFIX2STR_BUFFER
];
249 prefix2str(&p
, buf
, sizeof(buf
));
250 zlog_debug("%s: interface %s bfd destination %s %s",
251 __PRETTY_FUNCTION__
, ifp
->name
, buf
,
252 bfd_get_status_str(status
));
255 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
, neigh_node
,
256 neigh_nextnode
, neigh
)) {
257 /* Check neigh address matches with BFD address */
258 if (neigh
->source_addr
.s_addr
!= p
.u
.prefix4
.s_addr
)
261 bfd_info
= (struct bfd_info
*)neigh
->bfd_info
;
262 if (bfd_info
->status
== status
) {
263 if (PIM_DEBUG_PIM_TRACE
) {
264 char str
[INET_ADDRSTRLEN
];
265 pim_inet4_dump("<nht_nbr?>", neigh
->source_addr
,
267 zlog_debug("%s: bfd status is same for nbr %s",
268 __PRETTY_FUNCTION__
, str
);
272 old_status
= bfd_info
->status
;
273 BFD_SET_CLIENT_STATUS(bfd_info
->status
, status
);
275 bfd_info
->last_update
= tv
.tv_sec
;
277 if (PIM_DEBUG_PIM_TRACE
) {
278 zlog_debug("%s: status %s old_status %s",
280 bfd_get_status_str(status
),
281 bfd_get_status_str(old_status
));
283 if ((status
== BFD_STATUS_DOWN
)
284 && (old_status
== BFD_STATUS_UP
)) {
285 snprintf(msg
, sizeof(msg
), "BFD Session Expired");
286 pim_neighbor_delete(ifp
, neigh
, msg
);
293 * pim_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
296 static int pim_bfd_nbr_replay(ZAPI_CALLBACK_ARGS
)
298 struct interface
*ifp
= NULL
;
299 struct pim_interface
*pim_ifp
= NULL
;
300 struct pim_neighbor
*neigh
= NULL
;
301 struct listnode
*neigh_node
;
302 struct listnode
*neigh_nextnode
;
303 struct vrf
*vrf
= NULL
;
305 /* Send the client registration */
306 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
, vrf_id
);
308 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
309 FOR_ALL_INTERFACES (vrf
, ifp
) {
315 if (pim_ifp
->pim_sock_fd
< 0)
318 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
,
319 neigh_node
, neigh_nextnode
,
321 if (!neigh
->bfd_info
)
323 if (PIM_DEBUG_PIM_TRACE
) {
324 char str
[INET_ADDRSTRLEN
];
326 pim_inet4_dump("<bfd_nbr?>",
327 neigh
->source_addr
, str
,
330 "%s: Replaying Pim Neigh %s to BFD vrf_id %u",
331 __PRETTY_FUNCTION__
, str
,
334 pim_bfd_reg_dereg_nbr(neigh
,
335 ZEBRA_BFD_DEST_UPDATE
);
342 void pim_bfd_init(void)
344 struct zclient
*zclient
= NULL
;
346 zclient
= pim_zebra_zclient_get();
350 zclient
->interface_bfd_dest_update
= pim_bfd_interface_dest_update
;
351 zclient
->bfd_dest_replay
= pim_bfd_nbr_replay
;