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