]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/ptm_adapter.c
Merge pull request #5641 from slankdev/slankdev-bgpd-fix-large-rd-frr-7-1
[mirror_frr.git] / bfdd / ptm_adapter.c
CommitLineData
d3af6147
RZ
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
28#include "lib/bfd.h"
29
30#include "bfd.h"
31
32/*
33 * Data structures
34 */
35struct ptm_client_notification {
36 struct bfd_session *pcn_bs;
37 struct ptm_client *pcn_pc;
38
39 TAILQ_ENTRY(ptm_client_notification) pcn_entry;
40};
41TAILQ_HEAD(pcnqueue, ptm_client_notification);
42
43struct ptm_client {
44 uint32_t pc_pid;
45 struct pcnqueue pc_pcnqueue;
46
47 TAILQ_ENTRY(ptm_client) pc_entry;
48};
49TAILQ_HEAD(pcqueue, ptm_client);
50
51static struct pcqueue pcqueue;
52static struct zclient *zclient;
53
54
55/*
56 * Prototypes
57 */
79b4a6fc 58static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
d3af6147
RZ
59
60static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
61static int _ptm_msg_read(struct stream *msg, int command,
62 struct bfd_peer_cfg *bpc, struct ptm_client **pc);
63
64static struct ptm_client *pc_lookup(uint32_t pid);
65static struct ptm_client *pc_new(uint32_t pid);
a375de5c 66static void pc_free(struct ptm_client *pc);
788378fe 67static void pc_free_all(void);
d3af6147
RZ
68static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
69 struct bfd_session *bs);
70static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
71 struct bfd_session *bs);
72static void pcn_free(struct ptm_client_notification *pcn);
73
74
75static void bfdd_dest_register(struct stream *msg);
76static void bfdd_dest_deregister(struct stream *msg);
77static void bfdd_client_register(struct stream *msg);
a375de5c 78static void bfdd_client_deregister(struct stream *msg);
d3af6147
RZ
79
80/*
81 * Functions
82 */
83#ifdef BFD_DEBUG
84static void debug_printbpc(const char *func, unsigned int line,
85 struct bfd_peer_cfg *bpc);
86
87static void debug_printbpc(const char *func, unsigned int line,
88 struct bfd_peer_cfg *bpc)
89{
90 char addr[3][128];
91 char timers[3][128];
92
93 addr[0][0] = addr[1][0] = addr[2][0] = timers[0][0] = timers[1][0] =
94 timers[2][0] = 0;
95
96 snprintf(addr[0], sizeof(addr[0]), "peer:%s", satostr(&bpc->bpc_peer));
97 if (bpc->bpc_local.sa_sin.sin_family)
98 snprintf(addr[1], sizeof(addr[1]), " local:%s",
99 satostr(&bpc->bpc_local));
100
101 if (bpc->bpc_has_localif)
102 snprintf(addr[2], sizeof(addr[2]), " ifname:%s",
103 bpc->bpc_localif);
104
105 if (bpc->bpc_has_vrfname)
106 snprintf(addr[2], sizeof(addr[2]), " vrf:%s", bpc->bpc_vrfname);
107
108 if (bpc->bpc_has_recvinterval)
109 snprintf(timers[0], sizeof(timers[0]), " rx:%lu",
110 bpc->bpc_recvinterval);
111
112 if (bpc->bpc_has_txinterval)
113 snprintf(timers[1], sizeof(timers[1]), " tx:%lu",
114 bpc->bpc_recvinterval);
115
116 if (bpc->bpc_has_detectmultiplier)
117 snprintf(timers[2], sizeof(timers[2]), " detect-multiplier:%d",
118 bpc->bpc_detectmultiplier);
119
120 log_debug("%s:%d: %s %s%s%s%s%s%s", func, line,
121 bpc->bpc_mhop ? "multi-hop" : "single-hop", addr[0], addr[1],
122 addr[2], timers[0], timers[1], timers[2]);
123}
124
125#define DEBUG_PRINTBPC(bpc) debug_printbpc(__FILE__, __LINE__, (bpc))
126#else
127#define DEBUG_PRINTBPC(bpc)
128#endif /* BFD_DEBUG */
129
79b4a6fc 130static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
d3af6147 131{
79b4a6fc
RZ
132 stream_putc(msg, family);
133
134 switch (family) {
d3af6147 135 case AF_INET:
79b4a6fc 136 stream_put(msg, addr, sizeof(struct in_addr));
d3af6147
RZ
137 stream_putc(msg, 32);
138 break;
139
140 case AF_INET6:
79b4a6fc 141 stream_put(msg, addr, sizeof(struct in6_addr));
d3af6147
RZ
142 stream_putc(msg, 128);
143 break;
144
145 default:
79b4a6fc
RZ
146 assert(0);
147 break;
d3af6147
RZ
148 }
149
150 return 0;
151}
152
153int ptm_bfd_notify(struct bfd_session *bs)
154{
155 struct stream *msg;
d3af6147 156
0684c9b1
RZ
157 bs->stats.znotification++;
158
d3af6147
RZ
159 /*
160 * Message format:
161 * - header: command, vrf
162 * - l: interface index
163 * - c: family
164 * - AF_INET:
165 * - 4 bytes: ipv4
166 * - AF_INET6:
167 * - 16 bytes: ipv6
168 * - c: prefix length
169 * - l: bfd status
170 * - c: family
171 * - AF_INET:
172 * - 4 bytes: ipv4
173 * - AF_INET6:
174 * - 16 bytes: ipv6
175 * - c: prefix length
176 *
177 * Commands: ZEBRA_BFD_DEST_REPLAY
178 *
179 * q(64), l(32), w(16), c(8)
180 */
181 msg = zclient->obuf;
182 stream_reset(msg);
183
184 /* TODO: VRF handling */
185 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
186
971532e2
RZ
187 /* This header will be handled by `zebra_ptm.c`. */
188 stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
189
d3af6147 190 /* NOTE: Interface is a shortcut to avoid comparing source address. */
80edb675
RZ
191 if (bs->ifp != NULL)
192 stream_putl(msg, bs->ifp->ifindex);
193 else
194 stream_putl(msg, IFINDEX_INTERNAL);
d3af6147
RZ
195
196 /* BFD destination prefix information. */
79b4a6fc 197 _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
d3af6147
RZ
198
199 /* BFD status */
200 switch (bs->ses_state) {
201 case PTM_BFD_UP:
202 stream_putl(msg, BFD_STATUS_UP);
203 break;
204
205 case PTM_BFD_ADM_DOWN:
206 case PTM_BFD_DOWN:
207 case PTM_BFD_INIT:
208 stream_putl(msg, BFD_STATUS_DOWN);
209 break;
210
211 default:
212 stream_putl(msg, BFD_STATUS_UNKNOWN);
213 break;
214 }
215
216 /* BFD source prefix information. */
79b4a6fc 217 _ptm_msg_address(msg, bs->key.family, &bs->key.local);
d3af6147
RZ
218
219 /* Write packet size. */
220 stream_putw_at(msg, 0, stream_get_endp(msg));
221
222 return zclient_send_message(zclient);
223}
224
225static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa)
226{
227 uint16_t family;
228
229 STREAM_GETW(msg, family);
230
231 switch (family) {
232 case AF_INET:
233 sa->sa_sin.sin_family = family;
234 STREAM_GET(&sa->sa_sin.sin_addr, msg,
235 sizeof(sa->sa_sin.sin_addr));
236#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
237 sa->sa_sin.sin_len = sizeof(sa->sa_sin);
238#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
239 return;
240
241 case AF_INET6:
242 sa->sa_sin6.sin6_family = family;
243 STREAM_GET(&sa->sa_sin6.sin6_addr, msg,
244 sizeof(sa->sa_sin6.sin6_addr));
245#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
246 sa->sa_sin6.sin6_len = sizeof(sa->sa_sin6);
247#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
248 return;
249
250 default:
ae9f45a3 251 log_warning("ptm-read-address: invalid family: %d", family);
d3af6147
RZ
252 break;
253 }
254
255stream_failure:
256 memset(sa, 0, sizeof(*sa));
257}
258
259static int _ptm_msg_read(struct stream *msg, int command,
260 struct bfd_peer_cfg *bpc, struct ptm_client **pc)
261{
262 uint32_t pid;
f0d2be33 263 uint8_t ttl __attribute__((unused));
ae9eebca 264 size_t ifnamelen;
d3af6147
RZ
265
266 /*
267 * Register/Deregister/Update Message format:
268 * - header: Command, VRF
269 * - l: pid
270 * - w: family
271 * - AF_INET:
272 * - l: destination ipv4
273 * - AF_INET6:
274 * - 16 bytes: destination IPv6
275 * - command != ZEBRA_BFD_DEST_DEREGISTER
276 * - l: min_rx
277 * - l: min_tx
278 * - c: detect multiplier
279 * - c: is_multihop?
280 * - multihop:
281 * - w: family
282 * - AF_INET:
283 * - l: destination ipv4
284 * - AF_INET6:
285 * - 16 bytes: destination IPv6
286 * - c: ttl
287 * - no multihop
288 * - AF_INET6:
289 * - w: family
290 * - 16 bytes: ipv6 address
291 * - c: ifname length
292 * - X bytes: interface name
293 *
294 * q(64), l(32), w(16), c(8)
295 */
296
297 /* Initialize parameters return values. */
298 memset(bpc, 0, sizeof(*bpc));
299 *pc = NULL;
300
301 /* Find or allocate process context data. */
302 STREAM_GETL(msg, pid);
303
304 *pc = pc_new(pid);
305 if (*pc == NULL) {
ae9f45a3 306 log_debug("ptm-read: failed to allocate memory");
d3af6147
RZ
307 return -1;
308 }
309
310 /* Register/update peer information. */
311 _ptm_msg_read_address(msg, &bpc->bpc_peer);
312
313 /* Determine IP type from peer destination. */
314 bpc->bpc_ipv4 = (bpc->bpc_peer.sa_sin.sin_family == AF_INET);
315
316 /* Get peer configuration. */
317 if (command != ZEBRA_BFD_DEST_DEREGISTER) {
318 STREAM_GETL(msg, bpc->bpc_recvinterval);
319 bpc->bpc_has_recvinterval =
320 (bpc->bpc_recvinterval != BPC_DEF_RECEIVEINTERVAL);
321
322 STREAM_GETL(msg, bpc->bpc_txinterval);
323 bpc->bpc_has_txinterval =
324 (bpc->bpc_txinterval != BPC_DEF_TRANSMITINTERVAL);
325
326 STREAM_GETC(msg, bpc->bpc_detectmultiplier);
327 bpc->bpc_has_detectmultiplier =
328 (bpc->bpc_detectmultiplier != BPC_DEF_DETECTMULTIPLIER);
329 }
330
331 /* Read (single|multi)hop and its options. */
332 STREAM_GETC(msg, bpc->bpc_mhop);
333 if (bpc->bpc_mhop) {
334 /* Read multihop source address and TTL. */
335 _ptm_msg_read_address(msg, &bpc->bpc_local);
336 STREAM_GETC(msg, ttl);
d3af6147
RZ
337 } else {
338 /* If target is IPv6, then we must obtain local address. */
339 if (bpc->bpc_ipv4 == false)
340 _ptm_msg_read_address(msg, &bpc->bpc_local);
341
342 /*
343 * Read interface name and make sure it fits our data
344 * structure, otherwise fail.
345 */
346 STREAM_GETC(msg, ifnamelen);
ae9f45a3
RZ
347 if (ifnamelen >= sizeof(bpc->bpc_localif)) {
348 log_error("ptm-read: interface name is too big");
d3af6147
RZ
349 return -1;
350 }
351
352 bpc->bpc_has_localif = ifnamelen > 0;
353 if (bpc->bpc_has_localif) {
354 STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
355 bpc->bpc_localif[ifnamelen] = 0;
356 }
357 }
358
359 /* Sanity check: peer and local address must match IP types. */
360 if (bpc->bpc_local.sa_sin.sin_family != 0
361 && (bpc->bpc_local.sa_sin.sin_family
362 != bpc->bpc_peer.sa_sin.sin_family)) {
ae9f45a3 363 log_warning("ptm-read: peer family doesn't match local type");
d3af6147
RZ
364 return -1;
365 }
366
367 return 0;
368
369stream_failure:
370 return -1;
371}
372
373static void bfdd_dest_register(struct stream *msg)
374{
375 struct ptm_client *pc;
376 struct ptm_client_notification *pcn;
377 struct bfd_session *bs;
378 struct bfd_peer_cfg bpc;
379
380 /* Read the client context and peer data. */
381 if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, &bpc, &pc) == -1)
382 return;
383
384 DEBUG_PRINTBPC(&bpc);
385
386 /* Find or start new BFD session. */
387 bs = bs_peer_find(&bpc);
388 if (bs == NULL) {
389 bs = ptm_bfd_sess_new(&bpc);
390 if (bs == NULL) {
ae9f45a3 391 log_debug("ptm-add-dest: failed to create BFD session");
d3af6147
RZ
392 return;
393 }
394 } else {
395 /* Don't try to change echo/shutdown state. */
396 bpc.bpc_echo = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
397 bpc.bpc_shutdown =
398 BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
399 }
400
401 /* Create client peer notification register. */
402 pcn = pcn_new(pc, bs);
403 if (pcn == NULL) {
ae9f45a3 404 log_error("ptm-add-dest: failed to registrate notifications");
d3af6147
RZ
405 return;
406 }
407
408 ptm_bfd_notify(bs);
409}
410
411static void bfdd_dest_deregister(struct stream *msg)
412{
413 struct ptm_client *pc;
414 struct ptm_client_notification *pcn;
415 struct bfd_session *bs;
416 struct bfd_peer_cfg bpc;
417
418 /* Read the client context and peer data. */
419 if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, &bpc, &pc) == -1)
420 return;
421
422 DEBUG_PRINTBPC(&bpc);
423
424 /* Find or start new BFD session. */
425 bs = bs_peer_find(&bpc);
426 if (bs == NULL) {
ae9f45a3 427 log_debug("ptm-del-dest: failed to find BFD session");
d3af6147
RZ
428 return;
429 }
430
431 /* Unregister client peer notification. */
432 pcn = pcn_lookup(pc, bs);
433 pcn_free(pcn);
4c741971
PG
434 if (bs->refcount ||
435 BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
436 return;
437 ptm_bfd_ses_del(&bpc);
d3af6147
RZ
438}
439
440/*
441 * header: command, VRF
442 * l: pid
443 */
444static void bfdd_client_register(struct stream *msg)
445{
446 struct ptm_client *pc;
447 uint32_t pid;
448
449 /* Find or allocate process context data. */
450 STREAM_GETL(msg, pid);
451
452 pc = pc_new(pid);
453 if (pc == NULL) {
ae9f45a3 454 log_error("ptm-add-client: failed to register client: %u", pid);
d3af6147
RZ
455 return;
456 }
457
458 return;
459
460stream_failure:
ae9f45a3 461 log_error("ptm-add-client: failed to register client");
d3af6147
RZ
462}
463
a375de5c
RZ
464/*
465 * header: command, VRF
466 * l: pid
467 */
468static void bfdd_client_deregister(struct stream *msg)
469{
470 struct ptm_client *pc;
471 uint32_t pid;
472
473 /* Find or allocate process context data. */
474 STREAM_GETL(msg, pid);
475
476 pc = pc_lookup(pid);
477 if (pc == NULL) {
ae9f45a3 478 log_debug("ptm-del-client: failed to find client: %u", pid);
a375de5c
RZ
479 return;
480 }
481
482 pc_free(pc);
483
484 return;
485
486stream_failure:
ae9f45a3 487 log_error("ptm-del-client: failed to deregister client");
a375de5c
RZ
488}
489
121f9dee 490static int bfdd_replay(ZAPI_CALLBACK_ARGS)
d3af6147 491{
121f9dee 492 struct stream *msg = zclient->ibuf;
d3af6147
RZ
493 uint32_t rcmd;
494
495 STREAM_GETL(msg, rcmd);
496
497 switch (rcmd) {
498 case ZEBRA_BFD_DEST_REGISTER:
499 case ZEBRA_BFD_DEST_UPDATE:
500 bfdd_dest_register(msg);
501 break;
502 case ZEBRA_BFD_DEST_DEREGISTER:
503 bfdd_dest_deregister(msg);
504 break;
505 case ZEBRA_BFD_CLIENT_REGISTER:
506 bfdd_client_register(msg);
507 break;
a375de5c
RZ
508 case ZEBRA_BFD_CLIENT_DEREGISTER:
509 bfdd_client_deregister(msg);
510 break;
d3af6147
RZ
511
512 default:
ae9f45a3 513 log_debug("ptm-replay: invalid message type %u", rcmd);
d3af6147
RZ
514 return -1;
515 }
516
517 return 0;
518
519stream_failure:
ae9f45a3 520 log_error("ptm-replay: failed to find command");
d3af6147
RZ
521 return -1;
522}
523
971532e2
RZ
524static void bfdd_zebra_connected(struct zclient *zc)
525{
526 struct stream *msg = zc->obuf;
527
788378fe
RZ
528 /* Clean-up and free ptm clients data memory. */
529 pc_free_all();
530
971532e2
RZ
531 /*
532 * The replay is an empty message just to trigger client daemons
533 * configuration replay.
534 */
535 stream_reset(msg);
536 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
537 stream_putl(msg, ZEBRA_BFD_DEST_REPLAY);
538 stream_putw_at(msg, 0, stream_get_endp(msg));
539
80edb675
RZ
540 /* Ask for interfaces information. */
541 zclient_create_header(msg, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
542
543 /* Send requests. */
971532e2
RZ
544 zclient_send_message(zclient);
545}
546
d245e522
RZ
547static void bfdd_sessions_enable_interface(struct interface *ifp)
548{
549 struct bfd_session_observer *bso;
550 struct bfd_session *bs;
551
552 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
553 if (bso->bso_isinterface == false)
554 continue;
555
556 /* Interface name mismatch. */
557 bs = bso->bso_bs;
79b4a6fc 558 if (strcmp(ifp->name, bs->key.ifname))
d245e522
RZ
559 continue;
560 /* Skip enabled sessions. */
561 if (bs->sock != -1)
562 continue;
563
564 /* Try to enable it. */
565 bfd_session_enable(bs);
566 }
567}
568
569static void bfdd_sessions_disable_interface(struct interface *ifp)
570{
571 struct bfd_session_observer *bso;
572 struct bfd_session *bs;
573
574 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
575 if (bso->bso_isinterface == false)
576 continue;
577
578 /* Interface name mismatch. */
579 bs = bso->bso_bs;
79b4a6fc 580 if (strcmp(ifp->name, bs->key.ifname))
d245e522
RZ
581 continue;
582 /* Skip disabled sessions. */
583 if (bs->sock == -1)
584 continue;
585
586 /* Try to enable it. */
587 bfd_session_disable(bs);
588
589 TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry);
590 }
591}
592
121f9dee 593static int bfdd_interface_update(ZAPI_CALLBACK_ARGS)
80edb675 594{
d245e522
RZ
595 struct interface *ifp;
596
80edb675
RZ
597 /*
598 * `zebra_interface_add_read` will handle the interface creation
599 * on `lib/if.c`. We'll use that data structure instead of
600 * rolling our own.
601 */
602 if (cmd == ZEBRA_INTERFACE_ADD) {
121f9dee 603 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
d245e522
RZ
604 if (ifp == NULL)
605 return 0;
606
607 bfdd_sessions_enable_interface(ifp);
80edb675
RZ
608 return 0;
609 }
610
611 /* Update interface information. */
121f9dee 612 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
d245e522
RZ
613 if (ifp == NULL)
614 return 0;
80edb675 615
d245e522 616 bfdd_sessions_disable_interface(ifp);
80edb675 617
9d6c33ea
DS
618 if_set_index(ifp, IFINDEX_INTERNAL);
619
80edb675
RZ
620 return 0;
621}
622
121f9dee 623static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS)
b333abc2
RZ
624{
625 struct interface *ifp;
626 vrf_id_t nvrfid;
627
121f9dee 628 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid);
b333abc2
RZ
629 if (ifp == NULL)
630 return 0;
631
632 if_update_to_new_vrf(ifp, nvrfid);
633
634 return 0;
635}
636
261e0ba9
RZ
637static void bfdd_sessions_enable_address(struct connected *ifc)
638{
639 struct bfd_session_observer *bso;
640 struct bfd_session *bs;
641 struct prefix prefix;
642
643 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
644 if (bso->bso_isaddress == false)
645 continue;
646
647 /* Skip enabled sessions. */
648 bs = bso->bso_bs;
649 if (bs->sock != -1)
650 continue;
651
652 /* Check address. */
653 prefix = bso->bso_addr;
654 prefix.prefixlen = ifc->address->prefixlen;
655 if (prefix_cmp(&prefix, ifc->address))
656 continue;
657
658 /* Try to enable it. */
659 bfd_session_enable(bs);
660 }
661}
662
121f9dee 663static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
261e0ba9
RZ
664{
665 struct connected *ifc;
666
121f9dee 667 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
261e0ba9
RZ
668 if (ifc == NULL)
669 return 0;
670
671 bfdd_sessions_enable_address(ifc);
672
673 return 0;
674}
675
d3af6147
RZ
676void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
677{
26f63a1e 678 zclient = zclient_new(master, &zclient_options_default);
d3af6147
RZ
679 assert(zclient != NULL);
680 zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
681
682 /*
683 * We'll receive all messages through replay, however it will
684 * contain a special field with the real command inside so we
685 * avoid having to create too many handlers.
686 */
687 zclient->bfd_dest_replay = bfdd_replay;
971532e2
RZ
688
689 /* Send replay request on zebra connect. */
690 zclient->zebra_connected = bfdd_zebra_connected;
80edb675
RZ
691
692 /* Learn interfaces from zebra instead of the OS. */
693 zclient->interface_add = bfdd_interface_update;
694 zclient->interface_delete = bfdd_interface_update;
b333abc2
RZ
695
696 /* Learn about interface VRF. */
697 zclient->interface_vrf_update = bfdd_interface_vrf_update;
261e0ba9
RZ
698
699 /* Learn about new addresses being registered. */
700 zclient->interface_address_add = bfdd_interface_address_update;
701 zclient->interface_address_delete = bfdd_interface_address_update;
d3af6147
RZ
702}
703
704void bfdd_zclient_stop(void)
705{
706 zclient_stop(zclient);
788378fe
RZ
707
708 /* Clean-up and free ptm clients data memory. */
709 pc_free_all();
d3af6147
RZ
710}
711
712
713/*
714 * Client handling.
715 */
716static struct ptm_client *pc_lookup(uint32_t pid)
717{
718 struct ptm_client *pc;
719
720 TAILQ_FOREACH (pc, &pcqueue, pc_entry) {
721 if (pc->pc_pid != pid)
722 continue;
723
724 break;
725 }
726
727 return pc;
728}
729
730static struct ptm_client *pc_new(uint32_t pid)
731{
732 struct ptm_client *pc;
733
734 /* Look up first, if not found create the client. */
735 pc = pc_lookup(pid);
736 if (pc != NULL)
737 return pc;
738
739 /* Allocate the client data and save it. */
740 pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc));
d3af6147
RZ
741
742 pc->pc_pid = pid;
743 TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
744 return pc;
745}
746
a375de5c
RZ
747static void pc_free(struct ptm_client *pc)
748{
749 struct ptm_client_notification *pcn;
750
751 if (pc == NULL)
752 return;
753
754 TAILQ_REMOVE(&pcqueue, pc, pc_entry);
755
756 while (!TAILQ_EMPTY(&pc->pc_pcnqueue)) {
757 pcn = TAILQ_FIRST(&pc->pc_pcnqueue);
758 pcn_free(pcn);
759 }
760
761 XFREE(MTYPE_BFDD_CONTROL, pc);
762}
763
788378fe
RZ
764static void pc_free_all(void)
765{
766 struct ptm_client *pc;
767
768 while (!TAILQ_EMPTY(&pcqueue)) {
769 pc = TAILQ_FIRST(&pcqueue);
770 pc_free(pc);
771 }
772}
773
d3af6147
RZ
774static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
775 struct bfd_session *bs)
776{
777 struct ptm_client_notification *pcn;
778
779 /* Try to find an existing pcn fist. */
780 pcn = pcn_lookup(pc, bs);
781 if (pcn != NULL)
782 return pcn;
783
784 /* Save the client notification data. */
785 pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn));
d3af6147
RZ
786
787 TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
788 pcn->pcn_pc = pc;
789 pcn->pcn_bs = bs;
790 bs->refcount++;
791
792 return pcn;
793}
794
795static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
796 struct bfd_session *bs)
797{
798 struct ptm_client_notification *pcn;
799
800 TAILQ_FOREACH (pcn, &pc->pc_pcnqueue, pcn_entry) {
801 if (pcn->pcn_bs != bs)
802 continue;
803
804 break;
805 }
806
807 return pcn;
808}
809
810static void pcn_free(struct ptm_client_notification *pcn)
811{
812 struct ptm_client *pc;
813 struct bfd_session *bs;
814
815 if (pcn == NULL)
816 return;
817
818 /* Handle session de-registration. */
819 bs = pcn->pcn_bs;
820 pcn->pcn_bs = NULL;
821 bs->refcount--;
822
823 /* Handle ptm_client deregistration. */
824 pc = pcn->pcn_pc;
825 pcn->pcn_pc = NULL;
826 TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
827
828 XFREE(MTYPE_BFDD_NOTIFICATION, pcn);
829}