]>
Commit | Line | Data |
---|---|---|
7f342629 DS |
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 | * | |
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 | |
7f342629 DS |
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" | |
a099abe5 | 30 | #include "vrf.h" |
7f342629 DS |
31 | #include "zclient.h" |
32 | #include "table.h" | |
33 | #include "vty.h" | |
34 | #include "bfd.h" | |
35 | ||
bf8d3d6a | 36 | DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info"); |
4a1ab8e4 | 37 | |
c17faa4b QY |
38 | static int bfd_debug = 0; |
39 | static struct bfd_gbl bfd_gbl; | |
567b877d | 40 | |
41 | /* | |
42 | * bfd_gbl_init - Initialize the BFD global structure | |
43 | */ | |
d62a17ae | 44 | void bfd_gbl_init(void) |
567b877d | 45 | { |
d62a17ae | 46 | memset(&bfd_gbl, 0, sizeof(struct bfd_gbl)); |
567b877d | 47 | } |
48 | ||
49 | /* | |
50 | * bfd_gbl_exit - Called when daemon exits | |
51 | */ | |
d62a17ae | 52 | void bfd_gbl_exit(void) |
567b877d | 53 | { |
d62a17ae | 54 | SET_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN); |
567b877d | 55 | } |
588e90ec | 56 | |
7f342629 DS |
57 | /* |
58 | * bfd_info_create - Allocate the BFD information | |
59 | */ | |
d62a17ae | 60 | struct bfd_info *bfd_info_create(void) |
7f342629 | 61 | { |
d62a17ae | 62 | struct bfd_info *bfd_info; |
7f342629 | 63 | |
d62a17ae | 64 | bfd_info = XCALLOC(MTYPE_BFD_INFO, sizeof(struct bfd_info)); |
65 | assert(bfd_info); | |
7f342629 | 66 | |
d62a17ae | 67 | bfd_info->status = BFD_STATUS_UNKNOWN; |
68 | bfd_info->type = BFD_TYPE_NOT_CONFIGURED; | |
69 | bfd_info->last_update = 0; | |
70 | return bfd_info; | |
7f342629 DS |
71 | } |
72 | ||
73 | /* | |
74 | * bfd_info_free - Free the BFD information. | |
75 | */ | |
d62a17ae | 76 | void bfd_info_free(struct bfd_info **bfd_info) |
7f342629 | 77 | { |
e1b36e13 | 78 | XFREE(MTYPE_BFD_INFO, *bfd_info); |
7f342629 DS |
79 | } |
80 | ||
81 | /* | |
82 | * bfd_validate_param - Validate the BFD paramter information. | |
83 | */ | |
d62a17ae | 84 | int bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str, |
d7c0a89a QY |
85 | const char *tx_str, uint8_t *dm_val, uint32_t *rx_val, |
86 | uint32_t *tx_val) | |
7f342629 | 87 | { |
d62a17ae | 88 | *dm_val = strtoul(dm_str, NULL, 10); |
89 | *rx_val = strtoul(rx_str, NULL, 10); | |
90 | *tx_val = strtoul(tx_str, NULL, 10); | |
91 | return CMD_SUCCESS; | |
7f342629 DS |
92 | } |
93 | ||
94 | /* | |
95 | * bfd_set_param - Set the configured BFD paramter values | |
96 | */ | |
d7c0a89a | 97 | void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx, |
4affdba7 G |
98 | uint8_t detect_mult, const char *profile, int defaults, |
99 | int *command) | |
7f342629 | 100 | { |
d62a17ae | 101 | if (!*bfd_info) { |
102 | *bfd_info = bfd_info_create(); | |
103 | *command = ZEBRA_BFD_DEST_REGISTER; | |
104 | } else { | |
105 | if (((*bfd_info)->required_min_rx != min_rx) | |
106 | || ((*bfd_info)->desired_min_tx != min_tx) | |
4affdba7 | 107 | || ((*bfd_info)->detect_mult != detect_mult) |
a29c51a1 RZ |
108 | || ((*bfd_info)->profile[0] == 0 && profile) |
109 | || ((*bfd_info)->profile[0] && profile == NULL) | |
110 | || (profile && (*bfd_info)->profile[0] | |
111 | && strcmp((*bfd_info)->profile, profile))) | |
d62a17ae | 112 | *command = ZEBRA_BFD_DEST_UPDATE; |
113 | } | |
114 | ||
115 | if (*command) { | |
116 | (*bfd_info)->required_min_rx = min_rx; | |
117 | (*bfd_info)->desired_min_tx = min_tx; | |
118 | (*bfd_info)->detect_mult = detect_mult; | |
4affdba7 G |
119 | if (profile) |
120 | strlcpy((*bfd_info)->profile, profile, | |
121 | BFD_PROFILE_NAME_LEN); | |
122 | else | |
123 | (*bfd_info)->profile[0] = '\0'; | |
d62a17ae | 124 | } |
125 | ||
126 | if (!defaults) | |
127 | SET_FLAG((*bfd_info)->flags, BFD_FLAG_PARAM_CFG); | |
128 | else | |
129 | UNSET_FLAG((*bfd_info)->flags, BFD_FLAG_PARAM_CFG); | |
7f342629 DS |
130 | } |
131 | ||
132 | /* | |
133 | * bfd_peer_sendmsg - Format and send a peer register/Unregister | |
134 | * command to Zebra to be forwarded to BFD | |
bb99eb5d G |
135 | * |
136 | * DEPRECATED: use zclient_bfd_command instead | |
7f342629 | 137 | */ |
d62a17ae | 138 | void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, |
139 | int family, void *dst_ip, void *src_ip, char *if_name, | |
9beff0bd PG |
140 | int ttl, int multihop, int cbit, int command, |
141 | int set_flag, vrf_id_t vrf_id) | |
7f342629 | 142 | { |
18322efd RZ |
143 | struct bfd_session_arg args = {}; |
144 | size_t addrlen; | |
d62a17ae | 145 | |
0437e105 | 146 | /* Individual reg/dereg messages are suppressed during shutdown. */ |
d62a17ae | 147 | if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) { |
148 | if (bfd_debug) | |
149 | zlog_debug( | |
150 | "%s: Suppressing BFD peer reg/dereg messages", | |
15569c58 | 151 | __func__); |
d62a17ae | 152 | return; |
153 | } | |
154 | ||
155 | /* Check socket. */ | |
156 | if (!zclient || zclient->sock < 0) { | |
157 | if (bfd_debug) | |
158 | zlog_debug( | |
3efd0893 | 159 | "%s: Can't send BFD peer register, Zebra client not established", |
15569c58 | 160 | __func__); |
d62a17ae | 161 | return; |
162 | } | |
163 | ||
18322efd RZ |
164 | /* Fill in all arguments. */ |
165 | args.ttl = ttl; | |
166 | args.cbit = cbit; | |
167 | args.family = family; | |
168 | args.mhop = multihop; | |
169 | args.vrf_id = vrf_id; | |
170 | args.command = command; | |
171 | args.set_flag = set_flag; | |
172 | args.bfd_info = bfd_info; | |
6a6b1036 RZ |
173 | if (args.bfd_info) { |
174 | args.min_rx = bfd_info->required_min_rx; | |
175 | args.min_tx = bfd_info->desired_min_tx; | |
176 | args.detection_multiplier = bfd_info->detect_mult; | |
4affdba7 G |
177 | if (bfd_info->profile[0]) { |
178 | args.profilelen = strlen(bfd_info->profile); | |
179 | strlcpy(args.profile, bfd_info->profile, | |
180 | sizeof(args.profile)); | |
181 | } | |
6a6b1036 | 182 | } |
18322efd RZ |
183 | |
184 | addrlen = family == AF_INET ? sizeof(struct in_addr) | |
185 | : sizeof(struct in6_addr); | |
186 | memcpy(&args.dst, dst_ip, addrlen); | |
187 | if (src_ip) | |
188 | memcpy(&args.src, src_ip, addrlen); | |
189 | ||
190 | if (if_name) | |
191 | args.ifnamelen = | |
192 | strlcpy(args.ifname, if_name, sizeof(args.ifname)); | |
193 | ||
194 | zclient_bfd_command(zclient, &args); | |
7f342629 DS |
195 | } |
196 | ||
197 | /* | |
198 | * bfd_get_command_dbg_str - Convert command to a debug string. | |
199 | */ | |
d62a17ae | 200 | const char *bfd_get_command_dbg_str(int command) |
7f342629 | 201 | { |
d62a17ae | 202 | switch (command) { |
203 | case ZEBRA_BFD_DEST_REGISTER: | |
204 | return "Register"; | |
205 | case ZEBRA_BFD_DEST_DEREGISTER: | |
206 | return "Deregister"; | |
207 | case ZEBRA_BFD_DEST_UPDATE: | |
208 | return "Update"; | |
209 | default: | |
210 | return "Unknown"; | |
211 | } | |
7f342629 DS |
212 | } |
213 | ||
214 | /* | |
215 | * bfd_get_peer_info - Extract the Peer information for which the BFD session | |
216 | * went down from the message sent from Zebra to clients. | |
217 | */ | |
d62a17ae | 218 | struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, |
219 | struct prefix *sp, int *status, | |
9beff0bd | 220 | int *remote_cbit, |
d62a17ae | 221 | vrf_id_t vrf_id) |
7f342629 | 222 | { |
d62a17ae | 223 | unsigned int ifindex; |
224 | struct interface *ifp = NULL; | |
225 | int plen; | |
9beff0bd | 226 | int local_remote_cbit; |
d62a17ae | 227 | |
37a74717 DS |
228 | /* |
229 | * If the ifindex lookup fails the | |
230 | * rest of the data in the stream is | |
231 | * not read. All examples of this function | |
232 | * call immediately use the dp->family which | |
233 | * is not good. Ensure we are not using | |
234 | * random data | |
235 | */ | |
236 | memset(dp, 0, sizeof(*dp)); | |
237 | memset(sp, 0, sizeof(*sp)); | |
238 | ||
d62a17ae | 239 | /* Get interface index. */ |
240 | ifindex = stream_getl(s); | |
241 | ||
242 | /* Lookup index. */ | |
243 | if (ifindex != 0) { | |
244 | ifp = if_lookup_by_index(ifindex, vrf_id); | |
245 | if (ifp == NULL) { | |
246 | if (bfd_debug) | |
247 | zlog_debug( | |
3efd0893 | 248 | "zebra_interface_bfd_read: Can't find interface by ifindex: %d ", |
d62a17ae | 249 | ifindex); |
250 | return NULL; | |
251 | } | |
252 | } | |
253 | ||
254 | /* Fetch destination address. */ | |
255 | dp->family = stream_getc(s); | |
256 | ||
257 | plen = prefix_blen(dp); | |
258 | stream_get(&dp->u.prefix, s, plen); | |
259 | dp->prefixlen = stream_getc(s); | |
260 | ||
261 | /* Get BFD status. */ | |
262 | *status = stream_getl(s); | |
263 | ||
37a74717 DS |
264 | sp->family = stream_getc(s); |
265 | ||
266 | plen = prefix_blen(sp); | |
267 | stream_get(&sp->u.prefix, s, plen); | |
268 | sp->prefixlen = stream_getc(s); | |
d62a17ae | 269 | |
9beff0bd PG |
270 | local_remote_cbit = stream_getc(s); |
271 | if (remote_cbit) | |
272 | *remote_cbit = local_remote_cbit; | |
d62a17ae | 273 | return ifp; |
7f342629 | 274 | } |
68fe91d6 | 275 | |
276 | /* | |
277 | * bfd_get_status_str - Convert BFD status to a display string. | |
278 | */ | |
d62a17ae | 279 | const char *bfd_get_status_str(int status) |
68fe91d6 | 280 | { |
d62a17ae | 281 | switch (status) { |
282 | case BFD_STATUS_DOWN: | |
283 | return "Down"; | |
284 | case BFD_STATUS_UP: | |
285 | return "Up"; | |
7555dc61 S |
286 | case BFD_STATUS_ADMIN_DOWN: |
287 | return "Admin Down"; | |
d62a17ae | 288 | case BFD_STATUS_UNKNOWN: |
289 | default: | |
290 | return "Unknown"; | |
291 | } | |
68fe91d6 | 292 | } |
293 | ||
294 | /* | |
295 | * bfd_last_update - Calculate the last BFD update time and convert it | |
296 | * into a dd:hh:mm:ss display format. | |
297 | */ | |
d62a17ae | 298 | static void bfd_last_update(time_t last_update, char *buf, size_t len) |
68fe91d6 | 299 | { |
d62a17ae | 300 | time_t curr; |
301 | time_t diff; | |
a2700b50 | 302 | struct tm tm; |
d62a17ae | 303 | struct timeval tv; |
304 | ||
305 | /* If no BFD satatus update has ever been received, print `never'. */ | |
306 | if (last_update == 0) { | |
307 | snprintf(buf, len, "never"); | |
308 | return; | |
309 | } | |
310 | ||
311 | /* Get current time. */ | |
312 | monotime(&tv); | |
313 | curr = tv.tv_sec; | |
314 | diff = curr - last_update; | |
a2700b50 | 315 | gmtime_r(&diff, &tm); |
d62a17ae | 316 | |
a2700b50 MS |
317 | snprintf(buf, len, "%d:%02d:%02d:%02d", tm.tm_yday, tm.tm_hour, |
318 | tm.tm_min, tm.tm_sec); | |
68fe91d6 | 319 | } |
320 | ||
321 | /* | |
322 | * bfd_show_param - Show the BFD parameter information. | |
323 | */ | |
d62a17ae | 324 | void bfd_show_param(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag, |
9f049418 | 325 | int extra_space, bool use_json, json_object *json_obj) |
68fe91d6 | 326 | { |
d62a17ae | 327 | json_object *json_bfd = NULL; |
328 | ||
329 | if (!bfd_info) | |
330 | return; | |
331 | ||
332 | if (use_json) { | |
333 | if (bfd_tag) | |
334 | json_bfd = json_object_new_object(); | |
335 | else | |
336 | json_bfd = json_obj; | |
337 | ||
338 | json_object_int_add(json_bfd, "detectMultiplier", | |
339 | bfd_info->detect_mult); | |
340 | json_object_int_add(json_bfd, "rxMinInterval", | |
341 | bfd_info->required_min_rx); | |
342 | json_object_int_add(json_bfd, "txMinInterval", | |
343 | bfd_info->desired_min_tx); | |
344 | if (bfd_tag) | |
345 | json_object_object_add(json_obj, "peerBfdInfo", | |
346 | json_bfd); | |
347 | } else { | |
348 | vty_out(vty, | |
3efd0893 | 349 | " %s%sDetect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", |
d62a17ae | 350 | (extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ", |
351 | bfd_info->detect_mult, bfd_info->required_min_rx, | |
352 | bfd_info->desired_min_tx); | |
353 | } | |
68fe91d6 | 354 | } |
355 | ||
356 | /* | |
357 | * bfd_show_status - Show the BFD status information. | |
358 | */ | |
d62a17ae | 359 | static void bfd_show_status(struct vty *vty, struct bfd_info *bfd_info, |
9f049418 | 360 | int bfd_tag, int extra_space, bool use_json, |
d62a17ae | 361 | json_object *json_bfd) |
68fe91d6 | 362 | { |
d62a17ae | 363 | char time_buf[32]; |
364 | ||
365 | if (!bfd_info) | |
366 | return; | |
367 | ||
368 | bfd_last_update(bfd_info->last_update, time_buf, 32); | |
369 | if (use_json) { | |
370 | json_object_string_add(json_bfd, "status", | |
371 | bfd_get_status_str(bfd_info->status)); | |
372 | json_object_string_add(json_bfd, "lastUpdate", time_buf); | |
373 | } else { | |
374 | vty_out(vty, " %s%sStatus: %s, Last update: %s\n", | |
375 | (extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ", | |
376 | bfd_get_status_str(bfd_info->status), time_buf); | |
377 | } | |
68fe91d6 | 378 | } |
379 | ||
380 | /* | |
381 | * bfd_show_info - Show the BFD information. | |
382 | */ | |
d62a17ae | 383 | void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop, |
9f049418 | 384 | int extra_space, bool use_json, json_object *json_obj) |
68fe91d6 | 385 | { |
d62a17ae | 386 | json_object *json_bfd = NULL; |
387 | ||
388 | if (!bfd_info) | |
389 | return; | |
390 | ||
391 | if (use_json) { | |
392 | json_bfd = json_object_new_object(); | |
393 | if (multihop) | |
394 | json_object_string_add(json_bfd, "type", "multi hop"); | |
395 | else | |
396 | json_object_string_add(json_bfd, "type", "single hop"); | |
397 | } else { | |
398 | vty_out(vty, " %sBFD: Type: %s\n", (extra_space) ? " " : "", | |
399 | (multihop) ? "multi hop" : "single hop"); | |
400 | } | |
401 | ||
402 | bfd_show_param(vty, bfd_info, 0, extra_space, use_json, json_bfd); | |
403 | bfd_show_status(vty, bfd_info, 0, extra_space, use_json, json_bfd); | |
404 | ||
405 | if (use_json) | |
406 | json_object_object_add(json_obj, "peerBfdInfo", json_bfd); | |
407 | else | |
408 | vty_out(vty, "\n"); | |
68fe91d6 | 409 | } |
055c4dfc | 410 | |
411 | /* | |
412 | * bfd_client_sendmsg - Format and send a client register | |
413 | * command to Zebra to be forwarded to BFD | |
414 | */ | |
0945d5ed PG |
415 | void bfd_client_sendmsg(struct zclient *zclient, int command, |
416 | vrf_id_t vrf_id) | |
055c4dfc | 417 | { |
d62a17ae | 418 | struct stream *s; |
8a3f8f2e | 419 | enum zclient_send_status ret; |
d62a17ae | 420 | |
421 | /* Check socket. */ | |
422 | if (!zclient || zclient->sock < 0) { | |
423 | if (bfd_debug) | |
424 | zlog_debug( | |
3efd0893 | 425 | "%s: Can't send BFD client register, Zebra client not established", |
15569c58 | 426 | __func__); |
d62a17ae | 427 | return; |
428 | } | |
429 | ||
430 | s = zclient->obuf; | |
431 | stream_reset(s); | |
0945d5ed | 432 | zclient_create_header(s, command, vrf_id); |
d62a17ae | 433 | |
434 | stream_putl(s, getpid()); | |
435 | ||
436 | stream_putw_at(s, 0, stream_get_endp(s)); | |
437 | ||
438 | ret = zclient_send_message(zclient); | |
439 | ||
8a3f8f2e | 440 | if (ret == ZCLIENT_SEND_FAILURE) { |
d62a17ae | 441 | if (bfd_debug) |
442 | zlog_debug( | |
443 | "bfd_client_sendmsg %ld: zclient_send_message() failed", | |
444 | (long)getpid()); | |
445 | return; | |
446 | } | |
447 | ||
448 | return; | |
055c4dfc | 449 | } |
18322efd RZ |
450 | |
451 | int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) | |
452 | { | |
453 | struct stream *s; | |
454 | size_t addrlen; | |
455 | ||
bb99eb5d G |
456 | /* Individual reg/dereg messages are suppressed during shutdown. */ |
457 | if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) { | |
458 | if (bfd_debug) | |
459 | zlog_debug( | |
460 | "%s: Suppressing BFD peer reg/dereg messages", | |
461 | __func__); | |
462 | return -1; | |
463 | } | |
464 | ||
18322efd RZ |
465 | /* Check socket. */ |
466 | if (!zc || zc->sock < 0) { | |
467 | if (bfd_debug) | |
468 | zlog_debug("%s: zclient unavailable", __func__); | |
469 | return -1; | |
470 | } | |
471 | ||
472 | s = zc->obuf; | |
473 | stream_reset(s); | |
474 | ||
475 | /* Create new message. */ | |
476 | zclient_create_header(s, args->command, args->vrf_id); | |
477 | stream_putl(s, getpid()); | |
478 | ||
479 | /* Encode destination address. */ | |
480 | stream_putw(s, args->family); | |
481 | addrlen = (args->family == AF_INET) ? sizeof(struct in_addr) | |
482 | : sizeof(struct in6_addr); | |
483 | stream_put(s, &args->dst, addrlen); | |
484 | ||
4b983eef RZ |
485 | /* |
486 | * For more BFD integration protocol details, see function | |
487 | * `_ptm_msg_read` in `bfdd/ptm_adapter.c`. | |
488 | */ | |
489 | #if HAVE_BFDD > 0 | |
490 | /* Session timers. */ | |
491 | stream_putl(s, args->min_rx); | |
492 | stream_putl(s, args->min_tx); | |
493 | stream_putc(s, args->detection_multiplier); | |
494 | ||
495 | /* Is multi hop? */ | |
496 | stream_putc(s, args->mhop != 0); | |
497 | ||
498 | /* Source address. */ | |
499 | stream_putw(s, args->family); | |
500 | stream_put(s, &args->src, addrlen); | |
501 | ||
502 | /* Send the expected TTL. */ | |
503 | stream_putc(s, args->ttl); | |
504 | ||
505 | /* Send interface name if any. */ | |
506 | stream_putc(s, args->ifnamelen); | |
507 | if (args->ifnamelen) | |
508 | stream_put(s, args->ifname, args->ifnamelen); | |
509 | ||
510 | /* Send the C bit indicator. */ | |
511 | stream_putc(s, args->cbit); | |
512 | ||
513 | /* Send profile name if any. */ | |
514 | stream_putc(s, args->profilelen); | |
515 | if (args->profilelen) | |
516 | stream_put(s, args->profile, args->profilelen); | |
517 | #else /* PTM BFD */ | |
18322efd RZ |
518 | /* Encode timers if this is a registration message. */ |
519 | if (args->command != ZEBRA_BFD_DEST_DEREGISTER) { | |
520 | stream_putl(s, args->min_rx); | |
521 | stream_putl(s, args->min_tx); | |
522 | stream_putc(s, args->detection_multiplier); | |
523 | } | |
524 | ||
525 | if (args->mhop) { | |
526 | /* Multi hop indicator. */ | |
527 | stream_putc(s, 1); | |
528 | ||
529 | /* Multi hop always sends the source address. */ | |
530 | stream_putw(s, args->family); | |
531 | stream_put(s, &args->src, addrlen); | |
532 | ||
533 | /* Send the expected TTL. */ | |
534 | stream_putc(s, args->ttl); | |
535 | } else { | |
536 | /* Multi hop indicator. */ | |
537 | stream_putc(s, 0); | |
538 | ||
539 | /* Single hop only sends the source address when IPv6. */ | |
540 | if (args->family == AF_INET6) { | |
541 | stream_putw(s, args->family); | |
542 | stream_put(s, &args->src, addrlen); | |
543 | } | |
544 | ||
545 | /* Send interface name if any. */ | |
546 | stream_putc(s, args->ifnamelen); | |
547 | if (args->ifnamelen) | |
548 | stream_put(s, args->ifname, args->ifnamelen); | |
549 | } | |
18322efd RZ |
550 | #endif /* HAVE_BFDD */ |
551 | ||
552 | /* Finish the message by writing the size. */ | |
553 | stream_putw_at(s, 0, stream_get_endp(s)); | |
554 | ||
555 | /* Send message to zebra. */ | |
8a3f8f2e | 556 | if (zclient_send_message(zc) == ZCLIENT_SEND_FAILURE) { |
18322efd RZ |
557 | if (bfd_debug) |
558 | zlog_debug("%s: zclient_send_message failed", __func__); | |
559 | return -1; | |
560 | } | |
561 | ||
562 | /* Write registration indicator into data structure. */ | |
6a6b1036 | 563 | if (args->bfd_info && args->set_flag) { |
18322efd RZ |
564 | if (args->command == ZEBRA_BFD_DEST_REGISTER) |
565 | SET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG); | |
566 | else if (args->command == ZEBRA_BFD_DEST_DEREGISTER) | |
567 | UNSET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG); | |
568 | } | |
569 | ||
570 | return 0; | |
571 | } | |
a099abe5 RZ |
572 | |
573 | /** | |
574 | * BFD protocol integration configuration. | |
575 | */ | |
576 | ||
577 | /** Events definitions. */ | |
578 | enum bfd_session_event { | |
579 | /** Remove the BFD session configuration. */ | |
580 | BSE_UNINSTALL, | |
581 | /** Install the BFD session configuration. */ | |
582 | BSE_INSTALL, | |
583 | }; | |
584 | ||
585 | /** | |
586 | * Data structure to do the necessary tricks to hide the BFD protocol | |
587 | * integration internals. | |
588 | */ | |
589 | struct bfd_session_params { | |
590 | /** Contains the session parameters and more. */ | |
591 | struct bfd_session_arg args; | |
592 | /** Contains the session state. */ | |
593 | struct bfd_session_status bss; | |
594 | /** Protocol implementation status update callback. */ | |
595 | bsp_status_update updatecb; | |
596 | /** Protocol implementation custom data pointer. */ | |
597 | void *arg; | |
598 | ||
599 | /** | |
600 | * Next event. | |
601 | * | |
602 | * This variable controls what action to execute when the command batch | |
603 | * finishes. Normally we'd use `thread_add_event` value, however since | |
604 | * that function is going to be called multiple times and the value | |
605 | * might be different we'll use this variable to keep track of it. | |
606 | */ | |
607 | enum bfd_session_event lastev; | |
608 | /** | |
609 | * BFD session configuration event. | |
610 | * | |
611 | * Multiple actions might be asked during a command batch (either via | |
612 | * configuration load or northbound batch), so we'll use this to | |
613 | * install/uninstall the BFD session parameters only once. | |
614 | */ | |
615 | struct thread *installev; | |
616 | ||
617 | /** BFD session installation state. */ | |
618 | bool installed; | |
619 | /** BFD session enabled. */ | |
620 | bool enabled; | |
621 | ||
622 | /** Global BFD paramaters list. */ | |
623 | TAILQ_ENTRY(bfd_session_params) entry; | |
624 | }; | |
625 | ||
626 | struct bfd_sessions_global { | |
627 | /** | |
628 | * Global BFD session parameters list for (re)installation and update | |
629 | * without code duplication among daemons. | |
630 | */ | |
631 | TAILQ_HEAD(bsplist, bfd_session_params) bsplist; | |
632 | ||
633 | /** Pointer to FRR's event manager. */ | |
634 | struct thread_master *tm; | |
635 | /** Pointer to zebra client data structure. */ | |
636 | struct zclient *zc; | |
637 | ||
638 | /** Debugging state. */ | |
639 | bool debugging; | |
640 | /** Is shutting down? */ | |
641 | bool shutting_down; | |
642 | }; | |
643 | ||
644 | /** Global configuration variable. */ | |
645 | static struct bfd_sessions_global bsglobal; | |
646 | ||
647 | /** Global empty address for IPv4/IPv6. */ | |
648 | static const struct in6_addr i6a_zero; | |
649 | ||
650 | struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *arg) | |
651 | { | |
652 | struct bfd_session_params *bsp; | |
653 | ||
654 | bsp = XCALLOC(MTYPE_BFD_INFO, sizeof(*bsp)); | |
655 | ||
656 | /* Save application data. */ | |
657 | bsp->updatecb = updatecb; | |
658 | bsp->arg = arg; | |
659 | ||
660 | /* Set defaults. */ | |
661 | bsp->args.detection_multiplier = BFD_DEF_DETECT_MULT; | |
662 | bsp->args.ttl = BFD_SINGLE_HOP_TTL; | |
663 | bsp->args.min_rx = BFD_DEF_MIN_RX; | |
664 | bsp->args.min_tx = BFD_DEF_MIN_TX; | |
665 | bsp->args.vrf_id = VRF_DEFAULT; | |
666 | ||
667 | /* Register in global list. */ | |
668 | TAILQ_INSERT_TAIL(&bsglobal.bsplist, bsp, entry); | |
669 | ||
670 | return bsp; | |
671 | } | |
672 | ||
673 | static bool _bfd_sess_valid(const struct bfd_session_params *bsp) | |
674 | { | |
675 | /* Peer/local address not configured. */ | |
676 | if (bsp->args.family == 0) | |
677 | return false; | |
678 | ||
679 | /* Address configured but invalid. */ | |
680 | if (bsp->args.family != AF_INET && bsp->args.family != AF_INET6) { | |
681 | if (bsglobal.debugging) | |
682 | zlog_debug("%s: invalid session family: %d", __func__, | |
683 | bsp->args.family); | |
684 | return false; | |
685 | } | |
686 | ||
687 | /* Invalid address. */ | |
688 | if (memcmp(&bsp->args.dst, &i6a_zero, sizeof(i6a_zero)) == 0) { | |
689 | if (bsglobal.debugging) { | |
690 | if (bsp->args.family == AF_INET) | |
691 | zlog_debug("%s: invalid address: %pI4", | |
692 | __func__, | |
693 | (struct in_addr *)&bsp->args.dst); | |
694 | else | |
695 | zlog_debug("%s: invalid address: %pI6", | |
696 | __func__, &bsp->args.dst); | |
697 | } | |
698 | return false; | |
699 | } | |
700 | ||
701 | /* Multi hop requires local address. */ | |
702 | if (bsp->args.mhop | |
703 | && memcmp(&i6a_zero, &bsp->args.src, sizeof(i6a_zero)) == 0) { | |
704 | if (bsglobal.debugging) | |
705 | zlog_debug( | |
706 | "%s: multi hop but no local address provided", | |
707 | __func__); | |
708 | return false; | |
709 | } | |
710 | ||
711 | /* Check VRF ID. */ | |
712 | if (bsp->args.vrf_id == VRF_UNKNOWN) { | |
713 | if (bsglobal.debugging) | |
714 | zlog_debug("%s: asked for unknown VRF", __func__); | |
715 | return false; | |
716 | } | |
717 | ||
718 | return true; | |
719 | } | |
720 | ||
721 | static int _bfd_sess_send(struct thread *t) | |
722 | { | |
723 | struct bfd_session_params *bsp = THREAD_ARG(t); | |
724 | int rv; | |
725 | ||
726 | /* Validate configuration before trying to send bogus data. */ | |
727 | if (!_bfd_sess_valid(bsp)) | |
728 | return 0; | |
729 | ||
730 | if (bsp->lastev == BSE_INSTALL) { | |
731 | bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE | |
732 | : ZEBRA_BFD_DEST_REGISTER; | |
733 | } else | |
734 | bsp->args.command = ZEBRA_BFD_DEST_DEREGISTER; | |
735 | ||
736 | /* If not installed and asked for uninstall, do nothing. */ | |
737 | if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER) | |
738 | return 0; | |
739 | ||
740 | rv = zclient_bfd_command(bsglobal.zc, &bsp->args); | |
741 | /* Command was sent successfully. */ | |
742 | if (rv == 0) { | |
743 | /* Update installation status. */ | |
744 | if (bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER) | |
745 | bsp->installed = false; | |
746 | else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER) | |
747 | bsp->installed = true; | |
748 | } | |
749 | ||
750 | return 0; | |
751 | } | |
752 | ||
753 | static void _bfd_sess_remove(struct bfd_session_params *bsp) | |
754 | { | |
755 | /* Not installed, nothing to do. */ | |
756 | if (!bsp->installed) | |
757 | return; | |
758 | ||
759 | /* Cancel any pending installation request. */ | |
760 | THREAD_OFF(bsp->installev); | |
761 | ||
762 | /* Send request to remove any session. */ | |
763 | bsp->lastev = BSE_UNINSTALL; | |
764 | thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0); | |
765 | } | |
766 | ||
767 | void bfd_sess_free(struct bfd_session_params **bsp) | |
768 | { | |
769 | if (*bsp == NULL) | |
770 | return; | |
771 | ||
772 | /* Remove any installed session. */ | |
773 | _bfd_sess_remove(*bsp); | |
774 | ||
775 | /* Remove from global list. */ | |
776 | TAILQ_REMOVE(&bsglobal.bsplist, (*bsp), entry); | |
777 | ||
778 | /* Free the memory and point to NULL. */ | |
779 | XFREE(MTYPE_BFD_INFO, (*bsp)); | |
780 | } | |
781 | ||
782 | void bfd_sess_enable(struct bfd_session_params *bsp, bool enable) | |
783 | { | |
784 | /* Remove the session when disabling. */ | |
785 | if (!enable) | |
786 | _bfd_sess_remove(bsp); | |
787 | ||
788 | bsp->enabled = enable; | |
789 | } | |
790 | ||
791 | void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, | |
792 | struct in_addr *src, struct in_addr *dst) | |
793 | { | |
794 | /* If already installed, remove the old setting. */ | |
795 | _bfd_sess_remove(bsp); | |
796 | ||
797 | bsp->args.family = AF_INET; | |
798 | ||
799 | /* Clean memory, set zero value and avoid static analyser warnings. */ | |
800 | memset(&bsp->args.src, 0, sizeof(bsp->args.src)); | |
801 | memset(&bsp->args.dst, 0, sizeof(bsp->args.dst)); | |
802 | ||
803 | /* Copy the equivalent of IPv4 to arguments structure. */ | |
804 | if (src) | |
805 | memcpy(&bsp->args.src, src, sizeof(struct in_addr)); | |
806 | ||
807 | assert(dst); | |
808 | memcpy(&bsp->args.dst, dst, sizeof(struct in_addr)); | |
809 | } | |
810 | ||
811 | void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, | |
812 | struct in6_addr *src, struct in6_addr *dst) | |
813 | { | |
814 | /* If already installed, remove the old setting. */ | |
815 | _bfd_sess_remove(bsp); | |
816 | ||
817 | bsp->args.family = AF_INET6; | |
818 | ||
819 | /* Clean memory, set zero value and avoid static analyser warnings. */ | |
820 | memset(&bsp->args.src, 0, sizeof(bsp->args.src)); | |
821 | ||
822 | if (src) | |
823 | bsp->args.src = *src; | |
824 | ||
825 | assert(dst); | |
826 | bsp->args.dst = *dst; | |
827 | } | |
828 | ||
829 | void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname) | |
830 | { | |
831 | /* If already installed, remove the old setting. */ | |
832 | _bfd_sess_remove(bsp); | |
833 | ||
834 | if (ifname == NULL) { | |
835 | bsp->args.ifname[0] = 0; | |
836 | bsp->args.ifnamelen = 0; | |
837 | return; | |
838 | } | |
839 | ||
840 | if (strlcpy(bsp->args.ifname, ifname, sizeof(bsp->args.ifname)) | |
841 | > sizeof(bsp->args.ifname)) | |
842 | zlog_warn("%s: interface name truncated: %s", __func__, ifname); | |
843 | ||
844 | bsp->args.ifnamelen = strlen(bsp->args.ifname); | |
845 | } | |
846 | ||
847 | void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile) | |
848 | { | |
849 | if (profile == NULL) { | |
850 | bsp->args.profile[0] = 0; | |
851 | bsp->args.profilelen = 0; | |
852 | return; | |
853 | } | |
854 | ||
855 | if (strlcpy(bsp->args.profile, profile, sizeof(bsp->args.profile)) | |
856 | > sizeof(bsp->args.profile)) | |
857 | zlog_warn("%s: profile name truncated: %s", __func__, profile); | |
858 | ||
859 | bsp->args.profilelen = strlen(bsp->args.profile); | |
860 | } | |
861 | ||
862 | void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id) | |
863 | { | |
864 | /* If already installed, remove the old setting. */ | |
865 | _bfd_sess_remove(bsp); | |
866 | ||
867 | bsp->args.vrf_id = vrf_id; | |
868 | } | |
869 | ||
870 | void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl) | |
871 | { | |
872 | assert(min_ttl != 0); | |
873 | ||
874 | /* If already installed, remove the old setting. */ | |
875 | _bfd_sess_remove(bsp); | |
876 | ||
877 | /* Invert TTL value: protocol expects number of hops. */ | |
878 | min_ttl = (BFD_SINGLE_HOP_TTL + 1) - min_ttl; | |
879 | bsp->args.ttl = min_ttl; | |
880 | bsp->args.mhop = (min_ttl > 1); | |
881 | } | |
882 | ||
883 | void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl) | |
884 | { | |
885 | /* If already installed, remove the old setting. */ | |
886 | _bfd_sess_remove(bsp); | |
887 | ||
888 | bsp->args.ttl = min_ttl; | |
889 | bsp->args.mhop = (min_ttl > 1); | |
890 | } | |
891 | ||
892 | ||
893 | void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable) | |
894 | { | |
895 | bsp->args.cbit = enable; | |
896 | } | |
897 | ||
898 | void bfd_sess_set_timers(struct bfd_session_params *bsp, | |
899 | uint8_t detection_multiplier, uint32_t min_rx, | |
900 | uint32_t min_tx) | |
901 | { | |
902 | bsp->args.detection_multiplier = detection_multiplier; | |
903 | bsp->args.min_rx = min_rx; | |
904 | bsp->args.min_tx = min_tx; | |
905 | } | |
906 | ||
907 | void bfd_sess_install(struct bfd_session_params *bsp) | |
908 | { | |
909 | /* Don't attempt to install/update when disabled. */ | |
910 | if (!bsp->enabled) | |
911 | return; | |
912 | ||
913 | bsp->lastev = BSE_INSTALL; | |
914 | thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); | |
915 | } | |
916 | ||
917 | void bfd_sess_uninstall(struct bfd_session_params *bsp) | |
918 | { | |
919 | bsp->lastev = BSE_UNINSTALL; | |
920 | thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); | |
921 | } | |
922 | ||
923 | enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp) | |
924 | { | |
925 | return bsp->bss.state; | |
926 | } | |
927 | ||
928 | uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp) | |
929 | { | |
930 | return ((BFD_SINGLE_HOP_TTL + 1) - bsp->args.ttl); | |
931 | } | |
932 | ||
933 | uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp) | |
934 | { | |
935 | return bsp->args.ttl; | |
936 | } | |
937 | ||
938 | const char *bfd_sess_profile(const struct bfd_session_params *bsp) | |
939 | { | |
940 | return bsp->args.profilelen ? bsp->args.profile : NULL; | |
941 | } | |
942 | ||
943 | void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family, | |
944 | struct in6_addr *src, struct in6_addr *dst) | |
945 | { | |
946 | *family = bsp->args.family; | |
947 | if (src) | |
948 | *src = bsp->args.src; | |
949 | if (dst) | |
950 | *dst = bsp->args.dst; | |
951 | } | |
952 | ||
953 | const char *bfd_sess_interface(const struct bfd_session_params *bsp) | |
954 | { | |
955 | if (bsp->args.ifnamelen) | |
956 | return bsp->args.ifname; | |
957 | ||
958 | return NULL; | |
959 | } | |
960 | ||
961 | const char *bfd_sess_vrf(const struct bfd_session_params *bsp) | |
962 | { | |
963 | return vrf_id_to_name(bsp->args.vrf_id); | |
964 | } | |
965 | ||
966 | vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp) | |
967 | { | |
968 | return bsp->args.vrf_id; | |
969 | } | |
970 | ||
971 | bool bfd_sess_cbit(const struct bfd_session_params *bsp) | |
972 | { | |
973 | return bsp->args.cbit; | |
974 | } | |
975 | ||
976 | void bfd_sess_timers(const struct bfd_session_params *bsp, | |
977 | uint8_t *detection_multiplier, uint32_t *min_rx, | |
978 | uint32_t *min_tx) | |
979 | { | |
980 | *detection_multiplier = bsp->args.detection_multiplier; | |
981 | *min_rx = bsp->args.min_rx; | |
982 | *min_tx = bsp->args.min_tx; | |
983 | } | |
984 | ||
985 | void bfd_sess_show(struct vty *vty, struct json_object *json, | |
986 | struct bfd_session_params *bsp) | |
987 | { | |
988 | json_object *json_bfd = NULL; | |
989 | char time_buf[64]; | |
990 | ||
991 | /* Show type. */ | |
992 | if (json) { | |
993 | json_bfd = json_object_new_object(); | |
994 | if (bsp->args.mhop) | |
995 | json_object_string_add(json_bfd, "type", "multi hop"); | |
996 | else | |
997 | json_object_string_add(json_bfd, "type", "single hop"); | |
998 | } else | |
999 | vty_out(vty, " BFD: Type: %s\n", | |
1000 | bsp->args.mhop ? "multi hop" : "single hop"); | |
1001 | ||
1002 | /* Show configuration. */ | |
1003 | if (json) { | |
1004 | json_object_int_add(json_bfd, "detectMultiplier", | |
1005 | bsp->args.detection_multiplier); | |
1006 | json_object_int_add(json_bfd, "rxMinInterval", | |
1007 | bsp->args.min_rx); | |
1008 | json_object_int_add(json_bfd, "txMinInterval", | |
1009 | bsp->args.min_tx); | |
1010 | } else { | |
1011 | vty_out(vty, | |
1012 | " Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", | |
1013 | bsp->args.detection_multiplier, bsp->args.min_rx, | |
1014 | bsp->args.min_tx); | |
1015 | } | |
1016 | ||
1017 | bfd_last_update(bsp->bss.last_event, time_buf, sizeof(time_buf)); | |
1018 | if (json) { | |
1019 | json_object_string_add(json_bfd, "status", | |
1020 | bfd_get_status_str(bsp->bss.state)); | |
1021 | json_object_string_add(json_bfd, "lastUpdate", time_buf); | |
1022 | } else | |
1023 | vty_out(vty, " Status: %s, Last update: %s\n", | |
1024 | bfd_get_status_str(bsp->bss.state), time_buf); | |
1025 | ||
1026 | if (json) | |
1027 | json_object_object_add(json, "peerBfdInfo", json_bfd); | |
1028 | else | |
1029 | vty_out(vty, "\n"); | |
1030 | } | |
1031 | ||
1032 | /* | |
1033 | * Zebra communication related. | |
1034 | */ | |
1035 | ||
1036 | /** | |
1037 | * Callback for reinstallation of all registered BFD sessions. | |
1038 | * | |
1039 | * Use this as `zclient` `bfd_dest_replay` callback. | |
1040 | */ | |
1041 | static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS) | |
1042 | { | |
1043 | struct bfd_session_params *bsp; | |
1044 | ||
1045 | /* Do nothing when shutting down. */ | |
1046 | if (bsglobal.shutting_down) | |
1047 | return 0; | |
1048 | ||
1049 | if (bsglobal.debugging) | |
1050 | zlog_debug("%s: sending all sessions registered", __func__); | |
1051 | ||
1052 | /* Send the client registration */ | |
1053 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); | |
1054 | ||
1055 | /* Replay all activated peers. */ | |
1056 | TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { | |
1057 | /* Skip disabled sessions. */ | |
1058 | if (!bsp->enabled) | |
1059 | continue; | |
1060 | ||
1061 | /* We are reconnecting, so we must send installation. */ | |
1062 | bsp->installed = false; | |
1063 | ||
1064 | /* Cancel any pending installation request. */ | |
1065 | THREAD_OFF(bsp->installev); | |
1066 | ||
1067 | /* Ask for installation. */ | |
1068 | bsp->lastev = BSE_INSTALL; | |
1069 | thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0); | |
1070 | } | |
1071 | ||
1072 | return 0; | |
1073 | } | |
1074 | ||
1075 | static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) | |
1076 | { | |
1077 | struct bfd_session_params *bsp; | |
1078 | size_t sessions_updated = 0; | |
1079 | struct interface *ifp; | |
1080 | int remote_cbit = false; | |
1081 | int state = BFD_STATUS_UNKNOWN; | |
3e6376b8 | 1082 | time_t now; |
a099abe5 RZ |
1083 | size_t addrlen; |
1084 | struct prefix dp; | |
1085 | struct prefix sp; | |
1086 | char ifstr[128], cbitstr[32]; | |
1087 | ||
1088 | /* Do nothing when shutting down. */ | |
1089 | if (bsglobal.shutting_down) | |
1090 | return 0; | |
1091 | ||
1092 | ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit, | |
1093 | vrf_id); | |
1094 | ||
1095 | if (bsglobal.debugging) { | |
1096 | ifstr[0] = 0; | |
1097 | if (ifp) | |
1098 | snprintf(ifstr, sizeof(ifstr), " (interface %s)", | |
1099 | ifp->name); | |
1100 | ||
1101 | snprintf(cbitstr, sizeof(cbitstr), " (CPI bit %s)", | |
1102 | remote_cbit ? "yes" : "no"); | |
1103 | ||
1104 | zlog_debug("%s: %pFX -> %pFX%s VRF %s(%u)%s: %s", __func__, &sp, | |
1105 | &dp, ifstr, vrf_id_to_name(vrf_id), vrf_id, cbitstr, | |
1106 | bfd_get_status_str(state)); | |
1107 | } | |
1108 | ||
1109 | switch (dp.family) { | |
1110 | case AF_INET: | |
1111 | addrlen = sizeof(struct in_addr); | |
1112 | break; | |
1113 | case AF_INET6: | |
1114 | addrlen = sizeof(struct in6_addr); | |
1115 | break; | |
1116 | ||
1117 | default: | |
1118 | /* Unexpected value. */ | |
1119 | assert(0); | |
1120 | break; | |
1121 | } | |
1122 | ||
3e6376b8 RZ |
1123 | /* Cache current time to avoid multiple monotime clock calls. */ |
1124 | now = monotime(NULL); | |
1125 | ||
a099abe5 RZ |
1126 | /* Notify all matching sessions about update. */ |
1127 | TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { | |
1128 | /* Skip disabled or not installed entries. */ | |
1129 | if (!bsp->enabled || !bsp->installed) | |
1130 | continue; | |
1131 | /* Skip different VRFs. */ | |
1132 | if (bsp->args.vrf_id != vrf_id) | |
1133 | continue; | |
1134 | /* Skip different families. */ | |
1135 | if (bsp->args.family != dp.family) | |
1136 | continue; | |
1137 | /* Skip different interface. */ | |
1138 | if (bsp->args.ifnamelen && ifp | |
1139 | && strcmp(bsp->args.ifname, ifp->name) != 0) | |
1140 | continue; | |
1141 | /* Skip non matching destination addresses. */ | |
1142 | if (memcmp(&bsp->args.dst, &dp.u, addrlen) != 0) | |
1143 | continue; | |
1144 | /* | |
1145 | * Source comparison test: | |
1146 | * We will only compare source if BFD daemon provided the | |
1147 | * source address and the protocol set a source address in | |
1148 | * the configuration otherwise we'll just skip it. | |
1149 | */ | |
1150 | if (sp.family && memcmp(&bsp->args.src, &i6a_zero, addrlen) != 0 | |
1151 | && memcmp(&sp.u, &i6a_zero, addrlen) != 0 | |
1152 | && memcmp(&bsp->args.src, &sp.u, addrlen) != 0) | |
1153 | continue; | |
1154 | /* No session state change. */ | |
1155 | if ((int)bsp->bss.state == state) | |
1156 | continue; | |
1157 | ||
3e6376b8 | 1158 | bsp->bss.last_event = now; |
a099abe5 RZ |
1159 | bsp->bss.previous_state = bsp->bss.state; |
1160 | bsp->bss.state = state; | |
1161 | bsp->bss.remote_cbit = remote_cbit; | |
1162 | bsp->updatecb(bsp, &bsp->bss, bsp->arg); | |
1163 | sessions_updated++; | |
1164 | } | |
1165 | ||
1166 | if (bsglobal.debugging) | |
1167 | zlog_debug("%s: sessions updated: %zu", __func__, | |
1168 | sessions_updated); | |
1169 | ||
1170 | return 0; | |
1171 | } | |
1172 | ||
1173 | void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm) | |
1174 | { | |
1175 | /* Initialize data structure. */ | |
1176 | TAILQ_INIT(&bsglobal.bsplist); | |
1177 | ||
1178 | /* Copy pointers. */ | |
1179 | bsglobal.zc = zc; | |
1180 | bsglobal.tm = tm; | |
1181 | ||
1182 | /* Install our callbacks. */ | |
1183 | zc->interface_bfd_dest_update = zclient_bfd_session_update; | |
1184 | zc->bfd_dest_replay = zclient_bfd_session_reply; | |
1185 | ||
1186 | /* Send the client registration */ | |
1187 | bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); | |
1188 | } | |
1189 | ||
1190 | void bfd_protocol_integration_set_debug(bool enable) | |
1191 | { | |
1192 | bsglobal.debugging = enable; | |
1193 | } | |
1194 | ||
1195 | void bfd_protocol_integration_set_shutdown(bool enable) | |
1196 | { | |
1197 | bsglobal.shutting_down = enable; | |
1198 | } | |
1199 | ||
1200 | bool bfd_protocol_integration_debug(void) | |
1201 | { | |
1202 | return bsglobal.debugging; | |
1203 | } | |
1204 | ||
1205 | bool bfd_protocol_integration_shutting_down(void) | |
1206 | { | |
1207 | return bsglobal.shutting_down; | |
1208 | } |