]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_bfd.c
Merge pull request #5972 from rubenk/eigrpd-remove-workaround-for-old-openbsd
[mirror_frr.git] / bgpd / bgp_bfd.c
CommitLineData
c43ed2e4
DS
1/**
2 * bgp_bfd.c: BGP BFD handling routines
3 *
4 * @copyright Copyright (C) 2015 Cumulus Networks, Inc.
5 *
6 * This file is part of GNU Zebra.
7 *
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
11 * later version.
12 *
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.
17 *
896014f4
DL
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
c43ed2e4
DS
21 */
22
23#include <zebra.h>
24
25#include "command.h"
26#include "linklist.h"
27#include "memory.h"
28#include "prefix.h"
29#include "thread.h"
30#include "buffer.h"
31#include "stream.h"
32#include "zclient.h"
7f342629 33#include "bfd.h"
856ca177 34#include "lib/json.h"
039f3a34
DS
35#include "filter.h"
36
c43ed2e4 37#include "bgpd/bgpd.h"
7f342629 38#include "bgp_fsm.h"
c43ed2e4
DS
39#include "bgpd/bgp_bfd.h"
40#include "bgpd/bgp_debug.h"
41#include "bgpd/bgp_vty.h"
42
43extern struct zclient *zclient;
44
c43ed2e4 45/*
d62a17ae 46 * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group
47 * template
c43ed2e4
DS
48 * to peer.
49 */
d62a17ae 50void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer)
c43ed2e4 51{
d62a17ae 52 struct bfd_info *bfd_info;
53 struct bfd_info *conf_bfd_info;
7f342629 54
d62a17ae 55 if (!conf->bfd_info)
56 return;
7f342629 57
d62a17ae 58 conf_bfd_info = (struct bfd_info *)conf->bfd_info;
59 if (!peer->bfd_info)
60 peer->bfd_info = bfd_info_create();
c43ed2e4 61
d62a17ae 62 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 63
d62a17ae 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;
c43ed2e4
DS
69}
70
71/*
d62a17ae 72 * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single
73 * hop.
c43ed2e4 74 */
d62a17ae 75int bgp_bfd_is_peer_multihop(struct peer *peer)
c43ed2e4 76{
d62a17ae 77 struct bfd_info *bfd_info;
986aa00f 78
d62a17ae 79 bfd_info = (struct bfd_info *)peer->bfd_info;
986aa00f 80
d62a17ae 81 if (!bfd_info)
82 return 0;
986aa00f 83
d62a17ae 84 if ((bfd_info->type == BFD_TYPE_MULTIHOP)
85 || ((peer->sort == BGP_PEER_IBGP) && !peer->shared_network)
86 || is_ebgp_multihop_configured(peer))
87 return 1;
88 else
89 return 0;
c43ed2e4
DS
90}
91
92/*
7f342629
DS
93 * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister
94 * command to Zebra to be forwarded to BFD
c43ed2e4 95 */
d62a17ae 96static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
c43ed2e4 97{
d62a17ae 98 struct bfd_info *bfd_info;
9beff0bd 99 int multihop, cbit = 0;
0945d5ed 100 vrf_id_t vrf_id;
d62a17ae 101
102 bfd_info = (struct bfd_info *)peer->bfd_info;
103
0945d5ed 104 vrf_id = peer->bgp->vrf_id;
d62a17ae 105
106 if (command == ZEBRA_BFD_DEST_DEREGISTER) {
107 multihop =
108 CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
109 UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
110 } else {
111 multihop = bgp_bfd_is_peer_multihop(peer);
112 if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop)
113 SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
114 }
dcffea69
PG
115 /* while graceful restart with fwd path preserved
116 * and bfd controlplane check not configured is not kept
9beff0bd
PG
117 * keep bfd independent controlplane bit set to 1
118 */
892fedb6
DA
119 if (!CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_RESTART)
120 && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)
dcffea69 121 && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
892fedb6 122 SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
9beff0bd
PG
123
124 cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
d62a17ae 125
126 if (peer->su.sa.sa_family == AF_INET)
127 bfd_peer_sendmsg(
128 zclient, bfd_info, AF_INET, &peer->su.sin.sin_addr,
129 (peer->su_local) ? &peer->su_local->sin.sin_addr : NULL,
130 (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL,
9beff0bd 131 peer->ttl, multihop, cbit, command, 1, vrf_id);
d62a17ae 132 else if (peer->su.sa.sa_family == AF_INET6)
133 bfd_peer_sendmsg(
134 zclient, bfd_info, AF_INET6, &peer->su.sin6.sin6_addr,
135 (peer->su_local) ? &peer->su_local->sin6.sin6_addr
136 : NULL,
137 (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL,
9beff0bd 138 peer->ttl, multihop, cbit, command, 1, vrf_id);
c43ed2e4
DS
139}
140
141/*
142 * bgp_bfd_register_peer - register a peer with BFD through zebra
143 * for monitoring the peer rechahability.
144 */
d62a17ae 145void bgp_bfd_register_peer(struct peer *peer)
c43ed2e4 146{
d62a17ae 147 struct bfd_info *bfd_info;
c43ed2e4 148
d62a17ae 149 if (!peer->bfd_info)
150 return;
151 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 152
d62a17ae 153 /* Check if BFD is enabled and peer has already been registered with BFD
154 */
155 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
156 return;
c43ed2e4 157
d62a17ae 158 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
c43ed2e4
DS
159}
160
161/**
162 * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
163 * for stopping the monitoring of the peer
164 * rechahability.
165 */
d62a17ae 166void bgp_bfd_deregister_peer(struct peer *peer)
c43ed2e4 167{
d62a17ae 168 struct bfd_info *bfd_info;
c43ed2e4 169
d62a17ae 170 if (!peer->bfd_info)
171 return;
172 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 173
d62a17ae 174 /* Check if BFD is eanbled and peer has not been registered */
175 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
176 return;
c43ed2e4 177
d62a17ae 178 bfd_info->status = BFD_STATUS_DOWN;
179 bfd_info->last_update = bgp_clock();
5c940836 180
d62a17ae 181 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
c43ed2e4
DS
182}
183
184/*
185 * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
186 * through zebra.
187 */
d62a17ae 188static void bgp_bfd_update_peer(struct peer *peer)
c43ed2e4 189{
d62a17ae 190 struct bfd_info *bfd_info;
c43ed2e4 191
d62a17ae 192 if (!peer->bfd_info)
193 return;
194 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 195
d62a17ae 196 /* Check if the peer has been registered with BFD*/
197 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
198 return;
c43ed2e4 199
d62a17ae 200 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE);
c43ed2e4
DS
201}
202
986aa00f 203/*
204 * bgp_bfd_update_type - update session type with BFD through zebra.
205 */
d62a17ae 206static void bgp_bfd_update_type(struct peer *peer)
986aa00f 207{
d62a17ae 208 struct bfd_info *bfd_info;
209 int multihop;
210
211 if (!peer->bfd_info)
212 return;
213 bfd_info = (struct bfd_info *)peer->bfd_info;
214
215 /* Check if the peer has been registered with BFD*/
216 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
217 return;
218
219 if (bfd_info->type == BFD_TYPE_NOT_CONFIGURED) {
220 multihop = bgp_bfd_is_peer_multihop(peer);
221 if ((multihop
222 && !CHECK_FLAG(bfd_info->flags,
223 BFD_FLAG_BFD_TYPE_MULTIHOP))
9d303b37
DL
224 || (!multihop && CHECK_FLAG(bfd_info->flags,
225 BFD_FLAG_BFD_TYPE_MULTIHOP))) {
d62a17ae 226 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
227 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
228 }
229 } else {
230 if ((bfd_info->type == BFD_TYPE_MULTIHOP
231 && !CHECK_FLAG(bfd_info->flags,
232 BFD_FLAG_BFD_TYPE_MULTIHOP))
233 || (bfd_info->type == BFD_TYPE_SINGLEHOP
234 && CHECK_FLAG(bfd_info->flags,
235 BFD_FLAG_BFD_TYPE_MULTIHOP))) {
236 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
237 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
238 }
239 }
986aa00f 240}
241
c43ed2e4
DS
242/*
243 * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
244 * to zebra
245 */
121f9dee 246static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS)
c43ed2e4 247{
d62a17ae 248 struct listnode *mnode, *node, *nnode;
249 struct bgp *bgp;
250 struct peer *peer;
c43ed2e4 251
d62a17ae 252 if (BGP_DEBUG(zebra, ZEBRA))
253 zlog_debug("Zebra: BFD Dest replay request");
c43ed2e4 254
d62a17ae 255 /* Send the client registration */
0945d5ed 256 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
055c4dfc 257
d62a17ae 258 /* Replay the peer, if BFD is enabled in BGP */
c43ed2e4 259
d62a17ae 260 for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
261 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
262 bgp_bfd_update_peer(peer);
263 }
c43ed2e4 264
d62a17ae 265 return 0;
c43ed2e4
DS
266}
267
268/*
68fe91d6 269 * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
d62a17ae 270 * down the peer if the BFD session went down from
271 * * up.
68fe91d6 272 */
9beff0bd
PG
273static void bgp_bfd_peer_status_update(struct peer *peer, int status,
274 int remote_cbit)
68fe91d6 275{
d62a17ae 276 struct bfd_info *bfd_info;
277 int old_status;
68fe91d6 278
d62a17ae 279 bfd_info = (struct bfd_info *)peer->bfd_info;
68fe91d6 280
d62a17ae 281 if (bfd_info->status == status)
282 return;
68fe91d6 283
d62a17ae 284 old_status = bfd_info->status;
7555dc61
S
285 BFD_SET_CLIENT_STATUS(bfd_info->status, status);
286
d62a17ae 287 bfd_info->last_update = bgp_clock();
68fe91d6 288
37bb7aca
PG
289 if (status != old_status) {
290 if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
291 zlog_debug("[%s]: BFD %s", peer->host,
292 bfd_get_status_str(status));
293 }
d62a17ae 294 if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) {
9beff0bd 295 if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) &&
dcffea69 296 CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE) &&
9beff0bd
PG
297 !remote_cbit) {
298 zlog_info("%s BFD DOWN message ignored in the process"
299 " of graceful restart when C bit is cleared",
300 peer->host);
301 return;
302 }
d62a17ae 303 peer->last_reset = PEER_DOWN_BFD_DOWN;
304 BGP_EVENT_ADD(peer, BGP_Stop);
305 }
51728519
PG
306 if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN)
307 && peer->status != Established) {
fc04a677
PG
308 if (!BGP_PEER_START_SUPPRESSED(peer)) {
309 bgp_fsm_event_update(peer, 1);
51728519 310 BGP_EVENT_ADD(peer, BGP_Start);
fc04a677 311 }
51728519 312 }
68fe91d6 313}
314
315/*
316 * bgp_bfd_dest_update - Find the peer for which the BFD status
317 * has changed and bring down the peer
318 * connectivity if the BFD session went down.
c43ed2e4 319 */
121f9dee 320static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS)
c43ed2e4 321{
d62a17ae 322 struct interface *ifp;
323 struct prefix dp;
324 struct prefix sp;
325 int status;
9beff0bd 326 int remote_cbit;
d62a17ae 327
9beff0bd
PG
328 ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status,
329 &remote_cbit, vrf_id);
d62a17ae 330
331 if (BGP_DEBUG(zebra, ZEBRA)) {
137147c6 332 struct vrf *vrf;
d62a17ae 333 char buf[2][PREFIX2STR_BUFFER];
137147c6
DS
334
335 vrf = vrf_lookup_by_id(vrf_id);
d62a17ae 336 prefix2str(&dp, buf[0], sizeof(buf[0]));
337 if (ifp) {
338 zlog_debug(
137147c6
DS
339 "Zebra: vrf %s(%u) interface %s bfd destination %s %s %s",
340 VRF_LOGNAME(vrf), vrf_id, ifp->name,
341 buf[0], bfd_get_status_str(status),
9beff0bd 342 remote_cbit ? "(cbit on)" : "");
d62a17ae 343 } else {
344 prefix2str(&sp, buf[1], sizeof(buf[1]));
345 zlog_debug(
137147c6
DS
346 "Zebra: vrf %s(%u) source %s bfd destination %s %s %s",
347 VRF_LOGNAME(vrf), vrf_id, buf[1], buf[0],
9beff0bd
PG
348 bfd_get_status_str(status),
349 remote_cbit ? "(cbit on)" : "");
d62a17ae 350 }
351 }
352
353 /* Bring the peer down if BFD is enabled in BGP */
354 {
355 struct listnode *mnode, *node, *nnode;
356 struct bgp *bgp;
357 struct peer *peer;
358
359 for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
360 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
361 if (!peer->bfd_info)
362 continue;
363
364 if ((dp.family == AF_INET)
365 && (peer->su.sa.sa_family == AF_INET)) {
366 if (dp.u.prefix4.s_addr
367 != peer->su.sin.sin_addr.s_addr)
368 continue;
369 } else if ((dp.family == AF_INET6)
370 && (peer->su.sa.sa_family
371 == AF_INET6)) {
372 if (memcmp(&dp.u.prefix6,
373 &peer->su.sin6.sin6_addr,
374 sizeof(struct in6_addr)))
375 continue;
376 } else
377 continue;
378
379 if (ifp && (ifp == peer->nexthop.ifp)) {
380 bgp_bfd_peer_status_update(peer,
9beff0bd
PG
381 status,
382 remote_cbit);
d62a17ae 383 } else {
384 if (!peer->su_local)
385 continue;
386
387 if ((sp.family == AF_INET)
388 && (peer->su_local->sa.sa_family
389 == AF_INET)) {
390 if (sp.u.prefix4.s_addr
391 != peer->su_local->sin
392 .sin_addr.s_addr)
393 continue;
394 } else if ((sp.family == AF_INET6)
395 && (peer->su_local->sa
396 .sa_family
397 == AF_INET6)) {
398 if (memcmp(&sp.u.prefix6,
399 &peer->su_local->sin6
400 .sin6_addr,
401 sizeof(struct
402 in6_addr)))
403 continue;
404 } else
405 continue;
406
407 if ((vrf_id != VRF_DEFAULT)
408 && (peer->bgp->vrf_id != vrf_id))
409 continue;
410
411 bgp_bfd_peer_status_update(peer,
9beff0bd
PG
412 status,
413 remote_cbit);
d62a17ae 414 }
415 }
416 }
417
418 return 0;
c43ed2e4
DS
419}
420
421/*
422 * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
423 */
d7c0a89a
QY
424static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx,
425 uint32_t min_tx, uint8_t detect_mult,
d62a17ae 426 int defaults)
c43ed2e4 427{
d62a17ae 428 struct peer_group *group;
429 struct listnode *node, *nnode;
430 int command = 0;
431
432 bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx,
433 detect_mult, defaults, &command);
434
435 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
436 group = peer->group;
437 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
438 command = 0;
439 bfd_set_param((struct bfd_info **)&(peer->bfd_info),
440 min_rx, min_tx, detect_mult, defaults,
441 &command);
442
443 if ((peer->status == Established)
444 && (command == ZEBRA_BFD_DEST_REGISTER))
445 bgp_bfd_register_peer(peer);
446 else if (command == ZEBRA_BFD_DEST_UPDATE)
447 bgp_bfd_update_peer(peer);
448 }
449 } else {
450 if ((peer->status == Established)
451 && (command == ZEBRA_BFD_DEST_REGISTER))
452 bgp_bfd_register_peer(peer);
453 else if (command == ZEBRA_BFD_DEST_UPDATE)
454 bgp_bfd_update_peer(peer);
455 }
456 return 0;
c43ed2e4
DS
457}
458
459/*
d62a17ae 460 * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for
461 * peer.
c43ed2e4 462 */
d62a17ae 463static int bgp_bfd_peer_param_unset(struct peer *peer)
c43ed2e4 464{
d62a17ae 465 struct peer_group *group;
466 struct listnode *node, *nnode;
467
468 if (!peer->bfd_info)
469 return 0;
470
471 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
472 bfd_info_free(&(peer->bfd_info));
473 group = peer->group;
474 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
475 bgp_bfd_deregister_peer(peer);
476 bfd_info_free(&(peer->bfd_info));
477 }
478 } else {
479 bgp_bfd_deregister_peer(peer);
480 bfd_info_free(&(peer->bfd_info));
481 }
482 return 0;
c43ed2e4
DS
483}
484
986aa00f 485/*
d62a17ae 486 * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or
487 * singlehop)
986aa00f 488 */
d62a17ae 489static int bgp_bfd_peer_param_type_set(struct peer *peer,
490 enum bfd_sess_type type)
986aa00f 491{
d62a17ae 492 struct peer_group *group;
493 struct listnode *node, *nnode;
494 int command = 0;
495 struct bfd_info *bfd_info;
496
497 if (!peer->bfd_info)
498 bfd_set_param((struct bfd_info **)&(peer->bfd_info),
499 BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
500 BFD_DEF_DETECT_MULT, 1, &command);
501
502 bfd_info = (struct bfd_info *)peer->bfd_info;
503 bfd_info->type = type;
504
505 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
506 group = peer->group;
507 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
508 command = 0;
509 if (!peer->bfd_info)
510 bfd_set_param(
511 (struct bfd_info **)&(peer->bfd_info),
512 BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
513 BFD_DEF_DETECT_MULT, 1, &command);
514
515 bfd_info = (struct bfd_info *)peer->bfd_info;
516 bfd_info->type = type;
517
518 if (peer->status == Established) {
519 if (command == ZEBRA_BFD_DEST_REGISTER)
520 bgp_bfd_register_peer(peer);
521 else
522 bgp_bfd_update_type(peer);
523 }
524 }
525 } else {
526 if (peer->status == Established) {
527 if (command == ZEBRA_BFD_DEST_REGISTER)
528 bgp_bfd_register_peer(peer);
529 else
530 bgp_bfd_update_type(peer);
531 }
532 }
533
534 return 0;
986aa00f 535}
536
c43ed2e4
DS
537/*
538 * bgp_bfd_peer_config_write - Write the peer BFD configuration.
539 */
d62a17ae 540void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
c43ed2e4 541{
d62a17ae 542 struct bfd_info *bfd_info;
c43ed2e4 543
d62a17ae 544 if (!peer->bfd_info)
545 return;
7f342629 546
d62a17ae 547 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 548
d62a17ae 549 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
a0841732
RZ
550#if HAVE_BFDD > 0
551 vty_out(vty, " neighbor %s bfd\n", addr);
552#else
d62a17ae 553 vty_out(vty, " neighbor %s bfd %d %d %d\n", addr,
554 bfd_info->detect_mult, bfd_info->required_min_rx,
555 bfd_info->desired_min_tx);
a0841732 556#endif /* HAVE_BFDD */
986aa00f 557
d62a17ae 558 if (bfd_info->type != BFD_TYPE_NOT_CONFIGURED)
559 vty_out(vty, " neighbor %s bfd %s\n", addr,
560 (bfd_info->type == BFD_TYPE_MULTIHOP) ? "multihop"
561 : "singlehop");
986aa00f 562
d62a17ae 563 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)
564 && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED))
565 vty_out(vty, " neighbor %s bfd\n", addr);
dcffea69
PG
566
567 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
568 vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", addr);
c43ed2e4
DS
569}
570
571/*
572 * bgp_bfd_show_info - Show the peer BFD information.
573 */
9f049418 574void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json,
d62a17ae 575 json_object *json_neigh)
c43ed2e4 576{
d62a17ae 577 bfd_show_info(vty, (struct bfd_info *)peer->bfd_info,
578 bgp_bfd_is_peer_multihop(peer), 0, use_json, json_neigh);
c43ed2e4
DS
579}
580
581DEFUN (neighbor_bfd,
582 neighbor_bfd_cmd,
9ccf14f7 583 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
c43ed2e4
DS
584 NEIGHBOR_STR
585 NEIGHBOR_ADDR_STR2
586 "Enables BFD support\n")
587{
d62a17ae 588 int idx_peer = 1;
589 struct peer *peer;
590 int ret;
c43ed2e4 591
d62a17ae 592 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
593 if (!peer)
594 return CMD_WARNING_CONFIG_FAILED;
c43ed2e4 595
d62a17ae 596 ret = bgp_bfd_peer_param_set(peer, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
597 BFD_DEF_DETECT_MULT, 1);
598 if (ret != 0)
599 return bgp_vty_return(vty, ret);
c43ed2e4 600
d62a17ae 601 return CMD_SUCCESS;
c43ed2e4
DS
602}
603
64dc4b2d
RZ
604#if HAVE_BFDD > 0
605DEFUN_HIDDEN(
606#else
607DEFUN(
608#endif /* HAVE_BFDD */
609 neighbor_bfd_param,
c43ed2e4 610 neighbor_bfd_param_cmd,
9ccf14f7 611 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd (2-255) (50-60000) (50-60000)",
c43ed2e4
DS
612 NEIGHBOR_STR
613 NEIGHBOR_ADDR_STR2
614 "Enables BFD support\n"
615 "Detect Multiplier\n"
616 "Required min receive interval\n"
617 "Desired min transmit interval\n")
618{
d62a17ae 619 int idx_peer = 1;
620 int idx_number_1 = 3;
621 int idx_number_2 = 4;
622 int idx_number_3 = 5;
623 struct peer *peer;
d7c0a89a
QY
624 uint32_t rx_val;
625 uint32_t tx_val;
626 uint8_t dm_val;
d62a17ae 627 int ret;
628
629 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
630 if (!peer)
631 return CMD_WARNING_CONFIG_FAILED;
632
633 if ((ret = bfd_validate_param(
634 vty, argv[idx_number_1]->arg, argv[idx_number_2]->arg,
635 argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
636 != CMD_SUCCESS)
637 return ret;
638
639 ret = bgp_bfd_peer_param_set(peer, rx_val, tx_val, dm_val, 0);
640 if (ret != 0)
641 return bgp_vty_return(vty, ret);
642
643 return CMD_SUCCESS;
c43ed2e4
DS
644}
645
986aa00f 646DEFUN_HIDDEN (neighbor_bfd_type,
647 neighbor_bfd_type_cmd,
e83a9414 648 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
986aa00f 649 NEIGHBOR_STR
650 NEIGHBOR_ADDR_STR2
651 "Enables BFD support\n"
d7fa34c1
QY
652 "Multihop session\n"
653 "Single hop session\n")
986aa00f 654{
d62a17ae 655 int idx_peer = 1;
656 int idx_hop = 3;
657 struct peer *peer;
658 enum bfd_sess_type type;
659 int ret;
660
661 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
662 if (!peer)
663 return CMD_WARNING_CONFIG_FAILED;
664
665 if (strmatch(argv[idx_hop]->text, "singlehop"))
666 type = BFD_TYPE_SINGLEHOP;
667 else if (strmatch(argv[idx_hop]->text, "multihop"))
668 type = BFD_TYPE_MULTIHOP;
669 else
670 return CMD_WARNING_CONFIG_FAILED;
671
672 ret = bgp_bfd_peer_param_type_set(peer, type);
673 if (ret != 0)
674 return bgp_vty_return(vty, ret);
675
676 return CMD_SUCCESS;
986aa00f 677}
678
dcffea69
PG
679static int bgp_bfd_set_check_controlplane_failure_peer(struct vty *vty, struct peer *peer,
680 const char *no)
681{
682 struct bfd_info *bfd_info;
683
684 if (!peer->bfd_info) {
685 if (no)
686 return CMD_SUCCESS;
687 vty_out(vty, "%% Specify bfd command first\n");
688 return CMD_WARNING_CONFIG_FAILED;
689 }
690 bfd_info = (struct bfd_info *)peer->bfd_info;
691 if (!no) {
692 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
693 SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
694 bgp_bfd_update_peer(peer);
695 }
696 } else {
697 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
698 UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
699 bgp_bfd_update_peer(peer);
700 }
701 }
702 return CMD_SUCCESS;
703}
704
705
706DEFUN (neighbor_bfd_check_controlplane_failure,
707 neighbor_bfd_check_controlplane_failure_cmd,
708 "[no] neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure",
709 NO_STR
710 NEIGHBOR_STR
711 NEIGHBOR_ADDR_STR2
712 "BFD support\n"
713 "Link dataplane status with BGP controlplane\n")
714{
715 const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL;
716 int idx_peer = 0;
717 struct peer *peer;
718 struct peer_group *group;
719 struct listnode *node, *nnode;
720 int ret = CMD_SUCCESS;
721
722 if (no)
723 idx_peer = 2;
724 else
725 idx_peer = 1;
726 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
727 if (!peer) {
728 vty_out(vty, "%% Specify remote-as or peer-group commands first\n");
729 return CMD_WARNING_CONFIG_FAILED;
730 }
731 if (!peer->bfd_info) {
732 if (no)
733 return CMD_SUCCESS;
734 vty_out(vty, "%% Specify bfd command first\n");
735 return CMD_WARNING_CONFIG_FAILED;
736 }
737 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
738 group = peer->group;
739 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer))
740 ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
741 } else
742 ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
743 return ret;
744 }
745
c43ed2e4
DS
746DEFUN (no_neighbor_bfd,
747 no_neighbor_bfd_cmd,
64dc4b2d
RZ
748#if HAVE_BFDD > 0
749 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
750#else
5bf15956 751 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd [(2-255) (50-60000) (50-60000)]",
64dc4b2d 752#endif /* HAVE_BFDD */
c43ed2e4
DS
753 NO_STR
754 NEIGHBOR_STR
755 NEIGHBOR_ADDR_STR2
5bf15956 756 "Disables BFD support\n"
64dc4b2d 757#if HAVE_BFDD == 0
5bf15956
DW
758 "Detect Multiplier\n"
759 "Required min receive interval\n"
64dc4b2d
RZ
760 "Desired min transmit interval\n"
761#endif /* !HAVE_BFDD */
762)
c43ed2e4 763{
d62a17ae 764 int idx_peer = 2;
765 struct peer *peer;
766 int ret;
c43ed2e4 767
d62a17ae 768 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
769 if (!peer)
770 return CMD_WARNING_CONFIG_FAILED;
c43ed2e4 771
d62a17ae 772 ret = bgp_bfd_peer_param_unset(peer);
773 if (ret != 0)
774 return bgp_vty_return(vty, ret);
c43ed2e4 775
d62a17ae 776 return CMD_SUCCESS;
c43ed2e4
DS
777}
778
813d4307 779
986aa00f 780DEFUN_HIDDEN (no_neighbor_bfd_type,
781 no_neighbor_bfd_type_cmd,
e83a9414 782 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
986aa00f 783 NO_STR
784 NEIGHBOR_STR
785 NEIGHBOR_ADDR_STR2
786 "Disables BFD support\n"
3a2d747c
QY
787 "Multihop session\n"
788 "Singlehop session\n")
986aa00f 789{
d62a17ae 790 int idx_peer = 2;
791 struct peer *peer;
792 int ret;
986aa00f 793
d62a17ae 794 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
795 if (!peer)
796 return CMD_WARNING_CONFIG_FAILED;
986aa00f 797
d62a17ae 798 if (!peer->bfd_info)
799 return 0;
986aa00f 800
d62a17ae 801 ret = bgp_bfd_peer_param_type_set(peer, BFD_TYPE_NOT_CONFIGURED);
802 if (ret != 0)
803 return bgp_vty_return(vty, ret);
986aa00f 804
d62a17ae 805 return CMD_SUCCESS;
986aa00f 806}
807
d62a17ae 808void bgp_bfd_init(void)
c43ed2e4 809{
d62a17ae 810 bfd_gbl_init();
811
812 /* Initialize BFD client functions */
813 zclient->interface_bfd_dest_update = bgp_bfd_dest_update;
814 zclient->bfd_dest_replay = bgp_bfd_dest_replay;
815
816 /* "neighbor bfd" commands. */
817 install_element(BGP_NODE, &neighbor_bfd_cmd);
818 install_element(BGP_NODE, &neighbor_bfd_param_cmd);
819 install_element(BGP_NODE, &neighbor_bfd_type_cmd);
dcffea69 820 install_element(BGP_NODE, &neighbor_bfd_check_controlplane_failure_cmd);
d62a17ae 821 install_element(BGP_NODE, &no_neighbor_bfd_cmd);
822 install_element(BGP_NODE, &no_neighbor_bfd_type_cmd);
c43ed2e4 823}