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