]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_bfd.c
Merge pull request #7353 from AnuradhaKaruppiah/mh-cleanup-fix-1
[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 */
3dc339cd 75bool 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)
3dc339cd 82 return false;
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))
3dc339cd 87 return true;
d62a17ae 88 else
3dc339cd 89 return false;
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{
02012bef 98 struct bfd_session_arg arg = {};
d62a17ae 99 struct bfd_info *bfd_info;
02012bef 100 int multihop;
0945d5ed 101 vrf_id_t vrf_id;
02012bef 102 size_t addrlen;
d62a17ae 103
95a99382
RZ
104 /*
105 * XXX: some pointers are dangling during shutdown, so instead of
106 * trying to send a message during signal handlers lets just wait BGP
107 * to terminate zebra's connection and BFD will automatically find
108 * out that we are no longer expecting notifications.
109 *
110 * The pointer that is causing a crash here is `peer->nexthop.ifp`.
111 * That happens because at this point of the shutdown all interfaces are
112 * already `free()`d.
113 */
114 if (bm->terminating)
115 return;
d62a17ae 116
117 bfd_info = (struct bfd_info *)peer->bfd_info;
118
0945d5ed 119 vrf_id = peer->bgp->vrf_id;
d62a17ae 120
121 if (command == ZEBRA_BFD_DEST_DEREGISTER) {
122 multihop =
123 CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
124 UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
125 } else {
126 multihop = bgp_bfd_is_peer_multihop(peer);
127 if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop)
128 SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
129 }
dcffea69
PG
130 /* while graceful restart with fwd path preserved
131 * and bfd controlplane check not configured is not kept
9beff0bd
PG
132 * keep bfd independent controlplane bit set to 1
133 */
892fedb6
DA
134 if (!CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_RESTART)
135 && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)
dcffea69 136 && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
892fedb6 137 SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
9beff0bd 138
02012bef
RZ
139 /* Set all message arguments. */
140 arg.family = peer->su.sa.sa_family;
141 addrlen = arg.family == AF_INET ? sizeof(struct in_addr)
142 : sizeof(struct in6_addr);
143
144 if (arg.family == AF_INET)
145 memcpy(&arg.dst, &peer->su.sin.sin_addr, addrlen);
146 else
147 memcpy(&arg.dst, &peer->su.sin6.sin6_addr, addrlen);
148
149 if (peer->su_local) {
150 if (arg.family == AF_INET)
151 memcpy(&arg.src, &peer->su_local->sin.sin_addr,
152 addrlen);
153 else
154 memcpy(&arg.src, &peer->su_local->sin6.sin6_addr,
155 addrlen);
156 }
157
158 if (peer->nexthop.ifp) {
159 arg.ifnamelen = strlen(peer->nexthop.ifp->name);
160 strlcpy(arg.ifname, peer->nexthop.ifp->name,
161 sizeof(arg.ifname));
162 }
163
164 if (bfd_info->profile[0]) {
165 arg.profilelen = strlen(bfd_info->profile);
166 strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile));
167 }
168
169 arg.set_flag = 1;
170 arg.mhop = multihop;
171 arg.ttl = peer->ttl;
172 arg.vrf_id = vrf_id;
173 arg.command = command;
174 arg.bfd_info = bfd_info;
175 arg.min_tx = bfd_info->desired_min_tx;
176 arg.min_rx = bfd_info->required_min_rx;
177 arg.detection_multiplier = bfd_info->detect_mult;
178 arg.cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
179
180 /* Send message. */
181 zclient_bfd_command(zclient, &arg);
c43ed2e4
DS
182}
183
184/*
185 * bgp_bfd_register_peer - register a peer with BFD through zebra
186 * for monitoring the peer rechahability.
187 */
d62a17ae 188void bgp_bfd_register_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 BFD is enabled and peer has already been registered with BFD
197 */
198 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
199 return;
c43ed2e4 200
d62a17ae 201 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
c43ed2e4
DS
202}
203
204/**
205 * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
206 * for stopping the monitoring of the peer
207 * rechahability.
208 */
d62a17ae 209void bgp_bfd_deregister_peer(struct peer *peer)
c43ed2e4 210{
d62a17ae 211 struct bfd_info *bfd_info;
c43ed2e4 212
d62a17ae 213 if (!peer->bfd_info)
214 return;
215 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 216
d62a17ae 217 /* Check if BFD is eanbled and peer has not been registered */
218 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
219 return;
c43ed2e4 220
d62a17ae 221 bfd_info->status = BFD_STATUS_DOWN;
222 bfd_info->last_update = bgp_clock();
5c940836 223
d62a17ae 224 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
c43ed2e4
DS
225}
226
227/*
228 * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
229 * through zebra.
230 */
d62a17ae 231static void bgp_bfd_update_peer(struct peer *peer)
c43ed2e4 232{
d62a17ae 233 struct bfd_info *bfd_info;
c43ed2e4 234
d62a17ae 235 if (!peer->bfd_info)
236 return;
237 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 238
d62a17ae 239 /* Check if the peer has been registered with BFD*/
240 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
241 return;
c43ed2e4 242
d62a17ae 243 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE);
c43ed2e4
DS
244}
245
fe0c4ed7
PG
246/**
247 * bgp_bfd_reset_peer - reinitialise bfd
248 * ensures that bfd state machine is restarted
249 * to be synced with remote bfd
250 */
251void bgp_bfd_reset_peer(struct peer *peer)
252{
fe0c4ed7
PG
253 if (!peer->bfd_info)
254 return;
fe0c4ed7 255
fe0c4ed7
PG
256 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
257}
258
986aa00f 259/*
260 * bgp_bfd_update_type - update session type with BFD through zebra.
261 */
d62a17ae 262static void bgp_bfd_update_type(struct peer *peer)
986aa00f 263{
d62a17ae 264 struct bfd_info *bfd_info;
265 int multihop;
266
267 if (!peer->bfd_info)
268 return;
269 bfd_info = (struct bfd_info *)peer->bfd_info;
270
271 /* Check if the peer has been registered with BFD*/
272 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
273 return;
274
275 if (bfd_info->type == BFD_TYPE_NOT_CONFIGURED) {
276 multihop = bgp_bfd_is_peer_multihop(peer);
277 if ((multihop
278 && !CHECK_FLAG(bfd_info->flags,
279 BFD_FLAG_BFD_TYPE_MULTIHOP))
9d303b37
DL
280 || (!multihop && CHECK_FLAG(bfd_info->flags,
281 BFD_FLAG_BFD_TYPE_MULTIHOP))) {
d62a17ae 282 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
283 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
284 }
285 } else {
286 if ((bfd_info->type == BFD_TYPE_MULTIHOP
287 && !CHECK_FLAG(bfd_info->flags,
288 BFD_FLAG_BFD_TYPE_MULTIHOP))
289 || (bfd_info->type == BFD_TYPE_SINGLEHOP
290 && CHECK_FLAG(bfd_info->flags,
291 BFD_FLAG_BFD_TYPE_MULTIHOP))) {
292 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
293 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
294 }
295 }
986aa00f 296}
297
c43ed2e4
DS
298/*
299 * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
300 * to zebra
301 */
121f9dee 302static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS)
c43ed2e4 303{
d62a17ae 304 struct listnode *mnode, *node, *nnode;
305 struct bgp *bgp;
306 struct peer *peer;
c43ed2e4 307
d62a17ae 308 if (BGP_DEBUG(zebra, ZEBRA))
309 zlog_debug("Zebra: BFD Dest replay request");
c43ed2e4 310
d62a17ae 311 /* Send the client registration */
0945d5ed 312 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
055c4dfc 313
d62a17ae 314 /* Replay the peer, if BFD is enabled in BGP */
c43ed2e4 315
d62a17ae 316 for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
317 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
318 bgp_bfd_update_peer(peer);
319 }
c43ed2e4 320
d62a17ae 321 return 0;
c43ed2e4
DS
322}
323
324/*
68fe91d6 325 * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
d62a17ae 326 * down the peer if the BFD session went down from
327 * * up.
68fe91d6 328 */
9beff0bd
PG
329static void bgp_bfd_peer_status_update(struct peer *peer, int status,
330 int remote_cbit)
68fe91d6 331{
d62a17ae 332 struct bfd_info *bfd_info;
333 int old_status;
68fe91d6 334
d62a17ae 335 bfd_info = (struct bfd_info *)peer->bfd_info;
68fe91d6 336
d62a17ae 337 if (bfd_info->status == status)
338 return;
68fe91d6 339
d62a17ae 340 old_status = bfd_info->status;
7555dc61
S
341 BFD_SET_CLIENT_STATUS(bfd_info->status, status);
342
d62a17ae 343 bfd_info->last_update = bgp_clock();
68fe91d6 344
37bb7aca
PG
345 if (status != old_status) {
346 if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
347 zlog_debug("[%s]: BFD %s", peer->host,
348 bfd_get_status_str(status));
349 }
d62a17ae 350 if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) {
9beff0bd 351 if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) &&
dcffea69 352 CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE) &&
9beff0bd 353 !remote_cbit) {
3efd0893 354 zlog_info("%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared",
9beff0bd
PG
355 peer->host);
356 return;
357 }
d62a17ae 358 peer->last_reset = PEER_DOWN_BFD_DOWN;
359 BGP_EVENT_ADD(peer, BGP_Stop);
360 }
51728519
PG
361 if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN)
362 && peer->status != Established) {
fc04a677 363 if (!BGP_PEER_START_SUPPRESSED(peer)) {
f8dcd38d 364 bgp_fsm_nht_update(peer, true);
51728519 365 BGP_EVENT_ADD(peer, BGP_Start);
fc04a677 366 }
51728519 367 }
68fe91d6 368}
369
370/*
371 * bgp_bfd_dest_update - Find the peer for which the BFD status
372 * has changed and bring down the peer
373 * connectivity if the BFD session went down.
c43ed2e4 374 */
121f9dee 375static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS)
c43ed2e4 376{
d62a17ae 377 struct interface *ifp;
378 struct prefix dp;
379 struct prefix sp;
380 int status;
9beff0bd 381 int remote_cbit;
d62a17ae 382
9beff0bd
PG
383 ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status,
384 &remote_cbit, vrf_id);
d62a17ae 385
386 if (BGP_DEBUG(zebra, ZEBRA)) {
137147c6 387 struct vrf *vrf;
d62a17ae 388 char buf[2][PREFIX2STR_BUFFER];
137147c6
DS
389
390 vrf = vrf_lookup_by_id(vrf_id);
d62a17ae 391 prefix2str(&dp, buf[0], sizeof(buf[0]));
392 if (ifp) {
393 zlog_debug(
137147c6
DS
394 "Zebra: vrf %s(%u) interface %s bfd destination %s %s %s",
395 VRF_LOGNAME(vrf), vrf_id, ifp->name,
396 buf[0], bfd_get_status_str(status),
9beff0bd 397 remote_cbit ? "(cbit on)" : "");
d62a17ae 398 } else {
399 prefix2str(&sp, buf[1], sizeof(buf[1]));
400 zlog_debug(
137147c6
DS
401 "Zebra: vrf %s(%u) source %s bfd destination %s %s %s",
402 VRF_LOGNAME(vrf), vrf_id, buf[1], buf[0],
9beff0bd
PG
403 bfd_get_status_str(status),
404 remote_cbit ? "(cbit on)" : "");
d62a17ae 405 }
406 }
407
408 /* Bring the peer down if BFD is enabled in BGP */
409 {
410 struct listnode *mnode, *node, *nnode;
411 struct bgp *bgp;
412 struct peer *peer;
413
414 for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
415 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
416 if (!peer->bfd_info)
417 continue;
418
419 if ((dp.family == AF_INET)
420 && (peer->su.sa.sa_family == AF_INET)) {
421 if (dp.u.prefix4.s_addr
422 != peer->su.sin.sin_addr.s_addr)
423 continue;
424 } else if ((dp.family == AF_INET6)
425 && (peer->su.sa.sa_family
426 == AF_INET6)) {
427 if (memcmp(&dp.u.prefix6,
428 &peer->su.sin6.sin6_addr,
429 sizeof(struct in6_addr)))
430 continue;
431 } else
432 continue;
433
434 if (ifp && (ifp == peer->nexthop.ifp)) {
435 bgp_bfd_peer_status_update(peer,
9beff0bd
PG
436 status,
437 remote_cbit);
d62a17ae 438 } else {
439 if (!peer->su_local)
440 continue;
441
442 if ((sp.family == AF_INET)
443 && (peer->su_local->sa.sa_family
444 == AF_INET)) {
445 if (sp.u.prefix4.s_addr
446 != peer->su_local->sin
447 .sin_addr.s_addr)
448 continue;
449 } else if ((sp.family == AF_INET6)
450 && (peer->su_local->sa
451 .sa_family
452 == AF_INET6)) {
453 if (memcmp(&sp.u.prefix6,
454 &peer->su_local->sin6
455 .sin6_addr,
456 sizeof(struct
457 in6_addr)))
458 continue;
459 } else
460 continue;
461
462 if ((vrf_id != VRF_DEFAULT)
463 && (peer->bgp->vrf_id != vrf_id))
464 continue;
465
466 bgp_bfd_peer_status_update(peer,
9beff0bd
PG
467 status,
468 remote_cbit);
d62a17ae 469 }
470 }
471 }
472
473 return 0;
c43ed2e4
DS
474}
475
476/*
477 * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
478 */
d7c0a89a
QY
479static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx,
480 uint32_t min_tx, uint8_t detect_mult,
d62a17ae 481 int defaults)
c43ed2e4 482{
68286f96 483 struct bfd_info *bi;
d62a17ae 484 struct peer_group *group;
485 struct listnode *node, *nnode;
486 int command = 0;
487
488 bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx,
4affdba7 489 detect_mult, NULL, defaults, &command);
d62a17ae 490
68286f96
RZ
491 /* This command overrides profile if it was previously applied. */
492 bi = peer->bfd_info;
493 bi->profile[0] = 0;
494
d62a17ae 495 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
496 group = peer->group;
497 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
498 command = 0;
499 bfd_set_param((struct bfd_info **)&(peer->bfd_info),
4affdba7
G
500 min_rx, min_tx, detect_mult, NULL,
501 defaults, &command);
d62a17ae 502
68286f96
RZ
503 /*
504 * This command overrides profile if it was previously
505 * applied.
506 */
507 bi = peer->bfd_info;
508 bi->profile[0] = 0;
509
d62a17ae 510 if ((peer->status == Established)
511 && (command == ZEBRA_BFD_DEST_REGISTER))
512 bgp_bfd_register_peer(peer);
513 else if (command == ZEBRA_BFD_DEST_UPDATE)
514 bgp_bfd_update_peer(peer);
515 }
516 } else {
517 if ((peer->status == Established)
518 && (command == ZEBRA_BFD_DEST_REGISTER))
519 bgp_bfd_register_peer(peer);
520 else if (command == ZEBRA_BFD_DEST_UPDATE)
521 bgp_bfd_update_peer(peer);
522 }
523 return 0;
c43ed2e4
DS
524}
525
526/*
d62a17ae 527 * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for
528 * peer.
c43ed2e4 529 */
d62a17ae 530static int bgp_bfd_peer_param_unset(struct peer *peer)
c43ed2e4 531{
d62a17ae 532 struct peer_group *group;
533 struct listnode *node, *nnode;
534
535 if (!peer->bfd_info)
536 return 0;
537
538 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
539 bfd_info_free(&(peer->bfd_info));
540 group = peer->group;
541 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
542 bgp_bfd_deregister_peer(peer);
543 bfd_info_free(&(peer->bfd_info));
544 }
545 } else {
546 bgp_bfd_deregister_peer(peer);
547 bfd_info_free(&(peer->bfd_info));
548 }
549 return 0;
c43ed2e4
DS
550}
551
986aa00f 552/*
d62a17ae 553 * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or
554 * singlehop)
986aa00f 555 */
d62a17ae 556static int bgp_bfd_peer_param_type_set(struct peer *peer,
557 enum bfd_sess_type type)
986aa00f 558{
d62a17ae 559 struct peer_group *group;
560 struct listnode *node, *nnode;
561 int command = 0;
562 struct bfd_info *bfd_info;
563
564 if (!peer->bfd_info)
565 bfd_set_param((struct bfd_info **)&(peer->bfd_info),
566 BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
4affdba7 567 BFD_DEF_DETECT_MULT, NULL, 1, &command);
d62a17ae 568
569 bfd_info = (struct bfd_info *)peer->bfd_info;
570 bfd_info->type = type;
571
572 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
573 group = peer->group;
574 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
575 command = 0;
576 if (!peer->bfd_info)
577 bfd_set_param(
578 (struct bfd_info **)&(peer->bfd_info),
579 BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
4affdba7 580 BFD_DEF_DETECT_MULT, NULL, 1, &command);
d62a17ae 581
582 bfd_info = (struct bfd_info *)peer->bfd_info;
583 bfd_info->type = type;
584
585 if (peer->status == Established) {
586 if (command == ZEBRA_BFD_DEST_REGISTER)
587 bgp_bfd_register_peer(peer);
588 else
589 bgp_bfd_update_type(peer);
590 }
591 }
592 } else {
593 if (peer->status == Established) {
594 if (command == ZEBRA_BFD_DEST_REGISTER)
595 bgp_bfd_register_peer(peer);
596 else
597 bgp_bfd_update_type(peer);
598 }
599 }
600
601 return 0;
986aa00f 602}
603
02012bef
RZ
604/**
605 * Set peer BFD profile configuration.
606 */
607static int bgp_bfd_peer_set_profile(struct peer *peer, const char *profile)
608{
609 struct peer_group *group;
610 struct listnode *node, *nnode;
611 int command = 0;
612 struct bfd_info *bfd_info;
613
614 bfd_set_param((struct bfd_info **)&(peer->bfd_info), BFD_DEF_MIN_RX,
4affdba7 615 BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT, NULL, 1, &command);
02012bef
RZ
616
617 bfd_info = (struct bfd_info *)peer->bfd_info;
618
619 /* If profile was specified, then copy string. */
620 if (profile)
621 strlcpy(bfd_info->profile, profile, sizeof(bfd_info->profile));
622 else /* Otherwise just initialize it empty. */
623 bfd_info->profile[0] = 0;
624
625 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
626 group = peer->group;
627 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
628 command = 0;
629 bfd_set_param((struct bfd_info **)&(peer->bfd_info),
630 BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
4affdba7 631 BFD_DEF_DETECT_MULT, NULL, 1, &command);
02012bef
RZ
632
633 bfd_info = (struct bfd_info *)peer->bfd_info;
634
635 /* If profile was specified, then copy string. */
636 if (profile)
637 strlcpy(bfd_info->profile, profile,
638 sizeof(bfd_info->profile));
639 else /* Otherwise just initialize it empty. */
640 bfd_info->profile[0] = 0;
641
642 if (peer->status == Established
643 && command == ZEBRA_BFD_DEST_REGISTER)
644 bgp_bfd_register_peer(peer);
645 else if (command == ZEBRA_BFD_DEST_UPDATE)
646 bgp_bfd_update_peer(peer);
647 }
648 } else {
649 if (peer->status == Established
650 && command == ZEBRA_BFD_DEST_REGISTER)
651 bgp_bfd_register_peer(peer);
652 else if (command == ZEBRA_BFD_DEST_UPDATE)
653 bgp_bfd_update_peer(peer);
654 }
655
656 return 0;
657}
658
c43ed2e4
DS
659/*
660 * bgp_bfd_peer_config_write - Write the peer BFD configuration.
661 */
d62a17ae 662void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
c43ed2e4 663{
d62a17ae 664 struct bfd_info *bfd_info;
c43ed2e4 665
d62a17ae 666 if (!peer->bfd_info)
667 return;
7f342629 668
d62a17ae 669 bfd_info = (struct bfd_info *)peer->bfd_info;
c43ed2e4 670
d62a17ae 671 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
a0841732
RZ
672#if HAVE_BFDD > 0
673 vty_out(vty, " neighbor %s bfd\n", addr);
674#else
d62a17ae 675 vty_out(vty, " neighbor %s bfd %d %d %d\n", addr,
676 bfd_info->detect_mult, bfd_info->required_min_rx,
677 bfd_info->desired_min_tx);
a0841732 678#endif /* HAVE_BFDD */
986aa00f 679
d62a17ae 680 if (bfd_info->type != BFD_TYPE_NOT_CONFIGURED)
681 vty_out(vty, " neighbor %s bfd %s\n", addr,
682 (bfd_info->type == BFD_TYPE_MULTIHOP) ? "multihop"
683 : "singlehop");
986aa00f 684
d62a17ae 685 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)
02012bef
RZ
686 && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED)) {
687 vty_out(vty, " neighbor %s bfd", addr);
688 if (bfd_info->profile[0])
689 vty_out(vty, " profile %s", bfd_info->profile);
690 vty_out(vty, "\n");
691 }
dcffea69
PG
692
693 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
694 vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", addr);
c43ed2e4
DS
695}
696
697/*
698 * bgp_bfd_show_info - Show the peer BFD information.
699 */
9f049418 700void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json,
d62a17ae 701 json_object *json_neigh)
c43ed2e4 702{
d62a17ae 703 bfd_show_info(vty, (struct bfd_info *)peer->bfd_info,
704 bgp_bfd_is_peer_multihop(peer), 0, use_json, json_neigh);
c43ed2e4
DS
705}
706
707DEFUN (neighbor_bfd,
708 neighbor_bfd_cmd,
9ccf14f7 709 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
c43ed2e4
DS
710 NEIGHBOR_STR
711 NEIGHBOR_ADDR_STR2
712 "Enables BFD support\n")
713{
d62a17ae 714 int idx_peer = 1;
715 struct peer *peer;
716 int ret;
c43ed2e4 717
d62a17ae 718 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
719 if (!peer)
720 return CMD_WARNING_CONFIG_FAILED;
c43ed2e4 721
d62a17ae 722 ret = bgp_bfd_peer_param_set(peer, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
723 BFD_DEF_DETECT_MULT, 1);
724 if (ret != 0)
725 return bgp_vty_return(vty, ret);
c43ed2e4 726
d62a17ae 727 return CMD_SUCCESS;
c43ed2e4
DS
728}
729
64dc4b2d
RZ
730#if HAVE_BFDD > 0
731DEFUN_HIDDEN(
732#else
733DEFUN(
734#endif /* HAVE_BFDD */
735 neighbor_bfd_param,
c43ed2e4 736 neighbor_bfd_param_cmd,
9ccf14f7 737 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd (2-255) (50-60000) (50-60000)",
c43ed2e4
DS
738 NEIGHBOR_STR
739 NEIGHBOR_ADDR_STR2
740 "Enables BFD support\n"
741 "Detect Multiplier\n"
742 "Required min receive interval\n"
743 "Desired min transmit interval\n")
744{
d62a17ae 745 int idx_peer = 1;
746 int idx_number_1 = 3;
747 int idx_number_2 = 4;
748 int idx_number_3 = 5;
749 struct peer *peer;
d7c0a89a
QY
750 uint32_t rx_val;
751 uint32_t tx_val;
752 uint8_t dm_val;
d62a17ae 753 int ret;
754
755 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
756 if (!peer)
757 return CMD_WARNING_CONFIG_FAILED;
758
759 if ((ret = bfd_validate_param(
760 vty, argv[idx_number_1]->arg, argv[idx_number_2]->arg,
761 argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
762 != CMD_SUCCESS)
763 return ret;
764
765 ret = bgp_bfd_peer_param_set(peer, rx_val, tx_val, dm_val, 0);
766 if (ret != 0)
767 return bgp_vty_return(vty, ret);
768
769 return CMD_SUCCESS;
c43ed2e4
DS
770}
771
986aa00f 772DEFUN_HIDDEN (neighbor_bfd_type,
773 neighbor_bfd_type_cmd,
e83a9414 774 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
986aa00f 775 NEIGHBOR_STR
776 NEIGHBOR_ADDR_STR2
777 "Enables BFD support\n"
d7fa34c1
QY
778 "Multihop session\n"
779 "Single hop session\n")
986aa00f 780{
d62a17ae 781 int idx_peer = 1;
782 int idx_hop = 3;
783 struct peer *peer;
784 enum bfd_sess_type type;
785 int ret;
786
787 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
788 if (!peer)
789 return CMD_WARNING_CONFIG_FAILED;
790
791 if (strmatch(argv[idx_hop]->text, "singlehop"))
792 type = BFD_TYPE_SINGLEHOP;
793 else if (strmatch(argv[idx_hop]->text, "multihop"))
794 type = BFD_TYPE_MULTIHOP;
795 else
796 return CMD_WARNING_CONFIG_FAILED;
797
798 ret = bgp_bfd_peer_param_type_set(peer, type);
799 if (ret != 0)
800 return bgp_vty_return(vty, ret);
801
802 return CMD_SUCCESS;
986aa00f 803}
804
dcffea69
PG
805static int bgp_bfd_set_check_controlplane_failure_peer(struct vty *vty, struct peer *peer,
806 const char *no)
807{
808 struct bfd_info *bfd_info;
809
810 if (!peer->bfd_info) {
811 if (no)
812 return CMD_SUCCESS;
813 vty_out(vty, "%% Specify bfd command first\n");
814 return CMD_WARNING_CONFIG_FAILED;
815 }
816 bfd_info = (struct bfd_info *)peer->bfd_info;
817 if (!no) {
818 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
819 SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
820 bgp_bfd_update_peer(peer);
821 }
822 } else {
823 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
824 UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
825 bgp_bfd_update_peer(peer);
826 }
827 }
828 return CMD_SUCCESS;
829}
830
831
832DEFUN (neighbor_bfd_check_controlplane_failure,
833 neighbor_bfd_check_controlplane_failure_cmd,
834 "[no] neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure",
835 NO_STR
836 NEIGHBOR_STR
837 NEIGHBOR_ADDR_STR2
838 "BFD support\n"
839 "Link dataplane status with BGP controlplane\n")
840{
841 const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL;
842 int idx_peer = 0;
843 struct peer *peer;
844 struct peer_group *group;
845 struct listnode *node, *nnode;
846 int ret = CMD_SUCCESS;
847
848 if (no)
849 idx_peer = 2;
850 else
851 idx_peer = 1;
852 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
853 if (!peer) {
854 vty_out(vty, "%% Specify remote-as or peer-group commands first\n");
855 return CMD_WARNING_CONFIG_FAILED;
856 }
857 if (!peer->bfd_info) {
858 if (no)
859 return CMD_SUCCESS;
860 vty_out(vty, "%% Specify bfd command first\n");
861 return CMD_WARNING_CONFIG_FAILED;
862 }
863 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
864 group = peer->group;
865 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer))
866 ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
867 } else
868 ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
869 return ret;
870 }
871
c43ed2e4
DS
872DEFUN (no_neighbor_bfd,
873 no_neighbor_bfd_cmd,
64dc4b2d
RZ
874#if HAVE_BFDD > 0
875 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
876#else
5bf15956 877 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd [(2-255) (50-60000) (50-60000)]",
64dc4b2d 878#endif /* HAVE_BFDD */
c43ed2e4
DS
879 NO_STR
880 NEIGHBOR_STR
881 NEIGHBOR_ADDR_STR2
5bf15956 882 "Disables BFD support\n"
64dc4b2d 883#if HAVE_BFDD == 0
5bf15956
DW
884 "Detect Multiplier\n"
885 "Required min receive interval\n"
64dc4b2d
RZ
886 "Desired min transmit interval\n"
887#endif /* !HAVE_BFDD */
888)
c43ed2e4 889{
d62a17ae 890 int idx_peer = 2;
891 struct peer *peer;
892 int ret;
c43ed2e4 893
d62a17ae 894 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
895 if (!peer)
896 return CMD_WARNING_CONFIG_FAILED;
c43ed2e4 897
d62a17ae 898 ret = bgp_bfd_peer_param_unset(peer);
899 if (ret != 0)
900 return bgp_vty_return(vty, ret);
c43ed2e4 901
d62a17ae 902 return CMD_SUCCESS;
c43ed2e4
DS
903}
904
813d4307 905
986aa00f 906DEFUN_HIDDEN (no_neighbor_bfd_type,
907 no_neighbor_bfd_type_cmd,
e83a9414 908 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
986aa00f 909 NO_STR
910 NEIGHBOR_STR
911 NEIGHBOR_ADDR_STR2
912 "Disables BFD support\n"
3a2d747c
QY
913 "Multihop session\n"
914 "Singlehop session\n")
986aa00f 915{
d62a17ae 916 int idx_peer = 2;
917 struct peer *peer;
918 int ret;
986aa00f 919
d62a17ae 920 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
921 if (!peer)
922 return CMD_WARNING_CONFIG_FAILED;
986aa00f 923
d62a17ae 924 if (!peer->bfd_info)
925 return 0;
986aa00f 926
d62a17ae 927 ret = bgp_bfd_peer_param_type_set(peer, BFD_TYPE_NOT_CONFIGURED);
928 if (ret != 0)
929 return bgp_vty_return(vty, ret);
986aa00f 930
d62a17ae 931 return CMD_SUCCESS;
986aa00f 932}
933
02012bef
RZ
934#if HAVE_BFDD > 0
935DEFUN(neighbor_bfd_profile, neighbor_bfd_profile_cmd,
936 "neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF",
937 NEIGHBOR_STR
938 NEIGHBOR_ADDR_STR2
939 "BFD integration\n"
940 BFD_PROFILE_STR
941 BFD_PROFILE_NAME_STR)
942{
943 int idx_peer = 1, idx_prof = 4;
944 struct peer *peer;
945 int ret;
946
947 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
948 if (!peer)
949 return CMD_WARNING_CONFIG_FAILED;
950
951 ret = bgp_bfd_peer_set_profile(peer, argv[idx_prof]->arg);
952 if (ret != 0)
953 return bgp_vty_return(vty, ret);
954
955 return CMD_SUCCESS;
956}
957
958DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd,
959 "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile [BFDPROF]",
960 NO_STR
961 NEIGHBOR_STR
962 NEIGHBOR_ADDR_STR2
963 "BFD integration\n"
964 BFD_PROFILE_STR
965 BFD_PROFILE_NAME_STR)
966{
967 int idx_peer = 2;
968 struct peer *peer;
969 int ret;
970
971 peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
972 if (!peer)
973 return CMD_WARNING_CONFIG_FAILED;
974
975 if (!peer->bfd_info)
976 return 0;
977
978 ret = bgp_bfd_peer_set_profile(peer, NULL);
979 if (ret != 0)
980 return bgp_vty_return(vty, ret);
981
982 return CMD_SUCCESS;
983}
984#endif /* HAVE_BFDD */
985
d62a17ae 986void bgp_bfd_init(void)
c43ed2e4 987{
d62a17ae 988 bfd_gbl_init();
989
990 /* Initialize BFD client functions */
991 zclient->interface_bfd_dest_update = bgp_bfd_dest_update;
992 zclient->bfd_dest_replay = bgp_bfd_dest_replay;
993
994 /* "neighbor bfd" commands. */
995 install_element(BGP_NODE, &neighbor_bfd_cmd);
996 install_element(BGP_NODE, &neighbor_bfd_param_cmd);
997 install_element(BGP_NODE, &neighbor_bfd_type_cmd);
dcffea69 998 install_element(BGP_NODE, &neighbor_bfd_check_controlplane_failure_cmd);
d62a17ae 999 install_element(BGP_NODE, &no_neighbor_bfd_cmd);
1000 install_element(BGP_NODE, &no_neighbor_bfd_type_cmd);
02012bef
RZ
1001
1002#if HAVE_BFDD > 0
1003 install_element(BGP_NODE, &neighbor_bfd_profile_cmd);
1004 install_element(BGP_NODE, &no_neighbor_bfd_profile_cmd);
1005#endif /* HAVE_BFDD */
c43ed2e4 1006}