]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_bfd.c
Merge branch 'cmaster' of ssh://stash.cumulusnetworks.com:7999/quag/quagga into cmaster
[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
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24 #include <zebra.h>
25
26 #include "command.h"
27 #include "linklist.h"
28 #include "memory.h"
29 #include "prefix.h"
30 #include "thread.h"
31 #include "buffer.h"
32 #include "stream.h"
33 #include "zclient.h"
34 #include "vty.h"
35 #include "bfd.h"
36 #include "lib/json.h"
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 template
47 * to peer.
48 */
49 void
50 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 }
69
70 /*
71 * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single hop.
72 */
73 static int
74 bgp_bfd_is_peer_multihop(struct peer *peer)
75 {
76 if((peer->sort == BGP_PEER_IBGP) || is_ebgp_multihop_configured(peer))
77 return 1;
78 else
79 return 0;
80 }
81
82 /*
83 * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister
84 * command to Zebra to be forwarded to BFD
85 */
86 static void
87 bgp_bfd_peer_sendmsg (struct peer *peer, int command)
88 {
89 struct bfd_info *bfd_info;
90
91 bfd_info = (struct bfd_info *)peer->bfd_info;
92
93 if (peer->su.sa.sa_family == AF_INET)
94 bfd_peer_sendmsg (zclient, bfd_info, AF_INET,
95 &peer->su.sin.sin_addr,
96 (peer->su_local) ? &peer->su_local->sin.sin_addr : NULL,
97 (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL,
98 peer->ttl, bgp_bfd_is_peer_multihop(peer), command, 1);
99 else if (peer->su.sa.sa_family == AF_INET6)
100 bfd_peer_sendmsg (zclient, bfd_info, AF_INET6,
101 &peer->su.sin6.sin6_addr,
102 (peer->su_local) ? &peer->su_local->sin6.sin6_addr : NULL,
103 (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL,
104 peer->ttl, bgp_bfd_is_peer_multihop(peer), command, 1);
105 }
106
107 /*
108 * bgp_bfd_register_peer - register a peer with BFD through zebra
109 * for monitoring the peer rechahability.
110 */
111 void
112 bgp_bfd_register_peer (struct peer *peer)
113 {
114 struct bfd_info *bfd_info;
115
116 if (!peer->bfd_info)
117 return;
118 bfd_info = (struct bfd_info *)peer->bfd_info;
119
120 /* Check if BFD is enabled and peer has already been registered with BFD */
121 if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
122 return;
123
124 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
125 }
126
127 /**
128 * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
129 * for stopping the monitoring of the peer
130 * rechahability.
131 */
132 void
133 bgp_bfd_deregister_peer (struct peer *peer)
134 {
135 struct bfd_info *bfd_info;
136
137 if (!peer->bfd_info)
138 return;
139 bfd_info = (struct bfd_info *)peer->bfd_info;
140
141 /* Check if BFD is eanbled and peer has not been registered */
142 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
143 return;
144
145 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
146 }
147
148 /*
149 * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
150 * through zebra.
151 */
152 static void
153 bgp_bfd_update_peer (struct peer *peer)
154 {
155 struct bfd_info *bfd_info;
156
157 if (!peer->bfd_info)
158 return;
159 bfd_info = (struct bfd_info *)peer->bfd_info;
160
161 /* Check if the peer has been registered with BFD*/
162 if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
163 return;
164
165 bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE);
166 }
167
168 /*
169 * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
170 * to zebra
171 */
172 static int
173 bgp_bfd_dest_replay (int command, struct zclient *client, zebra_size_t length)
174 {
175 struct listnode *mnode, *node, *nnode;
176 struct bgp *bgp;
177 struct peer *peer;
178
179 if (BGP_DEBUG (zebra, ZEBRA))
180 zlog_debug("Zebra: BFD Dest replay request");
181
182 /* Replay the peer, if BFD is enabled in BGP */
183
184 for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
185 for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
186 {
187 bgp_bfd_update_peer(peer);
188 }
189
190 return 0;
191 }
192
193 /*
194 * bgp_interface_bfd_dest_down - Find the peer for which the BFD status
195 * has changed and bring down the peer
196 * connectivity.
197 */
198 static int
199 bgp_interface_bfd_dest_down (int command, struct zclient *zclient,
200 zebra_size_t length)
201 {
202 struct interface *ifp;
203 struct prefix dp;
204 struct prefix sp;
205
206 ifp = bfd_get_peer_info (zclient->ibuf, &dp, &sp);
207
208 if (BGP_DEBUG (zebra, ZEBRA))
209 {
210 char buf[2][128];
211 prefix2str(&dp, buf[0], sizeof(buf[0]));
212 if (ifp)
213 {
214 zlog_debug("Zebra: interface %s bfd destination %s down",
215 ifp->name, buf[0]);
216 }
217 else
218 {
219 prefix2str(&sp, buf[1], sizeof(buf[1]));
220 zlog_debug("Zebra: source %s bfd destination %s down",
221 buf[1], buf[0]);
222 }
223 }
224
225 /* Bring the peer down if BFD is enabled in BGP */
226 {
227 struct listnode *mnode, *node, *nnode;
228 struct bgp *bgp;
229 struct peer *peer;
230
231 for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
232 for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
233 {
234 if (!peer->bfd_info)
235 continue;
236
237 if ((dp.family == AF_INET) && (peer->su.sa.sa_family == AF_INET))
238 {
239 if (dp.u.prefix4.s_addr != peer->su.sin.sin_addr.s_addr)
240 continue;
241 }
242 #ifdef HAVE_IPV6
243 else if ((dp.family == AF_INET6) &&
244 (peer->su.sa.sa_family == AF_INET6))
245 {
246 if (memcmp(&dp.u.prefix6, &peer->su.sin6.sin6_addr,
247 sizeof (struct in6_addr)))
248 continue;
249 }
250 #endif
251 else
252 continue;
253
254 if (ifp && (ifp == peer->nexthop.ifp))
255 {
256 peer->last_reset = PEER_DOWN_BFD_DOWN;
257 BGP_EVENT_ADD (peer, BGP_Stop);
258 }
259 else
260 {
261 if (!peer->su_local)
262 continue;
263
264 if ((sp.family == AF_INET) &&
265 (peer->su_local->sa.sa_family == AF_INET))
266 {
267 if (sp.u.prefix4.s_addr != peer->su_local->sin.sin_addr.s_addr)
268 continue;
269 }
270 #ifdef HAVE_IPV6
271 else if ((sp.family == AF_INET6) &&
272 (peer->su_local->sa.sa_family == AF_INET6))
273 {
274 if (memcmp(&sp.u.prefix6, &peer->su_local->sin6.sin6_addr,
275 sizeof (struct in6_addr)))
276 continue;
277 }
278 #endif
279 else
280 continue;
281
282 peer->last_reset = PEER_DOWN_BFD_DOWN;
283 BGP_EVENT_ADD (peer, BGP_Stop);
284 }
285 }
286 }
287
288 return 0;
289 }
290
291 /*
292 * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
293 */
294 static int
295 bgp_bfd_peer_param_set (struct peer *peer, u_int32_t min_rx, u_int32_t min_tx,
296 u_int8_t detect_mult, int defaults)
297 {
298 struct peer_group *group;
299 struct listnode *node, *nnode;
300 int command = 0;
301
302 bfd_set_param(&(peer->bfd_info), min_rx, min_tx, detect_mult,
303 defaults, &command);
304
305 if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
306 {
307 group = peer->group;
308 for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
309 {
310 command = 0;
311 bfd_set_param(&(peer->bfd_info), min_rx, min_tx, detect_mult,
312 defaults, &command);
313
314 if ((peer->status == Established) &&
315 (command == ZEBRA_BFD_DEST_REGISTER))
316 bgp_bfd_register_peer(peer);
317 else if (command == ZEBRA_BFD_DEST_UPDATE)
318 bgp_bfd_update_peer(peer);
319 }
320 }
321 else
322 {
323 if ((peer->status == Established) &&
324 (command == ZEBRA_BFD_DEST_REGISTER))
325 bgp_bfd_register_peer(peer);
326 else if (command == ZEBRA_BFD_DEST_UPDATE)
327 bgp_bfd_update_peer(peer);
328 }
329 return 0;
330 }
331
332 /*
333 * bgp_bfd_peer_param_unset - Unset the configured BFD paramter values for peer.
334 */
335 static int
336 bgp_bfd_peer_param_unset (struct peer *peer)
337 {
338 struct peer_group *group;
339 struct listnode *node, *nnode;
340
341 if (!peer->bfd_info)
342 return 0;
343
344 if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
345 {
346 bfd_info_free(&(peer->bfd_info));
347 group = peer->group;
348 for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
349 {
350 bgp_bfd_deregister_peer(peer);
351 bfd_info_free(&(peer->bfd_info));
352 }
353 }
354 else
355 {
356 bgp_bfd_deregister_peer(peer);
357 bfd_info_free(&(peer->bfd_info));
358 }
359 return 0;
360 }
361
362 /*
363 * bgp_bfd_peer_config_write - Write the peer BFD configuration.
364 */
365 void
366 bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
367 {
368 struct bfd_info *bfd_info;
369
370 if (!peer->bfd_info)
371 return;
372
373 bfd_info = (struct bfd_info *)peer->bfd_info;
374
375 if (CHECK_FLAG (bfd_info->flags, BFD_FLAG_PARAM_CFG))
376 vty_out (vty, " neighbor %s bfd %d %d %d%s", addr,
377 bfd_info->detect_mult, bfd_info->required_min_rx,
378 bfd_info->desired_min_tx, VTY_NEWLINE);
379 else
380 vty_out (vty, " neighbor %s bfd%s", addr, VTY_NEWLINE);
381 }
382
383 /*
384 * bgp_bfd_show_info - Show the peer BFD information.
385 */
386 void
387 bgp_bfd_show_info(struct vty *vty, struct peer *peer, u_char use_json, json_object *json_neigh)
388 {
389 struct bfd_info *bfd_info;
390 json_object *json_bfd = NULL;
391
392 if (!peer->bfd_info)
393 return;
394
395 if (use_json)
396 json_bfd = json_object_new_object();
397
398 bfd_info = (struct bfd_info *)peer->bfd_info;
399
400 if (use_json)
401 {
402 if (bgp_bfd_is_peer_multihop(peer))
403 json_object_string_add(json_bfd, "bfdMultiHop", "yes");
404 else
405 json_object_string_add(json_bfd, "bfdMultiHop", "no");
406 json_object_int_add(json_bfd, "detectMultiplier", bfd_info->detect_mult);
407 json_object_int_add(json_bfd, "rxMinInterval", bfd_info->required_min_rx);
408 json_object_int_add(json_bfd, "txMinInterval", bfd_info->desired_min_tx);
409 json_object_object_add(json_neigh, "peerBfdInfo", json_bfd);
410 }
411 else
412 {
413 vty_out (vty, " BFD: Multi-hop: %s%s",
414 (bgp_bfd_is_peer_multihop(peer)) ? "yes" : "no", VTY_NEWLINE);
415 vty_out (vty, " Detect Mul: %d, Min Rx interval: %d,"
416 " Min Tx interval: %d%s",
417 bfd_info->detect_mult, bfd_info->required_min_rx,
418 bfd_info->desired_min_tx, VTY_NEWLINE);
419 vty_out (vty, "%s", VTY_NEWLINE);
420 }
421 }
422
423 DEFUN (neighbor_bfd,
424 neighbor_bfd_cmd,
425 NEIGHBOR_CMD2 "bfd",
426 NEIGHBOR_STR
427 NEIGHBOR_ADDR_STR2
428 "Enables BFD support\n")
429 {
430 struct peer *peer;
431 int ret;
432
433 peer = peer_and_group_lookup_vty (vty, argv[0]);
434 if (! peer)
435 return CMD_WARNING;
436
437 ret = bgp_bfd_peer_param_set (peer, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
438 BFD_DEF_DETECT_MULT, 1);
439 if (ret != 0)
440 return bgp_vty_return (vty, ret);
441
442 return CMD_SUCCESS;
443
444 }
445
446 DEFUN (neighbor_bfd_param,
447 neighbor_bfd_param_cmd,
448 NEIGHBOR_CMD2 "bfd " BFD_CMD_DETECT_MULT_RANGE BFD_CMD_MIN_RX_RANGE BFD_CMD_MIN_TX_RANGE,
449 NEIGHBOR_STR
450 NEIGHBOR_ADDR_STR2
451 "Enables BFD support\n"
452 "Detect Multiplier\n"
453 "Required min receive interval\n"
454 "Desired min transmit interval\n")
455 {
456 struct peer *peer;
457 u_int32_t rx_val;
458 u_int32_t tx_val;
459 u_int8_t dm_val;
460 int ret;
461
462 peer = peer_and_group_lookup_vty (vty, argv[0]);
463 if (!peer)
464 return CMD_WARNING;
465
466 if ((ret = bfd_validate_param (vty, argv[1], argv[2], argv[3], &dm_val,
467 &rx_val, &tx_val)) != CMD_SUCCESS)
468 return ret;
469
470 ret = bgp_bfd_peer_param_set (peer, rx_val, tx_val, dm_val, 0);
471 if (ret != 0)
472 return bgp_vty_return (vty, ret);
473
474 return CMD_SUCCESS;
475
476 }
477
478 DEFUN (no_neighbor_bfd,
479 no_neighbor_bfd_cmd,
480 NO_NEIGHBOR_CMD2 "bfd",
481 NO_STR
482 NEIGHBOR_STR
483 NEIGHBOR_ADDR_STR2
484 "Disables BFD support\n")
485 {
486 struct peer *peer;
487 int ret;
488
489 peer = peer_and_group_lookup_vty (vty, argv[0]);
490 if (! peer)
491 return CMD_WARNING;
492
493 ret = bgp_bfd_peer_param_unset(peer);
494 if (ret != 0)
495 return bgp_vty_return (vty, ret);
496
497 return CMD_SUCCESS;
498 }
499
500 void
501 bgp_bfd_init(void)
502 {
503 /* Initialize BFD client functions */
504 zclient->interface_bfd_dest_down = bgp_interface_bfd_dest_down;
505 zclient->bfd_dest_replay = bgp_bfd_dest_replay;
506
507 /* "neighbor bfd" commands. */
508 install_element (BGP_NODE, &neighbor_bfd_cmd);
509 install_element (BGP_NODE, &neighbor_bfd_param_cmd);
510 install_element (BGP_NODE, &no_neighbor_bfd_cmd);
511 }