2 * bgp_bfd.c: BGP BFD handling routines
4 * @copyright Copyright (C) 2015 Cumulus Networks, Inc.
6 * This file is part of GNU Zebra.
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
38 #include "bgpd/bgpd.h"
40 #include "bgpd/bgp_bfd.h"
41 #include "bgpd/bgp_debug.h"
42 #include "bgpd/bgp_vty.h"
44 extern struct zclient
*zclient
;
47 * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group
51 void bgp_bfd_peer_group2peer_copy(struct peer
*conf
, struct peer
*peer
)
53 struct bfd_info
*bfd_info
;
54 struct bfd_info
*conf_bfd_info
;
59 conf_bfd_info
= (struct bfd_info
*)conf
->bfd_info
;
61 peer
->bfd_info
= bfd_info_create();
63 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
65 /* Copy BFD parameter values */
66 bfd_info
->required_min_rx
= conf_bfd_info
->required_min_rx
;
67 bfd_info
->desired_min_tx
= conf_bfd_info
->desired_min_tx
;
68 bfd_info
->detect_mult
= conf_bfd_info
->detect_mult
;
69 bfd_info
->type
= conf_bfd_info
->type
;
73 * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single
76 int bgp_bfd_is_peer_multihop(struct peer
*peer
)
78 struct bfd_info
*bfd_info
;
80 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
85 if ((bfd_info
->type
== BFD_TYPE_MULTIHOP
)
86 || ((peer
->sort
== BGP_PEER_IBGP
) && !peer
->shared_network
)
87 || is_ebgp_multihop_configured(peer
))
94 * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister
95 * command to Zebra to be forwarded to BFD
97 static void bgp_bfd_peer_sendmsg(struct peer
*peer
, int command
)
99 struct bfd_info
*bfd_info
;
100 vrf_id_t vrf_id
= VRF_DEFAULT
;
103 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
105 if (peer
->bgp
&& (peer
->bgp
->inst_type
== BGP_INSTANCE_TYPE_VRF
))
106 vrf_id
= peer
->bgp
->vrf_id
;
108 if (command
== ZEBRA_BFD_DEST_DEREGISTER
) {
110 CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
111 UNSET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
113 multihop
= bgp_bfd_is_peer_multihop(peer
);
114 if ((command
== ZEBRA_BFD_DEST_REGISTER
) && multihop
)
115 SET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
118 if (peer
->su
.sa
.sa_family
== AF_INET
)
120 zclient
, bfd_info
, AF_INET
, &peer
->su
.sin
.sin_addr
,
121 (peer
->su_local
) ? &peer
->su_local
->sin
.sin_addr
: NULL
,
122 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
123 peer
->ttl
, multihop
, command
, 1, vrf_id
);
124 else if (peer
->su
.sa
.sa_family
== AF_INET6
)
126 zclient
, bfd_info
, AF_INET6
, &peer
->su
.sin6
.sin6_addr
,
127 (peer
->su_local
) ? &peer
->su_local
->sin6
.sin6_addr
129 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
130 peer
->ttl
, multihop
, command
, 1, vrf_id
);
134 * bgp_bfd_register_peer - register a peer with BFD through zebra
135 * for monitoring the peer rechahability.
137 void bgp_bfd_register_peer(struct peer
*peer
)
139 struct bfd_info
*bfd_info
;
143 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
145 /* Check if BFD is enabled and peer has already been registered with BFD
147 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
150 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
154 * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
155 * for stopping the monitoring of the peer
158 void bgp_bfd_deregister_peer(struct peer
*peer
)
160 struct bfd_info
*bfd_info
;
164 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
166 /* Check if BFD is eanbled and peer has not been registered */
167 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
170 bfd_info
->status
= BFD_STATUS_DOWN
;
171 bfd_info
->last_update
= bgp_clock();
173 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
177 * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
180 static void bgp_bfd_update_peer(struct peer
*peer
)
182 struct bfd_info
*bfd_info
;
186 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
188 /* Check if the peer has been registered with BFD*/
189 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
192 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_UPDATE
);
196 * bgp_bfd_update_type - update session type with BFD through zebra.
198 static void bgp_bfd_update_type(struct peer
*peer
)
200 struct bfd_info
*bfd_info
;
205 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
207 /* Check if the peer has been registered with BFD*/
208 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
211 if (bfd_info
->type
== BFD_TYPE_NOT_CONFIGURED
) {
212 multihop
= bgp_bfd_is_peer_multihop(peer
);
214 && !CHECK_FLAG(bfd_info
->flags
,
215 BFD_FLAG_BFD_TYPE_MULTIHOP
))
216 || (!multihop
&& CHECK_FLAG(bfd_info
->flags
,
217 BFD_FLAG_BFD_TYPE_MULTIHOP
))) {
218 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
219 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
222 if ((bfd_info
->type
== BFD_TYPE_MULTIHOP
223 && !CHECK_FLAG(bfd_info
->flags
,
224 BFD_FLAG_BFD_TYPE_MULTIHOP
))
225 || (bfd_info
->type
== BFD_TYPE_SINGLEHOP
226 && CHECK_FLAG(bfd_info
->flags
,
227 BFD_FLAG_BFD_TYPE_MULTIHOP
))) {
228 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
229 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
235 * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
238 static int bgp_bfd_dest_replay(int command
, struct zclient
*client
,
239 zebra_size_t length
, vrf_id_t vrf_id
)
241 struct listnode
*mnode
, *node
, *nnode
;
245 if (BGP_DEBUG(zebra
, ZEBRA
))
246 zlog_debug("Zebra: BFD Dest replay request");
248 /* Send the client registration */
249 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
251 /* Replay the peer, if BFD is enabled in BGP */
253 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, mnode
, bgp
))
254 for (ALL_LIST_ELEMENTS(bgp
->peer
, node
, nnode
, peer
)) {
255 bgp_bfd_update_peer(peer
);
262 * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
263 * down the peer if the BFD session went down from
266 static void bgp_bfd_peer_status_update(struct peer
*peer
, int status
)
268 struct bfd_info
*bfd_info
;
271 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
273 if (bfd_info
->status
== status
)
276 old_status
= bfd_info
->status
;
277 bfd_info
->status
= status
;
278 bfd_info
->last_update
= bgp_clock();
280 if ((status
== BFD_STATUS_DOWN
) && (old_status
== BFD_STATUS_UP
)) {
281 peer
->last_reset
= PEER_DOWN_BFD_DOWN
;
282 BGP_EVENT_ADD(peer
, BGP_Stop
);
287 * bgp_bfd_dest_update - Find the peer for which the BFD status
288 * has changed and bring down the peer
289 * connectivity if the BFD session went down.
291 static int bgp_bfd_dest_update(int command
, struct zclient
*zclient
,
292 zebra_size_t length
, vrf_id_t vrf_id
)
294 struct interface
*ifp
;
299 ifp
= bfd_get_peer_info(zclient
->ibuf
, &dp
, &sp
, &status
, vrf_id
);
301 if (BGP_DEBUG(zebra
, ZEBRA
)) {
302 char buf
[2][PREFIX2STR_BUFFER
];
303 prefix2str(&dp
, buf
[0], sizeof(buf
[0]));
306 "Zebra: vrf %d interface %s bfd destination %s %s",
307 vrf_id
, ifp
->name
, buf
[0],
308 bfd_get_status_str(status
));
310 prefix2str(&sp
, buf
[1], sizeof(buf
[1]));
312 "Zebra: vrf %d source %s bfd destination %s %s",
313 vrf_id
, buf
[1], buf
[0],
314 bfd_get_status_str(status
));
318 /* Bring the peer down if BFD is enabled in BGP */
320 struct listnode
*mnode
, *node
, *nnode
;
324 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, mnode
, bgp
))
325 for (ALL_LIST_ELEMENTS(bgp
->peer
, node
, nnode
, peer
)) {
329 if ((dp
.family
== AF_INET
)
330 && (peer
->su
.sa
.sa_family
== AF_INET
)) {
331 if (dp
.u
.prefix4
.s_addr
332 != peer
->su
.sin
.sin_addr
.s_addr
)
334 } else if ((dp
.family
== AF_INET6
)
335 && (peer
->su
.sa
.sa_family
337 if (memcmp(&dp
.u
.prefix6
,
338 &peer
->su
.sin6
.sin6_addr
,
339 sizeof(struct in6_addr
)))
344 if (ifp
&& (ifp
== peer
->nexthop
.ifp
)) {
345 bgp_bfd_peer_status_update(peer
,
351 if ((sp
.family
== AF_INET
)
352 && (peer
->su_local
->sa
.sa_family
354 if (sp
.u
.prefix4
.s_addr
355 != peer
->su_local
->sin
358 } else if ((sp
.family
== AF_INET6
)
359 && (peer
->su_local
->sa
362 if (memcmp(&sp
.u
.prefix6
,
363 &peer
->su_local
->sin6
371 if ((vrf_id
!= VRF_DEFAULT
)
372 && (peer
->bgp
->vrf_id
!= vrf_id
))
375 bgp_bfd_peer_status_update(peer
,
385 * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
387 static int bgp_bfd_peer_param_set(struct peer
*peer
, u_int32_t min_rx
,
388 u_int32_t min_tx
, u_int8_t detect_mult
,
391 struct peer_group
*group
;
392 struct listnode
*node
, *nnode
;
395 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
), min_rx
, min_tx
,
396 detect_mult
, defaults
, &command
);
398 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
)) {
400 for (ALL_LIST_ELEMENTS(group
->peer
, node
, nnode
, peer
)) {
402 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
),
403 min_rx
, min_tx
, detect_mult
, defaults
,
406 if ((peer
->status
== Established
)
407 && (command
== ZEBRA_BFD_DEST_REGISTER
))
408 bgp_bfd_register_peer(peer
);
409 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
410 bgp_bfd_update_peer(peer
);
413 if ((peer
->status
== Established
)
414 && (command
== ZEBRA_BFD_DEST_REGISTER
))
415 bgp_bfd_register_peer(peer
);
416 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
417 bgp_bfd_update_peer(peer
);
423 * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for
426 static int bgp_bfd_peer_param_unset(struct peer
*peer
)
428 struct peer_group
*group
;
429 struct listnode
*node
, *nnode
;
434 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
)) {
435 bfd_info_free(&(peer
->bfd_info
));
437 for (ALL_LIST_ELEMENTS(group
->peer
, node
, nnode
, peer
)) {
438 bgp_bfd_deregister_peer(peer
);
439 bfd_info_free(&(peer
->bfd_info
));
442 bgp_bfd_deregister_peer(peer
);
443 bfd_info_free(&(peer
->bfd_info
));
449 * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or
452 static int bgp_bfd_peer_param_type_set(struct peer
*peer
,
453 enum bfd_sess_type type
)
455 struct peer_group
*group
;
456 struct listnode
*node
, *nnode
;
458 struct bfd_info
*bfd_info
;
461 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
),
462 BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
463 BFD_DEF_DETECT_MULT
, 1, &command
);
465 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
466 bfd_info
->type
= type
;
468 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
)) {
470 for (ALL_LIST_ELEMENTS(group
->peer
, node
, nnode
, peer
)) {
474 (struct bfd_info
**)&(peer
->bfd_info
),
475 BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
476 BFD_DEF_DETECT_MULT
, 1, &command
);
478 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
479 bfd_info
->type
= type
;
481 if (peer
->status
== Established
) {
482 if (command
== ZEBRA_BFD_DEST_REGISTER
)
483 bgp_bfd_register_peer(peer
);
485 bgp_bfd_update_type(peer
);
489 if (peer
->status
== Established
) {
490 if (command
== ZEBRA_BFD_DEST_REGISTER
)
491 bgp_bfd_register_peer(peer
);
493 bgp_bfd_update_type(peer
);
501 * bgp_bfd_peer_config_write - Write the peer BFD configuration.
503 void bgp_bfd_peer_config_write(struct vty
*vty
, struct peer
*peer
, char *addr
)
505 struct bfd_info
*bfd_info
;
510 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
512 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_PARAM_CFG
))
513 vty_out(vty
, " neighbor %s bfd %d %d %d%s", addr
,
514 bfd_info
->detect_mult
, bfd_info
->required_min_rx
,
515 bfd_info
->desired_min_tx
, VTY_NEWLINE
);
517 if (bfd_info
->type
!= BFD_TYPE_NOT_CONFIGURED
)
518 vty_out(vty
, " neighbor %s bfd %s%s", addr
,
519 (bfd_info
->type
== BFD_TYPE_MULTIHOP
) ? "multihop"
523 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_PARAM_CFG
)
524 && (bfd_info
->type
== BFD_TYPE_NOT_CONFIGURED
))
525 vty_out(vty
, " neighbor %s bfd%s", addr
, VTY_NEWLINE
);
529 * bgp_bfd_show_info - Show the peer BFD information.
531 void bgp_bfd_show_info(struct vty
*vty
, struct peer
*peer
, u_char use_json
,
532 json_object
*json_neigh
)
534 bfd_show_info(vty
, (struct bfd_info
*)peer
->bfd_info
,
535 bgp_bfd_is_peer_multihop(peer
), 0, use_json
, json_neigh
);
540 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
543 "Enables BFD support\n")
549 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
553 ret
= bgp_bfd_peer_param_set(peer
, BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
554 BFD_DEF_DETECT_MULT
, 1);
556 return bgp_vty_return(vty
, ret
);
561 DEFUN (neighbor_bfd_param
,
562 neighbor_bfd_param_cmd
,
563 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd (2-255) (50-60000) (50-60000)",
566 "Enables BFD support\n"
567 "Detect Multiplier\n"
568 "Required min receive interval\n"
569 "Desired min transmit interval\n")
572 int idx_number_1
= 3;
573 int idx_number_2
= 4;
574 int idx_number_3
= 5;
581 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
585 if ((ret
= bfd_validate_param(
586 vty
, argv
[idx_number_1
]->arg
, argv
[idx_number_2
]->arg
,
587 argv
[idx_number_3
]->arg
, &dm_val
, &rx_val
, &tx_val
))
591 ret
= bgp_bfd_peer_param_set(peer
, rx_val
, tx_val
, dm_val
, 0);
593 return bgp_vty_return(vty
, ret
);
598 DEFUN_HIDDEN (neighbor_bfd_type
,
599 neighbor_bfd_type_cmd
,
600 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
603 "Enables BFD support\n"
605 "Single hop session\n")
610 enum bfd_sess_type type
;
613 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
617 if (!strcmp(argv
[idx_hop
]->arg
, "singlehop"))
618 type
= BFD_TYPE_SINGLEHOP
;
619 else if (!strcmp(argv
[idx_hop
]->arg
, "multihop"))
620 type
= BFD_TYPE_MULTIHOP
;
624 ret
= bgp_bfd_peer_param_type_set(peer
, type
);
626 return bgp_vty_return(vty
, ret
);
631 DEFUN (no_neighbor_bfd
,
633 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd [(2-255) (50-60000) (50-60000)]",
637 "Disables BFD support\n"
638 "Detect Multiplier\n"
639 "Required min receive interval\n"
640 "Desired min transmit interval\n")
646 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
650 ret
= bgp_bfd_peer_param_unset(peer
);
652 return bgp_vty_return(vty
, ret
);
658 DEFUN_HIDDEN (no_neighbor_bfd_type
,
659 no_neighbor_bfd_type_cmd
,
660 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
664 "Disables BFD support\n"
666 "Singlehop session\n")
672 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
679 ret
= bgp_bfd_peer_param_type_set(peer
, BFD_TYPE_NOT_CONFIGURED
);
681 return bgp_vty_return(vty
, ret
);
686 void bgp_bfd_init(void)
690 /* Initialize BFD client functions */
691 zclient
->interface_bfd_dest_update
= bgp_bfd_dest_update
;
692 zclient
->bfd_dest_replay
= bgp_bfd_dest_replay
;
694 /* "neighbor bfd" commands. */
695 install_element(BGP_NODE
, &neighbor_bfd_cmd
);
696 install_element(BGP_NODE
, &neighbor_bfd_param_cmd
);
697 install_element(BGP_NODE
, &neighbor_bfd_type_cmd
);
698 install_element(BGP_NODE
, &no_neighbor_bfd_cmd
);
699 install_element(BGP_NODE
, &no_neighbor_bfd_type_cmd
);