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 along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
37 #include "bgpd/bgpd.h"
39 #include "bgpd/bgp_bfd.h"
40 #include "bgpd/bgp_debug.h"
41 #include "bgpd/bgp_vty.h"
43 extern struct zclient
*zclient
;
46 * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group
50 void bgp_bfd_peer_group2peer_copy(struct peer
*conf
, struct peer
*peer
)
52 struct bfd_info
*bfd_info
;
53 struct bfd_info
*conf_bfd_info
;
58 conf_bfd_info
= (struct bfd_info
*)conf
->bfd_info
;
60 peer
->bfd_info
= bfd_info_create();
62 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
64 /* Copy BFD parameter values */
65 bfd_info
->required_min_rx
= conf_bfd_info
->required_min_rx
;
66 bfd_info
->desired_min_tx
= conf_bfd_info
->desired_min_tx
;
67 bfd_info
->detect_mult
= conf_bfd_info
->detect_mult
;
68 bfd_info
->type
= conf_bfd_info
->type
;
72 * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single
75 int bgp_bfd_is_peer_multihop(struct peer
*peer
)
77 struct bfd_info
*bfd_info
;
79 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
84 if ((bfd_info
->type
== BFD_TYPE_MULTIHOP
)
85 || ((peer
->sort
== BGP_PEER_IBGP
) && !peer
->shared_network
)
86 || is_ebgp_multihop_configured(peer
))
93 * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister
94 * command to Zebra to be forwarded to BFD
96 static void bgp_bfd_peer_sendmsg(struct peer
*peer
, int command
)
98 struct bfd_info
*bfd_info
;
99 vrf_id_t vrf_id
= VRF_DEFAULT
;
102 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
104 if (peer
->bgp
->inst_type
== BGP_INSTANCE_TYPE_VRF
)
105 vrf_id
= peer
->bgp
->vrf_id
;
107 if (command
== ZEBRA_BFD_DEST_DEREGISTER
) {
109 CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
110 UNSET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
112 multihop
= bgp_bfd_is_peer_multihop(peer
);
113 if ((command
== ZEBRA_BFD_DEST_REGISTER
) && multihop
)
114 SET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
117 if (peer
->su
.sa
.sa_family
== AF_INET
)
119 zclient
, bfd_info
, AF_INET
, &peer
->su
.sin
.sin_addr
,
120 (peer
->su_local
) ? &peer
->su_local
->sin
.sin_addr
: NULL
,
121 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
122 peer
->ttl
, multihop
, command
, 1, vrf_id
);
123 else if (peer
->su
.sa
.sa_family
== AF_INET6
)
125 zclient
, bfd_info
, AF_INET6
, &peer
->su
.sin6
.sin6_addr
,
126 (peer
->su_local
) ? &peer
->su_local
->sin6
.sin6_addr
128 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
129 peer
->ttl
, multihop
, command
, 1, vrf_id
);
133 * bgp_bfd_register_peer - register a peer with BFD through zebra
134 * for monitoring the peer rechahability.
136 void bgp_bfd_register_peer(struct peer
*peer
)
138 struct bfd_info
*bfd_info
;
142 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
144 /* Check if BFD is enabled and peer has already been registered with BFD
146 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
149 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
153 * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
154 * for stopping the monitoring of the peer
157 void bgp_bfd_deregister_peer(struct peer
*peer
)
159 struct bfd_info
*bfd_info
;
163 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
165 /* Check if BFD is eanbled and peer has not been registered */
166 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
169 bfd_info
->status
= BFD_STATUS_DOWN
;
170 bfd_info
->last_update
= bgp_clock();
172 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
176 * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
179 static void bgp_bfd_update_peer(struct peer
*peer
)
181 struct bfd_info
*bfd_info
;
185 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
187 /* Check if the peer has been registered with BFD*/
188 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
191 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_UPDATE
);
195 * bgp_bfd_update_type - update session type with BFD through zebra.
197 static void bgp_bfd_update_type(struct peer
*peer
)
199 struct bfd_info
*bfd_info
;
204 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
206 /* Check if the peer has been registered with BFD*/
207 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
210 if (bfd_info
->type
== BFD_TYPE_NOT_CONFIGURED
) {
211 multihop
= bgp_bfd_is_peer_multihop(peer
);
213 && !CHECK_FLAG(bfd_info
->flags
,
214 BFD_FLAG_BFD_TYPE_MULTIHOP
))
215 || (!multihop
&& CHECK_FLAG(bfd_info
->flags
,
216 BFD_FLAG_BFD_TYPE_MULTIHOP
))) {
217 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
218 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
221 if ((bfd_info
->type
== BFD_TYPE_MULTIHOP
222 && !CHECK_FLAG(bfd_info
->flags
,
223 BFD_FLAG_BFD_TYPE_MULTIHOP
))
224 || (bfd_info
->type
== BFD_TYPE_SINGLEHOP
225 && CHECK_FLAG(bfd_info
->flags
,
226 BFD_FLAG_BFD_TYPE_MULTIHOP
))) {
227 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
228 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
234 * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
237 static int bgp_bfd_dest_replay(int command
, struct zclient
*client
,
238 zebra_size_t length
, vrf_id_t vrf_id
)
240 struct listnode
*mnode
, *node
, *nnode
;
244 if (BGP_DEBUG(zebra
, ZEBRA
))
245 zlog_debug("Zebra: BFD Dest replay request");
247 /* Send the client registration */
248 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
250 /* Replay the peer, if BFD is enabled in BGP */
252 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, mnode
, bgp
))
253 for (ALL_LIST_ELEMENTS(bgp
->peer
, node
, nnode
, peer
)) {
254 bgp_bfd_update_peer(peer
);
261 * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
262 * down the peer if the BFD session went down from
265 static void bgp_bfd_peer_status_update(struct peer
*peer
, int status
)
267 struct bfd_info
*bfd_info
;
270 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
272 if (bfd_info
->status
== status
)
275 old_status
= bfd_info
->status
;
276 bfd_info
->status
= status
;
277 bfd_info
->last_update
= bgp_clock();
279 if (status
!= old_status
) {
280 if (BGP_DEBUG(neighbor_events
, NEIGHBOR_EVENTS
))
281 zlog_debug("[%s]: BFD %s", peer
->host
,
282 bfd_get_status_str(status
));
284 if ((status
== BFD_STATUS_DOWN
) && (old_status
== BFD_STATUS_UP
)) {
285 peer
->last_reset
= PEER_DOWN_BFD_DOWN
;
286 BGP_EVENT_ADD(peer
, BGP_Stop
);
288 if ((status
== BFD_STATUS_UP
) && (old_status
== BFD_STATUS_DOWN
)
289 && peer
->status
!= Established
) {
290 if (!BGP_PEER_START_SUPPRESSED(peer
)) {
291 bgp_fsm_event_update(peer
, 1);
292 BGP_EVENT_ADD(peer
, BGP_Start
);
298 * bgp_bfd_dest_update - Find the peer for which the BFD status
299 * has changed and bring down the peer
300 * connectivity if the BFD session went down.
302 static int bgp_bfd_dest_update(int command
, struct zclient
*zclient
,
303 zebra_size_t length
, vrf_id_t vrf_id
)
305 struct interface
*ifp
;
310 ifp
= bfd_get_peer_info(zclient
->ibuf
, &dp
, &sp
, &status
, vrf_id
);
312 if (BGP_DEBUG(zebra
, ZEBRA
)) {
313 char buf
[2][PREFIX2STR_BUFFER
];
314 prefix2str(&dp
, buf
[0], sizeof(buf
[0]));
317 "Zebra: vrf %u interface %s bfd destination %s %s",
318 vrf_id
, ifp
->name
, buf
[0],
319 bfd_get_status_str(status
));
321 prefix2str(&sp
, buf
[1], sizeof(buf
[1]));
323 "Zebra: vrf %u source %s bfd destination %s %s",
324 vrf_id
, buf
[1], buf
[0],
325 bfd_get_status_str(status
));
329 /* Bring the peer down if BFD is enabled in BGP */
331 struct listnode
*mnode
, *node
, *nnode
;
335 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, mnode
, bgp
))
336 for (ALL_LIST_ELEMENTS(bgp
->peer
, node
, nnode
, peer
)) {
340 if ((dp
.family
== AF_INET
)
341 && (peer
->su
.sa
.sa_family
== AF_INET
)) {
342 if (dp
.u
.prefix4
.s_addr
343 != peer
->su
.sin
.sin_addr
.s_addr
)
345 } else if ((dp
.family
== AF_INET6
)
346 && (peer
->su
.sa
.sa_family
348 if (memcmp(&dp
.u
.prefix6
,
349 &peer
->su
.sin6
.sin6_addr
,
350 sizeof(struct in6_addr
)))
355 if (ifp
&& (ifp
== peer
->nexthop
.ifp
)) {
356 bgp_bfd_peer_status_update(peer
,
362 if ((sp
.family
== AF_INET
)
363 && (peer
->su_local
->sa
.sa_family
365 if (sp
.u
.prefix4
.s_addr
366 != peer
->su_local
->sin
369 } else if ((sp
.family
== AF_INET6
)
370 && (peer
->su_local
->sa
373 if (memcmp(&sp
.u
.prefix6
,
374 &peer
->su_local
->sin6
382 if ((vrf_id
!= VRF_DEFAULT
)
383 && (peer
->bgp
->vrf_id
!= vrf_id
))
386 bgp_bfd_peer_status_update(peer
,
396 * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
398 static int bgp_bfd_peer_param_set(struct peer
*peer
, uint32_t min_rx
,
399 uint32_t min_tx
, uint8_t detect_mult
,
402 struct peer_group
*group
;
403 struct listnode
*node
, *nnode
;
406 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
), min_rx
, min_tx
,
407 detect_mult
, defaults
, &command
);
409 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
)) {
411 for (ALL_LIST_ELEMENTS(group
->peer
, node
, nnode
, peer
)) {
413 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
),
414 min_rx
, min_tx
, detect_mult
, defaults
,
417 if ((peer
->status
== Established
)
418 && (command
== ZEBRA_BFD_DEST_REGISTER
))
419 bgp_bfd_register_peer(peer
);
420 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
421 bgp_bfd_update_peer(peer
);
424 if ((peer
->status
== Established
)
425 && (command
== ZEBRA_BFD_DEST_REGISTER
))
426 bgp_bfd_register_peer(peer
);
427 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
428 bgp_bfd_update_peer(peer
);
434 * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for
437 static int bgp_bfd_peer_param_unset(struct peer
*peer
)
439 struct peer_group
*group
;
440 struct listnode
*node
, *nnode
;
445 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
)) {
446 bfd_info_free(&(peer
->bfd_info
));
448 for (ALL_LIST_ELEMENTS(group
->peer
, node
, nnode
, peer
)) {
449 bgp_bfd_deregister_peer(peer
);
450 bfd_info_free(&(peer
->bfd_info
));
453 bgp_bfd_deregister_peer(peer
);
454 bfd_info_free(&(peer
->bfd_info
));
460 * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or
463 static int bgp_bfd_peer_param_type_set(struct peer
*peer
,
464 enum bfd_sess_type type
)
466 struct peer_group
*group
;
467 struct listnode
*node
, *nnode
;
469 struct bfd_info
*bfd_info
;
472 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
),
473 BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
474 BFD_DEF_DETECT_MULT
, 1, &command
);
476 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
477 bfd_info
->type
= type
;
479 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
)) {
481 for (ALL_LIST_ELEMENTS(group
->peer
, node
, nnode
, peer
)) {
485 (struct bfd_info
**)&(peer
->bfd_info
),
486 BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
487 BFD_DEF_DETECT_MULT
, 1, &command
);
489 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
490 bfd_info
->type
= type
;
492 if (peer
->status
== Established
) {
493 if (command
== ZEBRA_BFD_DEST_REGISTER
)
494 bgp_bfd_register_peer(peer
);
496 bgp_bfd_update_type(peer
);
500 if (peer
->status
== Established
) {
501 if (command
== ZEBRA_BFD_DEST_REGISTER
)
502 bgp_bfd_register_peer(peer
);
504 bgp_bfd_update_type(peer
);
512 * bgp_bfd_peer_config_write - Write the peer BFD configuration.
514 void bgp_bfd_peer_config_write(struct vty
*vty
, struct peer
*peer
, char *addr
)
516 struct bfd_info
*bfd_info
;
521 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
523 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_PARAM_CFG
))
525 vty_out(vty
, " neighbor %s bfd\n", addr
);
527 vty_out(vty
, " neighbor %s bfd %d %d %d\n", addr
,
528 bfd_info
->detect_mult
, bfd_info
->required_min_rx
,
529 bfd_info
->desired_min_tx
);
530 #endif /* HAVE_BFDD */
532 if (bfd_info
->type
!= BFD_TYPE_NOT_CONFIGURED
)
533 vty_out(vty
, " neighbor %s bfd %s\n", addr
,
534 (bfd_info
->type
== BFD_TYPE_MULTIHOP
) ? "multihop"
537 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_PARAM_CFG
)
538 && (bfd_info
->type
== BFD_TYPE_NOT_CONFIGURED
))
539 vty_out(vty
, " neighbor %s bfd\n", addr
);
543 * bgp_bfd_show_info - Show the peer BFD information.
545 void bgp_bfd_show_info(struct vty
*vty
, struct peer
*peer
, bool use_json
,
546 json_object
*json_neigh
)
548 bfd_show_info(vty
, (struct bfd_info
*)peer
->bfd_info
,
549 bgp_bfd_is_peer_multihop(peer
), 0, use_json
, json_neigh
);
554 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
557 "Enables BFD support\n")
563 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
565 return CMD_WARNING_CONFIG_FAILED
;
567 ret
= bgp_bfd_peer_param_set(peer
, BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
568 BFD_DEF_DETECT_MULT
, 1);
570 return bgp_vty_return(vty
, ret
);
579 #endif /* HAVE_BFDD */
581 neighbor_bfd_param_cmd
,
582 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd (2-255) (50-60000) (50-60000)",
585 "Enables BFD support\n"
586 "Detect Multiplier\n"
587 "Required min receive interval\n"
588 "Desired min transmit interval\n")
591 int idx_number_1
= 3;
592 int idx_number_2
= 4;
593 int idx_number_3
= 5;
600 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
602 return CMD_WARNING_CONFIG_FAILED
;
604 if ((ret
= bfd_validate_param(
605 vty
, argv
[idx_number_1
]->arg
, argv
[idx_number_2
]->arg
,
606 argv
[idx_number_3
]->arg
, &dm_val
, &rx_val
, &tx_val
))
610 ret
= bgp_bfd_peer_param_set(peer
, rx_val
, tx_val
, dm_val
, 0);
612 return bgp_vty_return(vty
, ret
);
617 DEFUN_HIDDEN (neighbor_bfd_type
,
618 neighbor_bfd_type_cmd
,
619 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
622 "Enables BFD support\n"
624 "Single hop session\n")
629 enum bfd_sess_type type
;
632 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
634 return CMD_WARNING_CONFIG_FAILED
;
636 if (strmatch(argv
[idx_hop
]->text
, "singlehop"))
637 type
= BFD_TYPE_SINGLEHOP
;
638 else if (strmatch(argv
[idx_hop
]->text
, "multihop"))
639 type
= BFD_TYPE_MULTIHOP
;
641 return CMD_WARNING_CONFIG_FAILED
;
643 ret
= bgp_bfd_peer_param_type_set(peer
, type
);
645 return bgp_vty_return(vty
, ret
);
650 DEFUN (no_neighbor_bfd
,
653 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
655 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd [(2-255) (50-60000) (50-60000)]",
656 #endif /* HAVE_BFDD */
660 "Disables BFD support\n"
662 "Detect Multiplier\n"
663 "Required min receive interval\n"
664 "Desired min transmit interval\n"
665 #endif /* !HAVE_BFDD */
672 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
674 return CMD_WARNING_CONFIG_FAILED
;
676 ret
= bgp_bfd_peer_param_unset(peer
);
678 return bgp_vty_return(vty
, ret
);
684 DEFUN_HIDDEN (no_neighbor_bfd_type
,
685 no_neighbor_bfd_type_cmd
,
686 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
690 "Disables BFD support\n"
692 "Singlehop session\n")
698 peer
= peer_and_group_lookup_vty(vty
, argv
[idx_peer
]->arg
);
700 return CMD_WARNING_CONFIG_FAILED
;
705 ret
= bgp_bfd_peer_param_type_set(peer
, BFD_TYPE_NOT_CONFIGURED
);
707 return bgp_vty_return(vty
, ret
);
712 void bgp_bfd_init(void)
716 /* Initialize BFD client functions */
717 zclient
->interface_bfd_dest_update
= bgp_bfd_dest_update
;
718 zclient
->bfd_dest_replay
= bgp_bfd_dest_replay
;
720 /* "neighbor bfd" commands. */
721 install_element(BGP_NODE
, &neighbor_bfd_cmd
);
722 install_element(BGP_NODE
, &neighbor_bfd_param_cmd
);
723 install_element(BGP_NODE
, &neighbor_bfd_type_cmd
);
724 install_element(BGP_NODE
, &no_neighbor_bfd_cmd
);
725 install_element(BGP_NODE
, &no_neighbor_bfd_type_cmd
);