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