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