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
;
54 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_PARAM_CFG
))
55 vty_out(vty
, " ip pim bfd %d %d %d\n", bfd_info
->detect_mult
,
56 bfd_info
->required_min_rx
, bfd_info
->desired_min_tx
);
58 vty_out(vty
, " ip pim bfd\n");
62 * pim_bfd_show_info - Show BFD info structure
64 void pim_bfd_show_info(struct vty
*vty
, void *bfd_info
, json_object
*json_obj
,
65 u_char use_json
, int param_only
)
68 bfd_show_param(vty
, (struct bfd_info
*)bfd_info
, 1, 0, use_json
,
71 bfd_show_info(vty
, (struct bfd_info
*)bfd_info
, 0, 1, use_json
,
76 * pim_bfd_info_nbr_create - Create/update BFD information for a neighbor.
78 void pim_bfd_info_nbr_create(struct pim_interface
*pim_ifp
,
79 struct pim_neighbor
*neigh
)
81 struct bfd_info
*nbr_bfd_info
= NULL
;
83 /* Check if Pim Interface BFD is enabled */
84 if (!pim_ifp
|| !pim_ifp
->bfd_info
)
88 neigh
->bfd_info
= bfd_info_create();
93 nbr_bfd_info
= (struct bfd_info
*)neigh
->bfd_info
;
94 nbr_bfd_info
->detect_mult
= pim_ifp
->bfd_info
->detect_mult
;
95 nbr_bfd_info
->desired_min_tx
= pim_ifp
->bfd_info
->desired_min_tx
;
96 nbr_bfd_info
->required_min_rx
= pim_ifp
->bfd_info
->required_min_rx
;
100 * pim_bfd_info_free - Free BFD info structure
102 void pim_bfd_info_free(void **bfd_info
)
104 bfd_info_free((struct bfd_info
**)bfd_info
);
107 static void pim_bfd_reg_dereg_nbr(struct pim_neighbor
*nbr
, int command
)
109 struct pim_interface
*pim_ifp
= NULL
;
110 struct bfd_info
*bfd_info
= NULL
;
111 struct zclient
*zclient
= NULL
;
113 zclient
= pim_zebra_zclient_get();
117 pim_ifp
= nbr
->interface
->info
;
118 bfd_info
= (struct bfd_info
*)pim_ifp
->bfd_info
;
121 if (PIM_DEBUG_PIM_TRACE
) {
122 char str
[INET_ADDRSTRLEN
];
123 pim_inet4_dump("<bfd_nbr?>", nbr
->source_addr
, str
,
125 zlog_debug("%s Nbr %s %s with BFD", __PRETTY_FUNCTION__
, str
,
126 bfd_get_command_dbg_str(command
));
128 bfd_peer_sendmsg(zclient
, bfd_info
, AF_INET
, &nbr
->source_addr
, NULL
,
129 nbr
->interface
->name
, 0, 0, command
, 0, VRF_DEFAULT
);
133 * pim_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated
134 * with a interface with BFD through
135 * zebra for starting/stopping the monitoring of
136 * the neighbor rechahability.
138 int pim_bfd_reg_dereg_all_nbr(struct interface
*ifp
, int command
)
140 struct pim_interface
*pim_ifp
= NULL
;
141 struct listnode
*node
= NULL
;
142 struct pim_neighbor
*neigh
= NULL
;
147 if (!pim_ifp
->bfd_info
)
150 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
151 if (command
!= ZEBRA_BFD_DEST_DEREGISTER
)
152 pim_bfd_info_nbr_create(pim_ifp
, neigh
);
154 bfd_info_free((struct bfd_info
**)&neigh
->bfd_info
);
156 pim_bfd_reg_dereg_nbr(neigh
, command
);
163 * pim_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
164 * neighbor state is changed to/from 2way.
166 void pim_bfd_trigger_event(struct pim_interface
*pim_ifp
,
167 struct pim_neighbor
*nbr
, uint8_t nbr_up
)
170 pim_bfd_info_nbr_create(pim_ifp
, nbr
);
171 pim_bfd_reg_dereg_nbr(nbr
, ZEBRA_BFD_DEST_REGISTER
);
173 pim_bfd_info_free((void *)&nbr
->bfd_info
);
174 pim_bfd_reg_dereg_nbr(nbr
, ZEBRA_BFD_DEST_DEREGISTER
);
179 * pim_bfd_if_param_set - Set the configured BFD paramter values for
182 void pim_bfd_if_param_set(struct interface
*ifp
, u_int32_t min_rx
,
183 u_int32_t min_tx
, u_int8_t detect_mult
, int defaults
)
185 struct pim_interface
*pim_ifp
= ifp
->info
;
190 bfd_set_param((struct bfd_info
**)&(pim_ifp
->bfd_info
), min_rx
, min_tx
,
191 detect_mult
, defaults
, &command
);
193 if (pim_ifp
->bfd_info
) {
194 if (PIM_DEBUG_PIM_TRACE
)
195 zlog_debug("%s: interface %s has bfd_info",
196 __PRETTY_FUNCTION__
, ifp
->name
);
199 pim_bfd_reg_dereg_all_nbr(ifp
, command
);
204 * pim_bfd_interface_dest_update - Find the neighbor for which the BFD status
205 * has changed and bring down the neighbor
206 * connectivity if the BFD status changed to
209 static int pim_bfd_interface_dest_update(int command
, struct zclient
*zclient
,
210 zebra_size_t length
, vrf_id_t vrf_id
)
212 struct interface
*ifp
= NULL
;
213 struct pim_interface
*pim_ifp
= NULL
;
218 struct bfd_info
*bfd_info
= NULL
;
220 struct listnode
*neigh_node
= NULL
;
221 struct listnode
*neigh_nextnode
= NULL
;
222 struct pim_neighbor
*neigh
= NULL
;
224 ifp
= bfd_get_peer_info(zclient
->ibuf
, &p
, NULL
, &status
, vrf_id
);
226 if ((ifp
== NULL
) || (p
.family
!= AF_INET
))
233 if (!pim_ifp
->bfd_info
) {
234 if (PIM_DEBUG_PIM_TRACE
)
235 zlog_debug("%s: pim interface %s BFD is disabled ",
236 __PRETTY_FUNCTION__
, ifp
->name
);
240 if (PIM_DEBUG_PIM_TRACE
) {
241 char buf
[PREFIX2STR_BUFFER
];
242 prefix2str(&p
, buf
, sizeof(buf
));
243 zlog_debug("%s: interface %s bfd destination %s %s",
244 __PRETTY_FUNCTION__
, ifp
->name
, buf
,
245 bfd_get_status_str(status
));
248 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
, neigh_node
,
249 neigh_nextnode
, neigh
)) {
250 /* Check neigh address matches with BFD address */
251 if (neigh
->source_addr
.s_addr
!= p
.u
.prefix4
.s_addr
)
254 bfd_info
= (struct bfd_info
*)neigh
->bfd_info
;
255 if (bfd_info
->status
== status
) {
256 if (PIM_DEBUG_PIM_TRACE
) {
257 char str
[INET_ADDRSTRLEN
];
258 pim_inet4_dump("<nht_nbr?>", neigh
->source_addr
,
260 zlog_debug("%s: bfd status is same for nbr %s",
261 __PRETTY_FUNCTION__
, str
);
265 old_status
= bfd_info
->status
;
266 bfd_info
->status
= status
;
268 bfd_info
->last_update
= tv
.tv_sec
;
270 if (PIM_DEBUG_PIM_TRACE
) {
271 zlog_debug("%s: status %s old_status %s",
273 bfd_get_status_str(status
),
274 bfd_get_status_str(old_status
));
276 if ((status
== BFD_STATUS_DOWN
)
277 && (old_status
== BFD_STATUS_UP
)) {
278 snprintf(msg
, sizeof(msg
), "BFD Session Expired");
279 pim_neighbor_delete(ifp
, neigh
, msg
);
286 * pim_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
289 static int pim_bfd_nbr_replay(int command
, struct zclient
*zclient
,
290 zebra_size_t length
, vrf_id_t vrf_id
)
292 struct interface
*ifp
= NULL
;
293 struct pim_interface
*pim_ifp
= NULL
;
294 struct pim_neighbor
*neigh
= NULL
;
295 struct listnode
*node
;
296 struct listnode
*neigh_node
;
297 struct listnode
*neigh_nextnode
;
298 struct vrf
*vrf
= NULL
;
300 /* Send the client registration */
301 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
303 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
304 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf
->vrf_id
), node
, ifp
)) {
310 if (pim_ifp
->pim_sock_fd
< 0)
313 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
,
314 neigh_node
, neigh_nextnode
,
316 if (!neigh
->bfd_info
)
318 if (PIM_DEBUG_PIM_TRACE
) {
319 char str
[INET_ADDRSTRLEN
];
321 pim_inet4_dump("<bfd_nbr?>",
324 zlog_debug("%s: Replaying Pim Neigh %s to BFD vrf_id %u",
325 __PRETTY_FUNCTION__
, str
,
328 pim_bfd_reg_dereg_nbr(neigh
,
329 ZEBRA_BFD_DEST_UPDATE
);
336 void pim_bfd_init(void)
338 struct zclient
*zclient
= NULL
;
340 zclient
= pim_zebra_zclient_get();
344 zclient
->interface_bfd_dest_update
= pim_bfd_interface_dest_update
;
345 zclient
->bfd_dest_replay
= pim_bfd_nbr_replay
;