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