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
39 #include "bgpd/bgpd.h"
41 #include "bgpd/bgp_bfd.h"
42 #include "bgpd/bgp_debug.h"
43 #include "bgpd/bgp_vty.h"
45 extern struct zclient
*zclient
;
48 * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group template
52 bgp_bfd_peer_group2peer_copy(struct peer
*conf
, struct peer
*peer
)
54 struct bfd_info
*bfd_info
;
55 struct bfd_info
*conf_bfd_info
;
60 conf_bfd_info
= (struct bfd_info
*)conf
->bfd_info
;
62 peer
->bfd_info
= bfd_info_create();
64 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
66 /* Copy BFD parameter values */
67 bfd_info
->required_min_rx
= conf_bfd_info
->required_min_rx
;
68 bfd_info
->desired_min_tx
= conf_bfd_info
->desired_min_tx
;
69 bfd_info
->detect_mult
= conf_bfd_info
->detect_mult
;
70 bfd_info
->type
= conf_bfd_info
->type
;
74 * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single hop.
77 bgp_bfd_is_peer_multihop(struct peer
*peer
)
79 struct bfd_info
*bfd_info
;
81 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
86 if((bfd_info
->type
== BFD_TYPE_MULTIHOP
) ||
87 ((peer
->sort
== BGP_PEER_IBGP
) && !peer
->shared_network
) ||
88 is_ebgp_multihop_configured(peer
))
95 * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister
96 * command to Zebra to be forwarded to BFD
99 bgp_bfd_peer_sendmsg (struct peer
*peer
, int command
)
101 struct bfd_info
*bfd_info
;
102 vrf_id_t vrf_id
= VRF_DEFAULT
;
105 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
107 if (peer
->bgp
&& (peer
->bgp
->inst_type
== BGP_INSTANCE_TYPE_VRF
))
108 vrf_id
= peer
->bgp
->vrf_id
;
110 if (command
== ZEBRA_BFD_DEST_DEREGISTER
)
112 multihop
= CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
113 UNSET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
117 multihop
= bgp_bfd_is_peer_multihop(peer
);
118 if ((command
== ZEBRA_BFD_DEST_REGISTER
) && multihop
)
119 SET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
122 if (peer
->su
.sa
.sa_family
== AF_INET
)
123 bfd_peer_sendmsg (zclient
, bfd_info
, AF_INET
,
124 &peer
->su
.sin
.sin_addr
,
125 (peer
->su_local
) ? &peer
->su_local
->sin
.sin_addr
: NULL
,
126 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
127 peer
->ttl
, multihop
, command
, 1, vrf_id
);
128 else if (peer
->su
.sa
.sa_family
== AF_INET6
)
129 bfd_peer_sendmsg (zclient
, bfd_info
, AF_INET6
,
130 &peer
->su
.sin6
.sin6_addr
,
131 (peer
->su_local
) ? &peer
->su_local
->sin6
.sin6_addr
: NULL
,
132 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
133 peer
->ttl
, multihop
, command
, 1, vrf_id
);
137 * bgp_bfd_register_peer - register a peer with BFD through zebra
138 * for monitoring the peer rechahability.
141 bgp_bfd_register_peer (struct peer
*peer
)
143 struct bfd_info
*bfd_info
;
147 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
149 /* Check if BFD is enabled and peer has already been registered with BFD */
150 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
153 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
157 * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
158 * for stopping the monitoring of the peer
162 bgp_bfd_deregister_peer (struct peer
*peer
)
164 struct bfd_info
*bfd_info
;
168 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
170 /* Check if BFD is eanbled and peer has not been registered */
171 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
174 bfd_info
->status
= BFD_STATUS_DOWN
;
175 bfd_info
->last_update
= bgp_clock();
177 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
181 * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
185 bgp_bfd_update_peer (struct peer
*peer
)
187 struct bfd_info
*bfd_info
;
191 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
193 /* Check if the peer has been registered with BFD*/
194 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
197 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_UPDATE
);
201 * bgp_bfd_update_type - update session type with BFD through zebra.
204 bgp_bfd_update_type (struct peer
*peer
)
206 struct bfd_info
*bfd_info
;
211 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
213 /* Check if the peer has been registered with BFD*/
214 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
217 if (bfd_info
->type
== BFD_TYPE_NOT_CONFIGURED
)
219 multihop
= bgp_bfd_is_peer_multihop(peer
);
220 if ((multihop
&& !CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)) ||
221 (!multihop
&& CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)))
223 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
224 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
229 if ((bfd_info
->type
== BFD_TYPE_MULTIHOP
&&
230 !CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)) ||
231 (bfd_info
->type
== BFD_TYPE_SINGLEHOP
&&
232 CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)))
234 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
235 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
241 * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
245 bgp_bfd_dest_replay (int command
, struct zclient
*client
, zebra_size_t length
,
248 struct listnode
*mnode
, *node
, *nnode
;
252 if (BGP_DEBUG (zebra
, ZEBRA
))
253 zlog_debug("Zebra: BFD Dest replay request");
255 /* Send the client registration */
256 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
258 /* Replay the peer, if BFD is enabled in BGP */
260 for (ALL_LIST_ELEMENTS_RO (bm
->bgp
, mnode
, bgp
))
261 for (ALL_LIST_ELEMENTS (bgp
->peer
, node
, nnode
, peer
))
263 bgp_bfd_update_peer(peer
);
270 * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
271 * down the peer if the BFD session went down from * up.
274 bgp_bfd_peer_status_update (struct peer
*peer
, int status
)
276 struct bfd_info
*bfd_info
;
279 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
281 if (bfd_info
->status
== status
)
284 old_status
= bfd_info
->status
;
285 bfd_info
->status
= status
;
286 bfd_info
->last_update
= bgp_clock();
288 if ((status
== BFD_STATUS_DOWN
) && (old_status
== BFD_STATUS_UP
))
290 peer
->last_reset
= PEER_DOWN_BFD_DOWN
;
291 BGP_EVENT_ADD (peer
, BGP_Stop
);
296 * bgp_bfd_dest_update - Find the peer for which the BFD status
297 * has changed and bring down the peer
298 * connectivity if the BFD session went down.
301 bgp_bfd_dest_update (int command
, struct zclient
*zclient
,
302 zebra_size_t length
, vrf_id_t vrf_id
)
304 struct interface
*ifp
;
309 ifp
= bfd_get_peer_info (zclient
->ibuf
, &dp
, &sp
, &status
, vrf_id
);
311 if (BGP_DEBUG (zebra
, ZEBRA
))
313 char buf
[2][PREFIX2STR_BUFFER
];
314 prefix2str(&dp
, buf
[0], sizeof(buf
[0]));
317 zlog_debug("Zebra: vrf %d interface %s bfd destination %s %s",
318 vrf_id
, ifp
->name
, buf
[0], bfd_get_status_str(status
));
322 prefix2str(&sp
, buf
[1], sizeof(buf
[1]));
323 zlog_debug("Zebra: vrf %d source %s bfd destination %s %s",
324 vrf_id
, buf
[1], buf
[0], bfd_get_status_str(status
));
328 /* Bring the peer down if BFD is enabled in BGP */
330 struct listnode
*mnode
, *node
, *nnode
;
334 for (ALL_LIST_ELEMENTS_RO (bm
->bgp
, mnode
, bgp
))
335 for (ALL_LIST_ELEMENTS (bgp
->peer
, node
, nnode
, peer
))
340 if ((dp
.family
== AF_INET
) && (peer
->su
.sa
.sa_family
== AF_INET
))
342 if (dp
.u
.prefix4
.s_addr
!= peer
->su
.sin
.sin_addr
.s_addr
)
346 else if ((dp
.family
== AF_INET6
) &&
347 (peer
->su
.sa
.sa_family
== AF_INET6
))
349 if (memcmp(&dp
.u
.prefix6
, &peer
->su
.sin6
.sin6_addr
,
350 sizeof (struct in6_addr
)))
357 if (ifp
&& (ifp
== peer
->nexthop
.ifp
))
359 bgp_bfd_peer_status_update(peer
, status
);
366 if ((sp
.family
== AF_INET
) &&
367 (peer
->su_local
->sa
.sa_family
== AF_INET
))
369 if (sp
.u
.prefix4
.s_addr
!= peer
->su_local
->sin
.sin_addr
.s_addr
)
373 else if ((sp
.family
== AF_INET6
) &&
374 (peer
->su_local
->sa
.sa_family
== AF_INET6
))
376 if (memcmp(&sp
.u
.prefix6
, &peer
->su_local
->sin6
.sin6_addr
,
377 sizeof (struct in6_addr
)))
384 if ((vrf_id
!= VRF_DEFAULT
) && (peer
->bgp
->vrf_id
!= vrf_id
))
387 bgp_bfd_peer_status_update(peer
, status
);
396 * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
399 bgp_bfd_peer_param_set (struct peer
*peer
, u_int32_t min_rx
, u_int32_t min_tx
,
400 u_int8_t detect_mult
, int defaults
)
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
))
412 for (ALL_LIST_ELEMENTS (group
->peer
, node
, nnode
, peer
))
415 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
), min_rx
, min_tx
,
416 detect_mult
, defaults
, &command
);
418 if ((peer
->status
== Established
) &&
419 (command
== ZEBRA_BFD_DEST_REGISTER
))
420 bgp_bfd_register_peer(peer
);
421 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
422 bgp_bfd_update_peer(peer
);
427 if ((peer
->status
== Established
) &&
428 (command
== ZEBRA_BFD_DEST_REGISTER
))
429 bgp_bfd_register_peer(peer
);
430 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
431 bgp_bfd_update_peer(peer
);
437 * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for peer.
440 bgp_bfd_peer_param_unset (struct peer
*peer
)
442 struct peer_group
*group
;
443 struct listnode
*node
, *nnode
;
448 if (CHECK_FLAG (peer
->sflags
, PEER_STATUS_GROUP
))
450 bfd_info_free(&(peer
->bfd_info
));
452 for (ALL_LIST_ELEMENTS (group
->peer
, node
, nnode
, peer
))
454 bgp_bfd_deregister_peer(peer
);
455 bfd_info_free(&(peer
->bfd_info
));
460 bgp_bfd_deregister_peer(peer
);
461 bfd_info_free(&(peer
->bfd_info
));
467 * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or singlehop)
470 bgp_bfd_peer_param_type_set (struct peer
*peer
, enum bfd_sess_type type
)
472 struct peer_group
*group
;
473 struct listnode
*node
, *nnode
;
475 struct bfd_info
*bfd_info
;
478 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
), BFD_DEF_MIN_RX
,
479 BFD_DEF_MIN_TX
, BFD_DEF_DETECT_MULT
, 1, &command
);
481 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
482 bfd_info
->type
= type
;
484 if (CHECK_FLAG (peer
->sflags
, PEER_STATUS_GROUP
))
487 for (ALL_LIST_ELEMENTS (group
->peer
, node
, nnode
, peer
))
491 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
),
492 BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
493 BFD_DEF_DETECT_MULT
, 1, &command
);
495 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
496 bfd_info
->type
= type
;
498 if (peer
->status
== Established
)
500 if (command
== ZEBRA_BFD_DEST_REGISTER
)
501 bgp_bfd_register_peer(peer
);
503 bgp_bfd_update_type(peer
);
509 if (peer
->status
== Established
)
511 if (command
== ZEBRA_BFD_DEST_REGISTER
)
512 bgp_bfd_register_peer(peer
);
514 bgp_bfd_update_type(peer
);
522 * bgp_bfd_peer_config_write - Write the peer BFD configuration.
525 bgp_bfd_peer_config_write(struct vty
*vty
, struct peer
*peer
, char *addr
)
527 struct bfd_info
*bfd_info
;
532 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
534 if (CHECK_FLAG (bfd_info
->flags
, BFD_FLAG_PARAM_CFG
))
535 vty_out (vty
, " neighbor %s bfd %d %d %d%s", addr
,
536 bfd_info
->detect_mult
, bfd_info
->required_min_rx
,
537 bfd_info
->desired_min_tx
, VTY_NEWLINE
);
539 if (bfd_info
->type
!= BFD_TYPE_NOT_CONFIGURED
)
540 vty_out (vty
, " neighbor %s bfd %s%s", addr
,
541 (bfd_info
->type
== BFD_TYPE_MULTIHOP
) ? "multihop" : "singlehop",
544 if (!CHECK_FLAG (bfd_info
->flags
, BFD_FLAG_PARAM_CFG
) &&
545 (bfd_info
->type
== BFD_TYPE_NOT_CONFIGURED
))
546 vty_out (vty
, " neighbor %s bfd%s", addr
, VTY_NEWLINE
);
550 * bgp_bfd_show_info - Show the peer BFD information.
553 bgp_bfd_show_info(struct vty
*vty
, struct peer
*peer
, u_char use_json
, json_object
*json_neigh
)
555 bfd_show_info(vty
, (struct bfd_info
*)peer
->bfd_info
,
556 bgp_bfd_is_peer_multihop(peer
), 0, use_json
, json_neigh
);
564 "Enables BFD support\n")
569 peer
= peer_and_group_lookup_vty (vty
, argv
[0]);
573 ret
= bgp_bfd_peer_param_set (peer
, BFD_DEF_MIN_RX
, BFD_DEF_MIN_TX
,
574 BFD_DEF_DETECT_MULT
, 1);
576 return bgp_vty_return (vty
, ret
);
582 DEFUN (neighbor_bfd_param
,
583 neighbor_bfd_param_cmd
,
584 NEIGHBOR_CMD2
"bfd " BFD_CMD_DETECT_MULT_RANGE BFD_CMD_MIN_RX_RANGE BFD_CMD_MIN_TX_RANGE
,
587 "Enables BFD support\n"
588 "Detect Multiplier\n"
589 "Required min receive interval\n"
590 "Desired min transmit interval\n")
598 peer
= peer_and_group_lookup_vty (vty
, argv
[0]);
602 if ((ret
= bfd_validate_param (vty
, argv
[1], argv
[2], argv
[3], &dm_val
,
603 &rx_val
, &tx_val
)) != CMD_SUCCESS
)
606 ret
= bgp_bfd_peer_param_set (peer
, rx_val
, tx_val
, dm_val
, 0);
608 return bgp_vty_return (vty
, ret
);
614 DEFUN_HIDDEN (neighbor_bfd_type
,
615 neighbor_bfd_type_cmd
,
616 NEIGHBOR_CMD2
"bfd " BFD_CMD_TYPE
,
619 "Enables BFD support\n"
623 enum bfd_sess_type type
;
626 peer
= peer_and_group_lookup_vty (vty
, argv
[0]);
630 if (!strcmp(argv
[1], "singlehop"))
631 type
= BFD_TYPE_SINGLEHOP
;
632 else if (!strcmp(argv
[1], "multihop"))
633 type
= BFD_TYPE_MULTIHOP
;
637 ret
= bgp_bfd_peer_param_type_set (peer
, type
);
639 return bgp_vty_return (vty
, ret
);
644 DEFUN (no_neighbor_bfd
,
646 NO_NEIGHBOR_CMD2
"bfd",
650 "Disables BFD support\n")
655 peer
= peer_and_group_lookup_vty (vty
, argv
[0]);
659 ret
= bgp_bfd_peer_param_unset(peer
);
661 return bgp_vty_return (vty
, ret
);
666 ALIAS (no_neighbor_bfd
,
667 no_neighbor_bfd_val_cmd
,
668 NO_NEIGHBOR_CMD2
"bfd " BFD_CMD_DETECT_MULT_RANGE BFD_CMD_MIN_RX_RANGE BFD_CMD_MIN_TX_RANGE
,
672 "Disables BFD support\n"
673 "Detect Multiplier\n"
674 "Required min receive interval\n"
675 "Desired min transmit interval\n")
677 DEFUN_HIDDEN (no_neighbor_bfd_type
,
678 no_neighbor_bfd_type_cmd
,
679 NO_NEIGHBOR_CMD2
"bfd " BFD_CMD_TYPE
,
683 "Disables BFD support\n"
689 peer
= peer_and_group_lookup_vty (vty
, argv
[0]);
696 ret
= bgp_bfd_peer_param_type_set(peer
, BFD_TYPE_NOT_CONFIGURED
);
698 return bgp_vty_return (vty
, ret
);
708 /* Initialize BFD client functions */
709 zclient
->interface_bfd_dest_update
= bgp_bfd_dest_update
;
710 zclient
->bfd_dest_replay
= bgp_bfd_dest_replay
;
712 /* "neighbor bfd" commands. */
713 install_element (BGP_NODE
, &neighbor_bfd_cmd
);
714 install_element (BGP_NODE
, &neighbor_bfd_param_cmd
);
715 install_element (BGP_NODE
, &neighbor_bfd_type_cmd
);
716 install_element (BGP_NODE
, &no_neighbor_bfd_cmd
);
717 install_element (BGP_NODE
, &no_neighbor_bfd_val_cmd
);
718 install_element (BGP_NODE
, &no_neighbor_bfd_type_cmd
);