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 template
50 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 hop.
75 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
97 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 multihop
= CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
111 UNSET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
115 multihop
= bgp_bfd_is_peer_multihop(peer
);
116 if ((command
== ZEBRA_BFD_DEST_REGISTER
) && multihop
)
117 SET_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
);
120 if (peer
->su
.sa
.sa_family
== AF_INET
)
121 bfd_peer_sendmsg (zclient
, bfd_info
, AF_INET
,
122 &peer
->su
.sin
.sin_addr
,
123 (peer
->su_local
) ? &peer
->su_local
->sin
.sin_addr
: NULL
,
124 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
125 peer
->ttl
, multihop
, command
, 1, vrf_id
);
126 else if (peer
->su
.sa
.sa_family
== AF_INET6
)
127 bfd_peer_sendmsg (zclient
, bfd_info
, AF_INET6
,
128 &peer
->su
.sin6
.sin6_addr
,
129 (peer
->su_local
) ? &peer
->su_local
->sin6
.sin6_addr
: NULL
,
130 (peer
->nexthop
.ifp
) ? peer
->nexthop
.ifp
->name
: NULL
,
131 peer
->ttl
, multihop
, command
, 1, vrf_id
);
135 * bgp_bfd_register_peer - register a peer with BFD through zebra
136 * for monitoring the peer rechahability.
139 bgp_bfd_register_peer (struct peer
*peer
)
141 struct bfd_info
*bfd_info
;
145 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
147 /* Check if BFD is enabled and peer has already been registered with BFD */
148 if (CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
151 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
155 * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
156 * for stopping the monitoring of the peer
160 bgp_bfd_deregister_peer (struct peer
*peer
)
162 struct bfd_info
*bfd_info
;
166 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
168 /* Check if BFD is eanbled and peer has not been registered */
169 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
172 bfd_info
->status
= BFD_STATUS_DOWN
;
173 bfd_info
->last_update
= bgp_clock();
175 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
179 * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
183 bgp_bfd_update_peer (struct peer
*peer
)
185 struct bfd_info
*bfd_info
;
189 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
191 /* Check if the peer has been registered with BFD*/
192 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
195 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_UPDATE
);
199 * bgp_bfd_update_type - update session type with BFD through zebra.
202 bgp_bfd_update_type (struct peer
*peer
)
204 struct bfd_info
*bfd_info
;
209 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
211 /* Check if the peer has been registered with BFD*/
212 if (!CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_REG
))
215 if (bfd_info
->type
== BFD_TYPE_NOT_CONFIGURED
)
217 multihop
= bgp_bfd_is_peer_multihop(peer
);
218 if ((multihop
&& !CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)) ||
219 (!multihop
&& CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)))
221 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
222 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
227 if ((bfd_info
->type
== BFD_TYPE_MULTIHOP
&&
228 !CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)) ||
229 (bfd_info
->type
== BFD_TYPE_SINGLEHOP
&&
230 CHECK_FLAG(bfd_info
->flags
, BFD_FLAG_BFD_TYPE_MULTIHOP
)))
232 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_DEREGISTER
);
233 bgp_bfd_peer_sendmsg(peer
, ZEBRA_BFD_DEST_REGISTER
);
239 * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
243 bgp_bfd_dest_replay (int command
, struct zclient
*client
, zebra_size_t length
,
246 struct listnode
*mnode
, *node
, *nnode
;
250 if (BGP_DEBUG (zebra
, ZEBRA
))
251 zlog_debug("Zebra: BFD Dest replay request");
253 /* Send the client registration */
254 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
256 /* Replay the peer, if BFD is enabled in BGP */
258 for (ALL_LIST_ELEMENTS_RO (bm
->bgp
, mnode
, bgp
))
259 for (ALL_LIST_ELEMENTS (bgp
->peer
, node
, nnode
, peer
))
261 bgp_bfd_update_peer(peer
);
268 * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
269 * down the peer if the BFD session went down from * up.
272 bgp_bfd_peer_status_update (struct peer
*peer
, int status
)
274 struct bfd_info
*bfd_info
;
277 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
279 if (bfd_info
->status
== status
)
282 old_status
= bfd_info
->status
;
283 bfd_info
->status
= status
;
284 bfd_info
->last_update
= bgp_clock();
286 if ((status
== BFD_STATUS_DOWN
) && (old_status
== BFD_STATUS_UP
))
288 peer
->last_reset
= PEER_DOWN_BFD_DOWN
;
289 BGP_EVENT_ADD (peer
, BGP_Stop
);
294 * bgp_bfd_dest_update - Find the peer for which the BFD status
295 * has changed and bring down the peer
296 * connectivity if the BFD session went down.
299 bgp_bfd_dest_update (int command
, struct zclient
*zclient
,
300 zebra_size_t length
, vrf_id_t vrf_id
)
302 struct interface
*ifp
;
307 ifp
= bfd_get_peer_info (zclient
->ibuf
, &dp
, &sp
, &status
, vrf_id
);
309 if (BGP_DEBUG (zebra
, ZEBRA
))
311 char buf
[2][PREFIX2STR_BUFFER
];
312 prefix2str(&dp
, buf
[0], sizeof(buf
[0]));
315 zlog_debug("Zebra: vrf %d interface %s bfd destination %s %s",
316 vrf_id
, ifp
->name
, buf
[0], bfd_get_status_str(status
));
320 prefix2str(&sp
, buf
[1], sizeof(buf
[1]));
321 zlog_debug("Zebra: vrf %d source %s bfd destination %s %s",
322 vrf_id
, buf
[1], buf
[0], bfd_get_status_str(status
));
326 /* Bring the peer down if BFD is enabled in BGP */
328 struct listnode
*mnode
, *node
, *nnode
;
332 for (ALL_LIST_ELEMENTS_RO (bm
->bgp
, mnode
, bgp
))
333 for (ALL_LIST_ELEMENTS (bgp
->peer
, node
, nnode
, peer
))
338 if ((dp
.family
== AF_INET
) && (peer
->su
.sa
.sa_family
== AF_INET
))
340 if (dp
.u
.prefix4
.s_addr
!= peer
->su
.sin
.sin_addr
.s_addr
)
343 else if ((dp
.family
== AF_INET6
) &&
344 (peer
->su
.sa
.sa_family
== AF_INET6
))
346 if (memcmp(&dp
.u
.prefix6
, &peer
->su
.sin6
.sin6_addr
,
347 sizeof (struct in6_addr
)))
353 if (ifp
&& (ifp
== peer
->nexthop
.ifp
))
355 bgp_bfd_peer_status_update(peer
, status
);
362 if ((sp
.family
== AF_INET
) &&
363 (peer
->su_local
->sa
.sa_family
== AF_INET
))
365 if (sp
.u
.prefix4
.s_addr
!= peer
->su_local
->sin
.sin_addr
.s_addr
)
368 else if ((sp
.family
== AF_INET6
) &&
369 (peer
->su_local
->sa
.sa_family
== AF_INET6
))
371 if (memcmp(&sp
.u
.prefix6
, &peer
->su_local
->sin6
.sin6_addr
,
372 sizeof (struct in6_addr
)))
378 if ((vrf_id
!= VRF_DEFAULT
) && (peer
->bgp
->vrf_id
!= vrf_id
))
381 bgp_bfd_peer_status_update(peer
, status
);
390 * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
393 bgp_bfd_peer_param_set (struct peer
*peer
, u_int32_t min_rx
, u_int32_t min_tx
,
394 u_int8_t detect_mult
, int defaults
)
396 struct peer_group
*group
;
397 struct listnode
*node
, *nnode
;
400 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
), min_rx
, min_tx
,
401 detect_mult
, defaults
, &command
);
403 if (CHECK_FLAG (peer
->sflags
, PEER_STATUS_GROUP
))
406 for (ALL_LIST_ELEMENTS (group
->peer
, node
, nnode
, peer
))
409 bfd_set_param((struct bfd_info
**)&(peer
->bfd_info
), min_rx
, min_tx
,
410 detect_mult
, defaults
, &command
);
412 if ((peer
->status
== Established
) &&
413 (command
== ZEBRA_BFD_DEST_REGISTER
))
414 bgp_bfd_register_peer(peer
);
415 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
416 bgp_bfd_update_peer(peer
);
421 if ((peer
->status
== Established
) &&
422 (command
== ZEBRA_BFD_DEST_REGISTER
))
423 bgp_bfd_register_peer(peer
);
424 else if (command
== ZEBRA_BFD_DEST_UPDATE
)
425 bgp_bfd_update_peer(peer
);
431 * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for peer.
434 bgp_bfd_peer_param_unset (struct peer
*peer
)
436 struct peer_group
*group
;
437 struct listnode
*node
, *nnode
;
442 if (CHECK_FLAG (peer
->sflags
, PEER_STATUS_GROUP
))
444 bfd_info_free(&(peer
->bfd_info
));
446 for (ALL_LIST_ELEMENTS (group
->peer
, node
, nnode
, peer
))
448 bgp_bfd_deregister_peer(peer
);
449 bfd_info_free(&(peer
->bfd_info
));
454 bgp_bfd_deregister_peer(peer
);
455 bfd_info_free(&(peer
->bfd_info
));
461 * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or singlehop)
464 bgp_bfd_peer_param_type_set (struct peer
*peer
, 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
), BFD_DEF_MIN_RX
,
473 BFD_DEF_MIN_TX
, BFD_DEF_DETECT_MULT
, 1, &command
);
475 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
476 bfd_info
->type
= type
;
478 if (CHECK_FLAG (peer
->sflags
, PEER_STATUS_GROUP
))
481 for (ALL_LIST_ELEMENTS (group
->peer
, node
, nnode
, peer
))
485 bfd_set_param((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
)
494 if (command
== ZEBRA_BFD_DEST_REGISTER
)
495 bgp_bfd_register_peer(peer
);
497 bgp_bfd_update_type(peer
);
503 if (peer
->status
== Established
)
505 if (command
== ZEBRA_BFD_DEST_REGISTER
)
506 bgp_bfd_register_peer(peer
);
508 bgp_bfd_update_type(peer
);
516 * bgp_bfd_peer_config_write - Write the peer BFD configuration.
519 bgp_bfd_peer_config_write(struct vty
*vty
, struct peer
*peer
, char *addr
)
521 struct bfd_info
*bfd_info
;
526 bfd_info
= (struct bfd_info
*)peer
->bfd_info
;
528 if (CHECK_FLAG (bfd_info
->flags
, BFD_FLAG_PARAM_CFG
))
529 vty_out (vty
, " neighbor %s bfd %d %d %d\n", addr
,
530 bfd_info
->detect_mult
, bfd_info
->required_min_rx
,
531 bfd_info
->desired_min_tx
);
533 if (bfd_info
->type
!= BFD_TYPE_NOT_CONFIGURED
)
534 vty_out (vty
, " neighbor %s bfd %s\n", addr
,
535 (bfd_info
->type
== BFD_TYPE_MULTIHOP
) ? "multihop" : "singlehop");
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.
546 bgp_bfd_show_info(struct vty
*vty
, struct peer
*peer
, u_char use_json
, 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
);
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
);
576 DEFUN (neighbor_bfd_param
,
577 neighbor_bfd_param_cmd
,
578 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd (2-255) (50-60000) (50-60000)",
581 "Enables BFD support\n"
582 "Detect Multiplier\n"
583 "Required min receive interval\n"
584 "Desired min transmit interval\n")
587 int idx_number_1
= 3;
588 int idx_number_2
= 4;
589 int idx_number_3
= 5;
596 peer
= peer_and_group_lookup_vty (vty
, argv
[idx_peer
]->arg
);
600 if ((ret
= bfd_validate_param (vty
, argv
[idx_number_1
]->arg
, argv
[idx_number_2
]->arg
, argv
[idx_number_3
]->arg
, &dm_val
,
601 &rx_val
, &tx_val
)) != CMD_SUCCESS
)
604 ret
= bgp_bfd_peer_param_set (peer
, rx_val
, tx_val
, dm_val
, 0);
606 return bgp_vty_return (vty
, ret
);
612 DEFUN_HIDDEN (neighbor_bfd_type
,
613 neighbor_bfd_type_cmd
,
614 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
617 "Enables BFD support\n"
619 "Single hop session\n")
624 enum bfd_sess_type type
;
627 peer
= peer_and_group_lookup_vty (vty
, argv
[idx_peer
]->arg
);
631 if (strmatch(argv
[idx_hop
]->text
, "singlehop"))
632 type
= BFD_TYPE_SINGLEHOP
;
633 else if (strmatch(argv
[idx_hop
]->text
, "multihop"))
634 type
= BFD_TYPE_MULTIHOP
;
638 ret
= bgp_bfd_peer_param_type_set (peer
, type
);
640 return bgp_vty_return (vty
, ret
);
645 DEFUN (no_neighbor_bfd
,
647 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd [(2-255) (50-60000) (50-60000)]",
651 "Disables BFD support\n"
652 "Detect Multiplier\n"
653 "Required min receive interval\n"
654 "Desired min transmit interval\n")
660 peer
= peer_and_group_lookup_vty (vty
, argv
[idx_peer
]->arg
);
664 ret
= bgp_bfd_peer_param_unset(peer
);
666 return bgp_vty_return (vty
, ret
);
672 DEFUN_HIDDEN (no_neighbor_bfd_type
,
673 no_neighbor_bfd_type_cmd
,
674 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
678 "Disables BFD support\n"
680 "Singlehop session\n")
686 peer
= peer_and_group_lookup_vty (vty
, argv
[idx_peer
]->arg
);
693 ret
= bgp_bfd_peer_param_type_set(peer
, BFD_TYPE_NOT_CONFIGURED
);
695 return bgp_vty_return (vty
, ret
);
705 /* Initialize BFD client functions */
706 zclient
->interface_bfd_dest_update
= bgp_bfd_dest_update
;
707 zclient
->bfd_dest_replay
= bgp_bfd_dest_replay
;
709 /* "neighbor bfd" commands. */
710 install_element (BGP_NODE
, &neighbor_bfd_cmd
);
711 install_element (BGP_NODE
, &neighbor_bfd_param_cmd
);
712 install_element (BGP_NODE
, &neighbor_bfd_type_cmd
);
713 install_element (BGP_NODE
, &no_neighbor_bfd_cmd
);
714 install_element (BGP_NODE
, &no_neighbor_bfd_type_cmd
);