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