]> git.proxmox.com Git - mirror_frr.git/blob - lib/bfd.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / lib / bfd.c
1 /**
2 * bfd.c: 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 "memory.h"
27 #include "prefix.h"
28 #include "thread.h"
29 #include "stream.h"
30 #include "zclient.h"
31 #include "table.h"
32 #include "vty.h"
33 #include "bfd.h"
34
35 DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info")
36
37 int bfd_debug = 0;
38 struct bfd_gbl bfd_gbl;
39
40 /*
41 * bfd_gbl_init - Initialize the BFD global structure
42 */
43 void bfd_gbl_init(void)
44 {
45 memset(&bfd_gbl, 0, sizeof(struct bfd_gbl));
46 }
47
48 /*
49 * bfd_gbl_exit - Called when daemon exits
50 */
51 void bfd_gbl_exit(void)
52 {
53 SET_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN);
54 }
55
56 /*
57 * bfd_info_create - Allocate the BFD information
58 */
59 struct bfd_info *bfd_info_create(void)
60 {
61 struct bfd_info *bfd_info;
62
63 bfd_info = XCALLOC(MTYPE_BFD_INFO, sizeof(struct bfd_info));
64 assert(bfd_info);
65
66 bfd_info->status = BFD_STATUS_UNKNOWN;
67 bfd_info->type = BFD_TYPE_NOT_CONFIGURED;
68 bfd_info->last_update = 0;
69 return bfd_info;
70 }
71
72 /*
73 * bfd_info_free - Free the BFD information.
74 */
75 void bfd_info_free(struct bfd_info **bfd_info)
76 {
77 if (*bfd_info) {
78 XFREE(MTYPE_BFD_INFO, *bfd_info);
79 *bfd_info = NULL;
80 }
81 }
82
83 /*
84 * bfd_validate_param - Validate the BFD paramter information.
85 */
86 int bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str,
87 const char *tx_str, uint8_t *dm_val, uint32_t *rx_val,
88 uint32_t *tx_val)
89 {
90 *dm_val = strtoul(dm_str, NULL, 10);
91 *rx_val = strtoul(rx_str, NULL, 10);
92 *tx_val = strtoul(tx_str, NULL, 10);
93 return CMD_SUCCESS;
94 }
95
96 /*
97 * bfd_set_param - Set the configured BFD paramter values
98 */
99 void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
100 uint8_t detect_mult, int defaults, int *command)
101 {
102 if (!*bfd_info) {
103 *bfd_info = bfd_info_create();
104 *command = ZEBRA_BFD_DEST_REGISTER;
105 } else {
106 if (((*bfd_info)->required_min_rx != min_rx)
107 || ((*bfd_info)->desired_min_tx != min_tx)
108 || ((*bfd_info)->detect_mult != detect_mult))
109 *command = ZEBRA_BFD_DEST_UPDATE;
110 }
111
112 if (*command) {
113 (*bfd_info)->required_min_rx = min_rx;
114 (*bfd_info)->desired_min_tx = min_tx;
115 (*bfd_info)->detect_mult = detect_mult;
116 }
117
118 if (!defaults)
119 SET_FLAG((*bfd_info)->flags, BFD_FLAG_PARAM_CFG);
120 else
121 UNSET_FLAG((*bfd_info)->flags, BFD_FLAG_PARAM_CFG);
122 }
123
124 /*
125 * bfd_peer_sendmsg - Format and send a peer register/Unregister
126 * command to Zebra to be forwarded to BFD
127 */
128 void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
129 int family, void *dst_ip, void *src_ip, char *if_name,
130 int ttl, int multihop, int command, int set_flag,
131 vrf_id_t vrf_id)
132 {
133 struct stream *s;
134 int ret;
135 int len;
136
137 /* Individual reg/dereg messages are suppressed during shutdown. */
138 if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) {
139 if (bfd_debug)
140 zlog_debug(
141 "%s: Suppressing BFD peer reg/dereg messages",
142 __FUNCTION__);
143 return;
144 }
145
146 /* Check socket. */
147 if (!zclient || zclient->sock < 0) {
148 if (bfd_debug)
149 zlog_debug(
150 "%s: Can't send BFD peer register, Zebra client not "
151 "established",
152 __FUNCTION__);
153 return;
154 }
155
156 s = zclient->obuf;
157 stream_reset(s);
158 zclient_create_header(s, command, vrf_id);
159
160 stream_putl(s, getpid());
161
162 stream_putw(s, family);
163 switch (family) {
164 case AF_INET:
165 stream_put_in_addr(s, (struct in_addr *)dst_ip);
166 break;
167 case AF_INET6:
168 stream_put(s, dst_ip, 16);
169 break;
170 default:
171 break;
172 }
173
174 if (command != ZEBRA_BFD_DEST_DEREGISTER) {
175 stream_putl(s, bfd_info->required_min_rx);
176 stream_putl(s, bfd_info->desired_min_tx);
177 stream_putc(s, bfd_info->detect_mult);
178 }
179
180 if (multihop) {
181 stream_putc(s, 1);
182 /* Multi-hop destination send the source IP address to BFD */
183 if (src_ip) {
184 stream_putw(s, family);
185 switch (family) {
186 case AF_INET:
187 stream_put_in_addr(s, (struct in_addr *)src_ip);
188 break;
189 case AF_INET6:
190 stream_put(s, src_ip, 16);
191 break;
192 default:
193 break;
194 }
195 }
196 stream_putc(s, ttl);
197 } else {
198 stream_putc(s, 0);
199 if ((family == AF_INET6) && (src_ip)) {
200 stream_putw(s, family);
201 stream_put(s, src_ip, 16);
202 }
203 if (if_name) {
204 len = strlen(if_name);
205 stream_putc(s, len);
206 stream_put(s, if_name, len);
207 } else {
208 stream_putc(s, 0);
209 }
210 }
211
212 stream_putw_at(s, 0, stream_get_endp(s));
213
214 ret = zclient_send_message(zclient);
215
216 if (ret < 0) {
217 if (bfd_debug)
218 zlog_debug(
219 "bfd_peer_sendmsg: zclient_send_message() failed");
220 return;
221 }
222
223 if (set_flag) {
224 if (command == ZEBRA_BFD_DEST_REGISTER)
225 SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG);
226 else if (command == ZEBRA_BFD_DEST_DEREGISTER)
227 UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG);
228 }
229
230 return;
231 }
232
233 /*
234 * bfd_get_command_dbg_str - Convert command to a debug string.
235 */
236 const char *bfd_get_command_dbg_str(int command)
237 {
238 switch (command) {
239 case ZEBRA_BFD_DEST_REGISTER:
240 return "Register";
241 case ZEBRA_BFD_DEST_DEREGISTER:
242 return "Deregister";
243 case ZEBRA_BFD_DEST_UPDATE:
244 return "Update";
245 default:
246 return "Unknown";
247 }
248 }
249
250 /*
251 * bfd_get_peer_info - Extract the Peer information for which the BFD session
252 * went down from the message sent from Zebra to clients.
253 */
254 struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
255 struct prefix *sp, int *status,
256 vrf_id_t vrf_id)
257 {
258 unsigned int ifindex;
259 struct interface *ifp = NULL;
260 int plen;
261
262 /* Get interface index. */
263 ifindex = stream_getl(s);
264
265 /* Lookup index. */
266 if (ifindex != 0) {
267 ifp = if_lookup_by_index(ifindex, vrf_id);
268 if (ifp == NULL) {
269 if (bfd_debug)
270 zlog_debug(
271 "zebra_interface_bfd_read: "
272 "Can't find interface by ifindex: %d ",
273 ifindex);
274 return NULL;
275 }
276 }
277
278 /* Fetch destination address. */
279 dp->family = stream_getc(s);
280
281 plen = prefix_blen(dp);
282 stream_get(&dp->u.prefix, s, plen);
283 dp->prefixlen = stream_getc(s);
284
285 /* Get BFD status. */
286 *status = stream_getl(s);
287
288 if (sp) {
289 sp->family = stream_getc(s);
290
291 plen = prefix_blen(sp);
292 stream_get(&sp->u.prefix, s, plen);
293 sp->prefixlen = stream_getc(s);
294 }
295 return ifp;
296 }
297
298 /*
299 * bfd_get_status_str - Convert BFD status to a display string.
300 */
301 const char *bfd_get_status_str(int status)
302 {
303 switch (status) {
304 case BFD_STATUS_DOWN:
305 return "Down";
306 case BFD_STATUS_UP:
307 return "Up";
308 case BFD_STATUS_UNKNOWN:
309 default:
310 return "Unknown";
311 }
312 }
313
314 /*
315 * bfd_last_update - Calculate the last BFD update time and convert it
316 * into a dd:hh:mm:ss display format.
317 */
318 static void bfd_last_update(time_t last_update, char *buf, size_t len)
319 {
320 time_t curr;
321 time_t diff;
322 struct tm *tm;
323 struct timeval tv;
324
325 /* If no BFD satatus update has ever been received, print `never'. */
326 if (last_update == 0) {
327 snprintf(buf, len, "never");
328 return;
329 }
330
331 /* Get current time. */
332 monotime(&tv);
333 curr = tv.tv_sec;
334 diff = curr - last_update;
335 tm = gmtime(&diff);
336
337 snprintf(buf, len, "%d:%02d:%02d:%02d", tm->tm_yday, tm->tm_hour,
338 tm->tm_min, tm->tm_sec);
339 }
340
341 /*
342 * bfd_show_param - Show the BFD parameter information.
343 */
344 void bfd_show_param(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag,
345 int extra_space, bool use_json, json_object *json_obj)
346 {
347 json_object *json_bfd = NULL;
348
349 if (!bfd_info)
350 return;
351
352 if (use_json) {
353 if (bfd_tag)
354 json_bfd = json_object_new_object();
355 else
356 json_bfd = json_obj;
357
358 json_object_int_add(json_bfd, "detectMultiplier",
359 bfd_info->detect_mult);
360 json_object_int_add(json_bfd, "rxMinInterval",
361 bfd_info->required_min_rx);
362 json_object_int_add(json_bfd, "txMinInterval",
363 bfd_info->desired_min_tx);
364 if (bfd_tag)
365 json_object_object_add(json_obj, "peerBfdInfo",
366 json_bfd);
367 } else {
368 vty_out(vty,
369 " %s%sDetect Multiplier: %d, Min Rx interval: %d,"
370 " Min Tx interval: %d\n",
371 (extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ",
372 bfd_info->detect_mult, bfd_info->required_min_rx,
373 bfd_info->desired_min_tx);
374 }
375 }
376
377 /*
378 * bfd_show_status - Show the BFD status information.
379 */
380 static void bfd_show_status(struct vty *vty, struct bfd_info *bfd_info,
381 int bfd_tag, int extra_space, bool use_json,
382 json_object *json_bfd)
383 {
384 char time_buf[32];
385
386 if (!bfd_info)
387 return;
388
389 bfd_last_update(bfd_info->last_update, time_buf, 32);
390 if (use_json) {
391 json_object_string_add(json_bfd, "status",
392 bfd_get_status_str(bfd_info->status));
393 json_object_string_add(json_bfd, "lastUpdate", time_buf);
394 } else {
395 vty_out(vty, " %s%sStatus: %s, Last update: %s\n",
396 (extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ",
397 bfd_get_status_str(bfd_info->status), time_buf);
398 }
399 }
400
401 /*
402 * bfd_show_info - Show the BFD information.
403 */
404 void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop,
405 int extra_space, bool use_json, json_object *json_obj)
406 {
407 json_object *json_bfd = NULL;
408
409 if (!bfd_info)
410 return;
411
412 if (use_json) {
413 json_bfd = json_object_new_object();
414 if (multihop)
415 json_object_string_add(json_bfd, "type", "multi hop");
416 else
417 json_object_string_add(json_bfd, "type", "single hop");
418 } else {
419 vty_out(vty, " %sBFD: Type: %s\n", (extra_space) ? " " : "",
420 (multihop) ? "multi hop" : "single hop");
421 }
422
423 bfd_show_param(vty, bfd_info, 0, extra_space, use_json, json_bfd);
424 bfd_show_status(vty, bfd_info, 0, extra_space, use_json, json_bfd);
425
426 if (use_json)
427 json_object_object_add(json_obj, "peerBfdInfo", json_bfd);
428 else
429 vty_out(vty, "\n");
430 }
431
432 /*
433 * bfd_client_sendmsg - Format and send a client register
434 * command to Zebra to be forwarded to BFD
435 */
436 void bfd_client_sendmsg(struct zclient *zclient, int command)
437 {
438 struct stream *s;
439 int ret;
440
441 /* Check socket. */
442 if (!zclient || zclient->sock < 0) {
443 if (bfd_debug)
444 zlog_debug(
445 "%s: Can't send BFD client register, Zebra client not "
446 "established",
447 __FUNCTION__);
448 return;
449 }
450
451 s = zclient->obuf;
452 stream_reset(s);
453 zclient_create_header(s, command, VRF_DEFAULT);
454
455 stream_putl(s, getpid());
456
457 stream_putw_at(s, 0, stream_get_endp(s));
458
459 ret = zclient_send_message(zclient);
460
461 if (ret < 0) {
462 if (bfd_debug)
463 zlog_debug(
464 "bfd_client_sendmsg %ld: zclient_send_message() failed",
465 (long)getpid());
466 return;
467 }
468
469 return;
470 }