]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/ptm_adapter.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / bfdd / ptm_adapter.c
1 /*
2 * BFD PTM adapter code
3 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
4 *
5 * FRR is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2, or (at your option) any
8 * later version.
9 *
10 * FRR is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with FRR; see the file COPYING. If not, write to the Free
17 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 */
20
21 #include <zebra.h>
22
23 #include "lib/libfrr.h"
24 #include "lib/queue.h"
25 #include "lib/stream.h"
26 #include "lib/zclient.h"
27 #include "lib/printfrr.h"
28
29 #include "lib/bfd.h"
30
31 #include "bfd.h"
32
33 /*
34 * Data structures
35 */
36 struct ptm_client_notification {
37 struct bfd_session *pcn_bs;
38 struct ptm_client *pcn_pc;
39
40 TAILQ_ENTRY(ptm_client_notification) pcn_entry;
41 };
42 TAILQ_HEAD(pcnqueue, ptm_client_notification);
43
44 struct ptm_client {
45 uint32_t pc_pid;
46 struct pcnqueue pc_pcnqueue;
47
48 TAILQ_ENTRY(ptm_client) pc_entry;
49 };
50 TAILQ_HEAD(pcqueue, ptm_client);
51
52 static struct pcqueue pcqueue;
53 static struct zclient *zclient;
54
55
56 /*
57 * Prototypes
58 */
59 static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
60
61 static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
62 static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
63 struct bfd_peer_cfg *bpc, struct ptm_client **pc);
64
65 static struct ptm_client *pc_lookup(uint32_t pid);
66 static struct ptm_client *pc_new(uint32_t pid);
67 static void pc_free(struct ptm_client *pc);
68 static void pc_free_all(void);
69 static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
70 struct bfd_session *bs);
71 static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
72 struct bfd_session *bs);
73 static void pcn_free(struct ptm_client_notification *pcn);
74
75
76 static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id);
77 static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id);
78 static void bfdd_client_register(struct stream *msg);
79 static void bfdd_client_deregister(struct stream *msg);
80
81 /*
82 * Functions
83 */
84 PRINTFRR(2, 3)
85 static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...)
86 {
87 char timers[3][128] = {};
88 char minttl_str[32] = {};
89 char addr[3][128] = {};
90 char profile[128] = {};
91 char cbit_str[32];
92 char msgbuf[512];
93 va_list vl;
94
95 /* Avoid debug calculations if it's disabled. */
96 if (bglobal.debug_zebra == false)
97 return;
98
99 snprintf(addr[0], sizeof(addr[0]), "peer:%s", satostr(&bpc->bpc_peer));
100 if (bpc->bpc_local.sa_sin.sin_family)
101 snprintf(addr[1], sizeof(addr[1]), " local:%s",
102 satostr(&bpc->bpc_local));
103
104 if (bpc->bpc_has_localif)
105 snprintf(addr[2], sizeof(addr[2]), " ifname:%s",
106 bpc->bpc_localif);
107
108 if (bpc->bpc_has_vrfname)
109 snprintf(addr[2], sizeof(addr[2]), " vrf:%s", bpc->bpc_vrfname);
110
111 if (bpc->bpc_has_recvinterval)
112 snprintfrr(timers[0], sizeof(timers[0]), " rx:%" PRIu64,
113 bpc->bpc_recvinterval);
114
115 if (bpc->bpc_has_txinterval)
116 snprintfrr(timers[1], sizeof(timers[1]), " tx:%" PRIu64,
117 bpc->bpc_recvinterval);
118
119 if (bpc->bpc_has_detectmultiplier)
120 snprintf(timers[2], sizeof(timers[2]), " detect-multiplier:%d",
121 bpc->bpc_detectmultiplier);
122
123 snprintf(cbit_str, sizeof(cbit_str), " cbit:0x%02x", bpc->bpc_cbit);
124
125 if (bpc->bpc_has_minimum_ttl)
126 snprintf(minttl_str, sizeof(minttl_str), " minimum-ttl:%d",
127 bpc->bpc_minimum_ttl);
128
129 if (bpc->bpc_has_profile)
130 snprintf(profile, sizeof(profile), " profile:%s",
131 bpc->bpc_profile);
132
133 va_start(vl, fmt);
134 vsnprintf(msgbuf, sizeof(msgbuf), fmt, vl);
135 va_end(vl);
136
137 zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s%s%s]", msgbuf,
138 bpc->bpc_mhop ? "yes" : "no", addr[0], addr[1], addr[2],
139 timers[0], timers[1], timers[2], cbit_str, minttl_str,
140 profile);
141 }
142
143 static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag)
144 {
145 if (bglobal.debug_peer_event)
146 zlog_debug("session-delete: %s", bs_to_string(bs));
147
148 /* Change state and notify peer. */
149 bs->ses_state = PTM_BFD_DOWN;
150 bs->local_diag = diag;
151 ptm_bfd_snd(bs, 0);
152
153 /* Session reached refcount == 0, lets delete it. */
154 if (bs->refcount == 0) {
155 /*
156 * Sanity check: if there is a refcount bug, we can't delete
157 * the session a user configured manually. Lets leave a
158 * message here so we can catch the bug if it exists.
159 */
160 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG)) {
161 zlog_err(
162 "ptm-del-session: [%s] session refcount is zero but it was configured by CLI",
163 bs_to_string(bs));
164 } else {
165 control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
166 bfd_session_free(bs);
167 }
168 }
169 }
170
171 static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
172 {
173 stream_putc(msg, family);
174
175 switch (family) {
176 case AF_INET:
177 stream_put(msg, addr, sizeof(struct in_addr));
178 stream_putc(msg, 32);
179 break;
180
181 case AF_INET6:
182 stream_put(msg, addr, sizeof(struct in6_addr));
183 stream_putc(msg, 128);
184 break;
185
186 default:
187 assert(0);
188 break;
189 }
190
191 return 0;
192 }
193
194 int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state)
195 {
196 struct stream *msg;
197
198 bs->stats.znotification++;
199
200 /*
201 * Message format:
202 * - header: command, vrf
203 * - l: interface index
204 * - c: family
205 * - AF_INET:
206 * - 4 bytes: ipv4
207 * - AF_INET6:
208 * - 16 bytes: ipv6
209 * - c: prefix length
210 * - l: bfd status
211 * - c: family
212 * - AF_INET:
213 * - 4 bytes: ipv4
214 * - AF_INET6:
215 * - 16 bytes: ipv6
216 * - c: prefix length
217 * - c: cbit
218 *
219 * Commands: ZEBRA_BFD_DEST_REPLAY
220 *
221 * q(64), l(32), w(16), c(8)
222 */
223 msg = zclient->obuf;
224 stream_reset(msg);
225
226 /* TODO: VRF handling */
227 if (bs->vrf)
228 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, bs->vrf->vrf_id);
229 else
230 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
231
232 /* This header will be handled by `zebra_ptm.c`. */
233 stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
234
235 /* NOTE: Interface is a shortcut to avoid comparing source address. */
236 if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && bs->ifp != NULL)
237 stream_putl(msg, bs->ifp->ifindex);
238 else
239 stream_putl(msg, IFINDEX_INTERNAL);
240
241 /* BFD destination prefix information. */
242 _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
243
244 /* BFD status */
245 switch (notify_state) {
246 case PTM_BFD_UP:
247 stream_putl(msg, BFD_STATUS_UP);
248 break;
249
250 case PTM_BFD_ADM_DOWN:
251 stream_putl(msg, BFD_STATUS_ADMIN_DOWN);
252 break;
253
254 case PTM_BFD_DOWN:
255 case PTM_BFD_INIT:
256 stream_putl(msg, BFD_STATUS_DOWN);
257 break;
258
259 default:
260 stream_putl(msg, BFD_STATUS_UNKNOWN);
261 break;
262 }
263
264 /* BFD source prefix information. */
265 _ptm_msg_address(msg, bs->key.family, &bs->key.local);
266
267 stream_putc(msg, bs->remote_cbit);
268
269 /* Write packet size. */
270 stream_putw_at(msg, 0, stream_get_endp(msg));
271
272 return zclient_send_message(zclient);
273 }
274
275 static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa)
276 {
277 uint16_t family;
278
279 STREAM_GETW(msg, family);
280
281 switch (family) {
282 case AF_INET:
283 sa->sa_sin.sin_family = family;
284 STREAM_GET(&sa->sa_sin.sin_addr, msg,
285 sizeof(sa->sa_sin.sin_addr));
286 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
287 sa->sa_sin.sin_len = sizeof(sa->sa_sin);
288 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
289 return;
290
291 case AF_INET6:
292 sa->sa_sin6.sin6_family = family;
293 STREAM_GET(&sa->sa_sin6.sin6_addr, msg,
294 sizeof(sa->sa_sin6.sin6_addr));
295 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
296 sa->sa_sin6.sin6_len = sizeof(sa->sa_sin6);
297 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
298 return;
299
300 default:
301 zlog_warn("ptm-read-address: invalid family: %d", family);
302 break;
303 }
304
305 stream_failure:
306 memset(sa, 0, sizeof(*sa));
307 }
308
309 static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
310 struct bfd_peer_cfg *bpc, struct ptm_client **pc)
311 {
312 uint32_t pid;
313 size_t ifnamelen;
314
315 /*
316 * Register/Deregister/Update Message format:
317 *
318 * Old format (being used by PTM BFD).
319 * - header: Command, VRF
320 * - l: pid
321 * - w: family
322 * - AF_INET:
323 * - l: destination ipv4
324 * - AF_INET6:
325 * - 16 bytes: destination IPv6
326 * - command != ZEBRA_BFD_DEST_DEREGISTER
327 * - l: min_rx
328 * - l: min_tx
329 * - c: detect multiplier
330 * - c: is_multihop?
331 * - multihop:
332 * - w: family
333 * - AF_INET:
334 * - l: source IPv4 address
335 * - AF_INET6:
336 * - 16 bytes: source IPv6 address
337 * - c: ttl
338 * - no multihop
339 * - AF_INET6:
340 * - w: family
341 * - 16 bytes: source IPv6 address
342 * - c: ifname length
343 * - X bytes: interface name
344 *
345 * New format:
346 * - header: Command, VRF
347 * - l: pid
348 * - w: family
349 * - AF_INET:
350 * - l: destination IPv4 address
351 * - AF_INET6:
352 * - 16 bytes: destination IPv6 address
353 * - l: min_rx
354 * - l: min_tx
355 * - c: detect multiplier
356 * - c: is_multihop?
357 * - w: family
358 * - AF_INET:
359 * - l: source IPv4 address
360 * - AF_INET6:
361 * - 16 bytes: source IPv6 address
362 * - c: ttl
363 * - c: ifname length
364 * - X bytes: interface name
365 * - c: bfd_cbit
366 * - c: profile name length.
367 * - X bytes: profile name.
368 *
369 * q(64), l(32), w(16), c(8)
370 */
371
372 /* Initialize parameters return values. */
373 memset(bpc, 0, sizeof(*bpc));
374 *pc = NULL;
375
376 /* Find or allocate process context data. */
377 STREAM_GETL(msg, pid);
378
379 *pc = pc_new(pid);
380
381 /* Register/update peer information. */
382 _ptm_msg_read_address(msg, &bpc->bpc_peer);
383
384 /* Determine IP type from peer destination. */
385 bpc->bpc_ipv4 = (bpc->bpc_peer.sa_sin.sin_family == AF_INET);
386
387 /* Get peer configuration. */
388 STREAM_GETL(msg, bpc->bpc_recvinterval);
389 bpc->bpc_has_recvinterval =
390 (bpc->bpc_recvinterval != BPC_DEF_RECEIVEINTERVAL);
391
392 STREAM_GETL(msg, bpc->bpc_txinterval);
393 bpc->bpc_has_txinterval =
394 (bpc->bpc_txinterval != BPC_DEF_TRANSMITINTERVAL);
395
396 STREAM_GETC(msg, bpc->bpc_detectmultiplier);
397 bpc->bpc_has_detectmultiplier =
398 (bpc->bpc_detectmultiplier != BPC_DEF_DETECTMULTIPLIER);
399
400 /* Read (single|multi)hop and its options. */
401 STREAM_GETC(msg, bpc->bpc_mhop);
402
403 /* Read multihop source address and TTL. */
404 _ptm_msg_read_address(msg, &bpc->bpc_local);
405
406 /* Read the minimum TTL (0 means unset or invalid). */
407 STREAM_GETC(msg, bpc->bpc_minimum_ttl);
408 if (bpc->bpc_minimum_ttl == 0) {
409 bpc->bpc_minimum_ttl = BFD_DEF_MHOP_TTL;
410 bpc->bpc_has_minimum_ttl = false;
411 } else {
412 bpc->bpc_minimum_ttl = (BFD_TTL_VAL + 1) - bpc->bpc_minimum_ttl;
413 bpc->bpc_has_minimum_ttl = true;
414 }
415
416 /*
417 * Read interface name and make sure it fits our data
418 * structure, otherwise fail.
419 */
420 STREAM_GETC(msg, ifnamelen);
421 if (ifnamelen >= sizeof(bpc->bpc_localif)) {
422 zlog_err("ptm-read: interface name is too big");
423 return -1;
424 }
425
426 bpc->bpc_has_localif = ifnamelen > 0;
427 if (bpc->bpc_has_localif) {
428 STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
429 bpc->bpc_localif[ifnamelen] = 0;
430 }
431
432 if (vrf_id != VRF_DEFAULT) {
433 struct vrf *vrf;
434
435 vrf = vrf_lookup_by_id(vrf_id);
436 if (vrf) {
437 bpc->bpc_has_vrfname = true;
438 strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname));
439 } else {
440 zlog_err("ptm-read: vrf id %u could not be identified",
441 vrf_id);
442 return -1;
443 }
444 } else {
445 bpc->bpc_has_vrfname = true;
446 strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
447 }
448
449 /* Read control plane independant configuration. */
450 STREAM_GETC(msg, bpc->bpc_cbit);
451
452 /* Handle profile names. */
453 STREAM_GETC(msg, ifnamelen);
454 bpc->bpc_has_profile = ifnamelen > 0;
455 if (bpc->bpc_has_profile) {
456 STREAM_GET(bpc->bpc_profile, msg, ifnamelen);
457 bpc->bpc_profile[ifnamelen] = 0;
458 }
459
460 /* Sanity check: peer and local address must match IP types. */
461 if (bpc->bpc_local.sa_sin.sin_family != AF_UNSPEC
462 && (bpc->bpc_local.sa_sin.sin_family
463 != bpc->bpc_peer.sa_sin.sin_family)) {
464 zlog_warn("ptm-read: peer family doesn't match local type");
465 return -1;
466 }
467
468 return 0;
469
470 stream_failure:
471 return -1;
472 }
473
474 static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
475 {
476 struct ptm_client *pc;
477 struct bfd_session *bs;
478 struct bfd_peer_cfg bpc;
479
480 /* Read the client context and peer data. */
481 if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1)
482 return;
483
484 debug_printbpc(&bpc, "ptm-add-dest: register peer");
485
486 /* Find or start new BFD session. */
487 bs = bs_peer_find(&bpc);
488 if (bs == NULL) {
489 bs = ptm_bfd_sess_new(&bpc);
490 if (bs == NULL) {
491 if (bglobal.debug_zebra)
492 zlog_debug(
493 "ptm-add-dest: failed to create BFD session");
494 return;
495 }
496 } else {
497 /*
498 * BFD session was already created, we are just updating the
499 * current peer.
500 *
501 * `ptm-bfd` (or `HAVE_BFDD == 0`) is the only implementation
502 * that allow users to set peer specific timers via protocol.
503 * BFD daemon (this code) on the other hand only supports
504 * changing peer configuration manually (through `peer` node)
505 * or via profiles.
506 */
507 if (bpc.bpc_has_profile)
508 bfd_profile_apply(bpc.bpc_profile, bs);
509 }
510
511 /* Create client peer notification register. */
512 pcn_new(pc, bs);
513
514 ptm_bfd_notify(bs, bs->ses_state);
515 }
516
517 static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
518 {
519 struct ptm_client *pc;
520 struct ptm_client_notification *pcn;
521 struct bfd_session *bs;
522 struct bfd_peer_cfg bpc;
523
524 /* Read the client context and peer data. */
525 if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, vrf_id, &bpc, &pc) == -1)
526 return;
527
528 debug_printbpc(&bpc, "ptm-del-dest: deregister peer");
529
530 /* Find or start new BFD session. */
531 bs = bs_peer_find(&bpc);
532 if (bs == NULL) {
533 if (bglobal.debug_zebra)
534 zlog_debug("ptm-del-dest: failed to find BFD session");
535 return;
536 }
537
538 /* Unregister client peer notification. */
539 pcn = pcn_lookup(pc, bs);
540 if (pcn != NULL) {
541 pcn_free(pcn);
542 return;
543 }
544
545 if (bglobal.debug_zebra)
546 zlog_debug("ptm-del-dest: failed to find BFD session");
547
548 /*
549 * XXX: We either got a double deregistration or the daemon who
550 * created this is no longer around. Lets try to delete it anyway
551 * and the worst case is the refcount will detain us.
552 */
553 _ptm_bfd_session_del(bs, BD_NEIGHBOR_DOWN);
554 }
555
556 /*
557 * header: command, VRF
558 * l: pid
559 */
560 static void bfdd_client_register(struct stream *msg)
561 {
562 uint32_t pid;
563
564 /* Find or allocate process context data. */
565 STREAM_GETL(msg, pid);
566
567 pc_new(pid);
568
569 return;
570
571 stream_failure:
572 zlog_err("ptm-add-client: failed to register client");
573 }
574
575 /*
576 * header: command, VRF
577 * l: pid
578 */
579 static void bfdd_client_deregister(struct stream *msg)
580 {
581 struct ptm_client *pc;
582 uint32_t pid;
583
584 /* Find or allocate process context data. */
585 STREAM_GETL(msg, pid);
586
587 pc = pc_lookup(pid);
588 if (pc == NULL) {
589 if (bglobal.debug_zebra)
590 zlog_debug("ptm-del-client: failed to find client: %u",
591 pid);
592 return;
593 }
594
595 if (bglobal.debug_zebra)
596 zlog_debug("ptm-del-client: client pid %u", pid);
597
598 pc_free(pc);
599
600 return;
601
602 stream_failure:
603 zlog_err("ptm-del-client: failed to deregister client");
604 }
605
606 static int bfdd_replay(ZAPI_CALLBACK_ARGS)
607 {
608 struct stream *msg = zclient->ibuf;
609 uint32_t rcmd;
610
611 STREAM_GETL(msg, rcmd);
612
613 switch (rcmd) {
614 case ZEBRA_BFD_DEST_REGISTER:
615 case ZEBRA_BFD_DEST_UPDATE:
616 bfdd_dest_register(msg, vrf_id);
617 break;
618 case ZEBRA_BFD_DEST_DEREGISTER:
619 bfdd_dest_deregister(msg, vrf_id);
620 break;
621 case ZEBRA_BFD_CLIENT_REGISTER:
622 bfdd_client_register(msg);
623 break;
624 case ZEBRA_BFD_CLIENT_DEREGISTER:
625 bfdd_client_deregister(msg);
626 break;
627
628 default:
629 if (bglobal.debug_zebra)
630 zlog_debug("ptm-replay: invalid message type %u", rcmd);
631 return -1;
632 }
633
634 return 0;
635
636 stream_failure:
637 zlog_err("ptm-replay: failed to find command");
638 return -1;
639 }
640
641 static void bfdd_zebra_connected(struct zclient *zc)
642 {
643 struct stream *msg = zc->obuf;
644
645 /* Clean-up and free ptm clients data memory. */
646 pc_free_all();
647
648 /*
649 * The replay is an empty message just to trigger client daemons
650 * configuration replay.
651 */
652 stream_reset(msg);
653 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
654 stream_putl(msg, ZEBRA_BFD_DEST_REPLAY);
655 stream_putw_at(msg, 0, stream_get_endp(msg));
656
657 /* Ask for interfaces information. */
658 zclient_create_header(msg, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
659
660 /* Send requests. */
661 zclient_send_message(zclient);
662 }
663
664 static void bfdd_sessions_enable_interface(struct interface *ifp)
665 {
666 struct bfd_session_observer *bso;
667 struct bfd_session *bs;
668 struct vrf *vrf;
669
670 vrf = ifp->vrf;
671
672 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
673 bs = bso->bso_bs;
674 /* check vrf name */
675 if (bs->key.vrfname[0] &&
676 strcmp(vrf->name, bs->key.vrfname))
677 continue;
678
679 /* If Interface matches vrfname, then bypass iface check */
680 if (vrf_is_backend_netns() || strcmp(ifp->name, vrf->name)) {
681 /* Interface name mismatch. */
682 if (bs->key.ifname[0] &&
683 strcmp(ifp->name, bs->key.ifname))
684 continue;
685 }
686
687 /* Skip enabled sessions. */
688 if (bs->sock != -1)
689 continue;
690
691 /* Try to enable it. */
692 bfd_session_enable(bs);
693 }
694 }
695
696 static void bfdd_sessions_disable_interface(struct interface *ifp)
697 {
698 struct bfd_session_observer *bso;
699 struct bfd_session *bs;
700
701 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
702 bs = bso->bso_bs;
703
704 if (bs->ifp != ifp)
705 continue;
706
707 /* Skip disabled sessions. */
708 if (bs->sock == -1) {
709 bs->ifp = NULL;
710 continue;
711 }
712
713 bfd_session_disable(bs);
714 bs->ifp = NULL;
715 }
716 }
717
718 void bfdd_sessions_enable_vrf(struct vrf *vrf)
719 {
720 struct bfd_session_observer *bso;
721 struct bfd_session *bs;
722
723 /* it may affect configs without interfaces */
724 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
725 bs = bso->bso_bs;
726 if (bs->vrf)
727 continue;
728 if (bs->key.vrfname[0] &&
729 strcmp(vrf->name, bs->key.vrfname))
730 continue;
731 /* need to update the vrf information on
732 * bs so that callbacks are handled
733 */
734 bs->vrf = vrf;
735 /* Skip enabled sessions. */
736 if (bs->sock != -1)
737 continue;
738 /* Try to enable it. */
739 bfd_session_enable(bs);
740 }
741 }
742
743 void bfdd_sessions_disable_vrf(struct vrf *vrf)
744 {
745 struct bfd_session_observer *bso;
746 struct bfd_session *bs;
747
748 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
749 bs = bso->bso_bs;
750 if (bs->key.vrfname[0] &&
751 strcmp(vrf->name, bs->key.vrfname))
752 continue;
753 /* Skip disabled sessions. */
754 if (bs->sock == -1)
755 continue;
756
757 bfd_session_disable(bs);
758 bs->vrf = NULL;
759 }
760 }
761
762 static int bfd_ifp_destroy(struct interface *ifp)
763 {
764 if (bglobal.debug_zebra)
765 zlog_debug("zclient: delete interface %s (VRF %s(%u))",
766 ifp->name, ifp->vrf->name, ifp->vrf->vrf_id);
767
768 bfdd_sessions_disable_interface(ifp);
769
770 return 0;
771 }
772
773 static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS)
774 {
775 struct interface *ifp;
776 vrf_id_t nvrfid;
777
778 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid);
779 if (ifp == NULL)
780 return 0;
781
782 if_update_to_new_vrf(ifp, nvrfid);
783
784 return 0;
785 }
786
787 static void bfdd_sessions_enable_address(struct connected *ifc)
788 {
789 struct bfd_session_observer *bso;
790 struct bfd_session *bs;
791 struct prefix prefix;
792
793 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
794 /* Skip enabled sessions. */
795 bs = bso->bso_bs;
796 if (bs->sock != -1)
797 continue;
798
799 /* Check address. */
800 prefix = bso->bso_addr;
801 prefix.prefixlen = ifc->address->prefixlen;
802 if (prefix_cmp(&prefix, ifc->address))
803 continue;
804
805 /* Try to enable it. */
806 bfd_session_enable(bs);
807 }
808 }
809
810 static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
811 {
812 struct connected *ifc;
813
814 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
815 if (ifc == NULL)
816 return 0;
817
818 if (bglobal.debug_zebra)
819 zlog_debug("zclient: %s local address %pFX (VRF %u)",
820 cmd == ZEBRA_INTERFACE_ADDRESS_ADD ? "add"
821 : "delete",
822 ifc->address, vrf_id);
823
824 if (cmd == ZEBRA_INTERFACE_ADDRESS_ADD)
825 bfdd_sessions_enable_address(ifc);
826 else
827 connected_free(&ifc);
828
829 return 0;
830 }
831
832 static int bfd_ifp_create(struct interface *ifp)
833 {
834 if (bglobal.debug_zebra)
835 zlog_debug("zclient: add interface %s (VRF %s(%u))", ifp->name,
836 ifp->vrf->name, ifp->vrf->vrf_id);
837 bfdd_sessions_enable_interface(ifp);
838
839 return 0;
840 }
841
842 static zclient_handler *const bfd_handlers[] = {
843 /*
844 * We'll receive all messages through replay, however it will
845 * contain a special field with the real command inside so we
846 * avoid having to create too many handlers.
847 */
848 [ZEBRA_BFD_DEST_REPLAY] = bfdd_replay,
849
850 /* Learn about interface VRF. */
851 [ZEBRA_INTERFACE_VRF_UPDATE] = bfdd_interface_vrf_update,
852
853 /* Learn about new addresses being registered. */
854 [ZEBRA_INTERFACE_ADDRESS_ADD] = bfdd_interface_address_update,
855 [ZEBRA_INTERFACE_ADDRESS_DELETE] = bfdd_interface_address_update,
856 };
857
858 void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
859 {
860 if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy);
861 zclient = zclient_new(master, &zclient_options_default, bfd_handlers,
862 array_size(bfd_handlers));
863 assert(zclient != NULL);
864 zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
865
866 /* Send replay request on zebra connect. */
867 zclient->zebra_connected = bfdd_zebra_connected;
868 }
869
870 void bfdd_zclient_register(vrf_id_t vrf_id)
871 {
872 if (!zclient || zclient->sock < 0)
873 return;
874 zclient_send_reg_requests(zclient, vrf_id);
875 }
876
877 void bfdd_zclient_unregister(vrf_id_t vrf_id)
878 {
879 if (!zclient || zclient->sock < 0)
880 return;
881 zclient_send_dereg_requests(zclient, vrf_id);
882 }
883
884 void bfdd_zclient_stop(void)
885 {
886 zclient_stop(zclient);
887
888 /* Clean-up and free ptm clients data memory. */
889 pc_free_all();
890 }
891
892
893 /*
894 * Client handling.
895 */
896 static struct ptm_client *pc_lookup(uint32_t pid)
897 {
898 struct ptm_client *pc;
899
900 TAILQ_FOREACH (pc, &pcqueue, pc_entry) {
901 if (pc->pc_pid != pid)
902 continue;
903
904 break;
905 }
906
907 return pc;
908 }
909
910 static struct ptm_client *pc_new(uint32_t pid)
911 {
912 struct ptm_client *pc;
913
914 /* Look up first, if not found create the client. */
915 pc = pc_lookup(pid);
916 if (pc != NULL)
917 return pc;
918
919 /* Allocate the client data and save it. */
920 pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc));
921
922 pc->pc_pid = pid;
923 TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
924 return pc;
925 }
926
927 static void pc_free(struct ptm_client *pc)
928 {
929 struct ptm_client_notification *pcn;
930
931 TAILQ_REMOVE(&pcqueue, pc, pc_entry);
932
933 while (!TAILQ_EMPTY(&pc->pc_pcnqueue)) {
934 pcn = TAILQ_FIRST(&pc->pc_pcnqueue);
935 pcn_free(pcn);
936 }
937
938 XFREE(MTYPE_BFDD_CONTROL, pc);
939 }
940
941 static void pc_free_all(void)
942 {
943 struct ptm_client *pc;
944
945 while (!TAILQ_EMPTY(&pcqueue)) {
946 pc = TAILQ_FIRST(&pcqueue);
947 pc_free(pc);
948 }
949 }
950
951 static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
952 struct bfd_session *bs)
953 {
954 struct ptm_client_notification *pcn;
955
956 /* Try to find an existing pcn fist. */
957 pcn = pcn_lookup(pc, bs);
958 if (pcn != NULL)
959 return pcn;
960
961 /* Save the client notification data. */
962 pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn));
963
964 TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
965 pcn->pcn_pc = pc;
966 pcn->pcn_bs = bs;
967 bs->refcount++;
968
969 return pcn;
970 }
971
972 static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
973 struct bfd_session *bs)
974 {
975 struct ptm_client_notification *pcn;
976
977 TAILQ_FOREACH (pcn, &pc->pc_pcnqueue, pcn_entry) {
978 if (pcn->pcn_bs != bs)
979 continue;
980
981 break;
982 }
983
984 return pcn;
985 }
986
987 static void pcn_free(struct ptm_client_notification *pcn)
988 {
989 struct ptm_client *pc;
990 struct bfd_session *bs;
991
992 /* Handle session de-registration. */
993 bs = pcn->pcn_bs;
994 pcn->pcn_bs = NULL;
995 bs->refcount--;
996
997 /* Log modification to users. */
998 if (bglobal.debug_zebra)
999 zlog_debug("ptm-del-session: [%s] refcount=%" PRIu64,
1000 bs_to_string(bs), bs->refcount);
1001
1002 /* Set session down. */
1003 _ptm_bfd_session_del(bs, BD_NEIGHBOR_DOWN);
1004
1005 /* Handle ptm_client deregistration. */
1006 pc = pcn->pcn_pc;
1007 pcn->pcn_pc = NULL;
1008 TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
1009
1010 XFREE(MTYPE_BFDD_NOTIFICATION, pcn);
1011 }