]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/ptm_adapter.c
lib/zlog: fix printfrr format attribute
[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 */
24843702 83static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...)
d3af6147 84{
24843702
RZ
85 char timers[3][128] = {};
86 char addr[3][128] = {};
87 char cbit_str[32];
88 char msgbuf[256];
89 va_list vl;
90
91 /* Avoid debug calculations if it's disabled. */
92 if (bglobal.debug_zebra == false)
93 return;
d3af6147
RZ
94
95 snprintf(addr[0], sizeof(addr[0]), "peer:%s", satostr(&bpc->bpc_peer));
96 if (bpc->bpc_local.sa_sin.sin_family)
97 snprintf(addr[1], sizeof(addr[1]), " local:%s",
98 satostr(&bpc->bpc_local));
99
100 if (bpc->bpc_has_localif)
101 snprintf(addr[2], sizeof(addr[2]), " ifname:%s",
102 bpc->bpc_localif);
103
104 if (bpc->bpc_has_vrfname)
105 snprintf(addr[2], sizeof(addr[2]), " vrf:%s", bpc->bpc_vrfname);
106
107 if (bpc->bpc_has_recvinterval)
24843702 108 snprintf(timers[0], sizeof(timers[0]), " rx:%" PRIu64,
d3af6147
RZ
109 bpc->bpc_recvinterval);
110
111 if (bpc->bpc_has_txinterval)
24843702 112 snprintf(timers[1], sizeof(timers[1]), " tx:%" PRIu64,
d3af6147
RZ
113 bpc->bpc_recvinterval);
114
115 if (bpc->bpc_has_detectmultiplier)
116 snprintf(timers[2], sizeof(timers[2]), " detect-multiplier:%d",
117 bpc->bpc_detectmultiplier);
118
24843702 119 snprintf(cbit_str, sizeof(cbit_str), " cbit:0x%02x", bpc->bpc_cbit);
9beff0bd 120
24843702
RZ
121 va_start(vl, fmt);
122 vsnprintf(msgbuf, sizeof(msgbuf), fmt, vl);
123 va_end(vl);
d3af6147 124
24843702
RZ
125 zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s]", msgbuf,
126 bpc->bpc_mhop ? "yes" : "no", addr[0], addr[1], addr[2],
127 timers[0], timers[1], timers[2], cbit_str);
128}
d3af6147 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
7555dc61 153int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state)
d3af6147
RZ
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
9beff0bd 176 * - c: cbit
d3af6147
RZ
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 */
45b000d0
PG
186 if (bs->vrf)
187 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, bs->vrf->vrf_id);
188 else
189 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
d3af6147 190
971532e2
RZ
191 /* This header will be handled by `zebra_ptm.c`. */
192 stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
193
d3af6147 194 /* NOTE: Interface is a shortcut to avoid comparing source address. */
80edb675
RZ
195 if (bs->ifp != NULL)
196 stream_putl(msg, bs->ifp->ifindex);
197 else
198 stream_putl(msg, IFINDEX_INTERNAL);
d3af6147
RZ
199
200 /* BFD destination prefix information. */
79b4a6fc 201 _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
d3af6147
RZ
202
203 /* BFD status */
7555dc61 204 switch (notify_state) {
d3af6147
RZ
205 case PTM_BFD_UP:
206 stream_putl(msg, BFD_STATUS_UP);
207 break;
208
209 case PTM_BFD_ADM_DOWN:
7555dc61
S
210 stream_putl(msg, BFD_STATUS_ADMIN_DOWN);
211 break;
212
d3af6147
RZ
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:
259b64eb 260 zlog_warn("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);
d3af6147
RZ
315
316 /* Register/update peer information. */
317 _ptm_msg_read_address(msg, &bpc->bpc_peer);
318
319 /* Determine IP type from peer destination. */
320 bpc->bpc_ipv4 = (bpc->bpc_peer.sa_sin.sin_family == AF_INET);
321
322 /* Get peer configuration. */
323 if (command != ZEBRA_BFD_DEST_DEREGISTER) {
324 STREAM_GETL(msg, bpc->bpc_recvinterval);
325 bpc->bpc_has_recvinterval =
326 (bpc->bpc_recvinterval != BPC_DEF_RECEIVEINTERVAL);
327
328 STREAM_GETL(msg, bpc->bpc_txinterval);
329 bpc->bpc_has_txinterval =
330 (bpc->bpc_txinterval != BPC_DEF_TRANSMITINTERVAL);
331
332 STREAM_GETC(msg, bpc->bpc_detectmultiplier);
333 bpc->bpc_has_detectmultiplier =
334 (bpc->bpc_detectmultiplier != BPC_DEF_DETECTMULTIPLIER);
335 }
336
337 /* Read (single|multi)hop and its options. */
338 STREAM_GETC(msg, bpc->bpc_mhop);
339 if (bpc->bpc_mhop) {
340 /* Read multihop source address and TTL. */
341 _ptm_msg_read_address(msg, &bpc->bpc_local);
342 STREAM_GETC(msg, ttl);
d3af6147
RZ
343 } else {
344 /* If target is IPv6, then we must obtain local address. */
345 if (bpc->bpc_ipv4 == false)
346 _ptm_msg_read_address(msg, &bpc->bpc_local);
347
348 /*
349 * Read interface name and make sure it fits our data
350 * structure, otherwise fail.
351 */
352 STREAM_GETC(msg, ifnamelen);
ae9f45a3 353 if (ifnamelen >= sizeof(bpc->bpc_localif)) {
259b64eb 354 zlog_err("ptm-read: interface name is too big");
d3af6147
RZ
355 return -1;
356 }
357
358 bpc->bpc_has_localif = ifnamelen > 0;
359 if (bpc->bpc_has_localif) {
360 STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
361 bpc->bpc_localif[ifnamelen] = 0;
362 }
363 }
45b000d0
PG
364 if (vrf_id != VRF_DEFAULT) {
365 struct vrf *vrf;
366
367 vrf = vrf_lookup_by_id(vrf_id);
368 if (vrf) {
369 bpc->bpc_has_vrfname = true;
370 strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname));
371 } else {
259b64eb
RZ
372 zlog_err("ptm-read: vrf id %u could not be identified",
373 vrf_id);
45b000d0
PG
374 return -1;
375 }
3a20889f
PG
376 } else {
377 bpc->bpc_has_vrfname = true;
378 strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
45b000d0 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)) {
259b64eb 387 zlog_warn("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;
d3af6147
RZ
400 struct bfd_session *bs;
401 struct bfd_peer_cfg bpc;
402
403 /* Read the client context and peer data. */
45b000d0 404 if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1)
d3af6147
RZ
405 return;
406
24843702 407 debug_printbpc(&bpc, "ptm-add-dest: register peer");
d3af6147
RZ
408
409 /* Find or start new BFD session. */
410 bs = bs_peer_find(&bpc);
411 if (bs == NULL) {
412 bs = ptm_bfd_sess_new(&bpc);
413 if (bs == NULL) {
48da2c31
RZ
414 if (bglobal.debug_zebra)
415 zlog_debug(
416 "ptm-add-dest: failed to create BFD session");
d3af6147
RZ
417 return;
418 }
419 } else {
420 /* Don't try to change echo/shutdown state. */
b88113ef 421 bpc.bpc_echo = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
d3af6147 422 bpc.bpc_shutdown =
b88113ef 423 CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
d3af6147
RZ
424 }
425
426 /* Create client peer notification register. */
08de92af 427 pcn_new(pc, bs);
d3af6147 428
7555dc61 429 ptm_bfd_notify(bs, bs->ses_state);
d3af6147
RZ
430}
431
45b000d0 432static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
d3af6147
RZ
433{
434 struct ptm_client *pc;
435 struct ptm_client_notification *pcn;
436 struct bfd_session *bs;
437 struct bfd_peer_cfg bpc;
438
439 /* Read the client context and peer data. */
45b000d0 440 if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, vrf_id, &bpc, &pc) == -1)
d3af6147
RZ
441 return;
442
24843702 443 debug_printbpc(&bpc, "ptm-del-dest: deregister peer");
d3af6147
RZ
444
445 /* Find or start new BFD session. */
446 bs = bs_peer_find(&bpc);
447 if (bs == NULL) {
48da2c31
RZ
448 if (bglobal.debug_zebra)
449 zlog_debug("ptm-del-dest: failed to find BFD session");
d3af6147
RZ
450 return;
451 }
452
453 /* Unregister client peer notification. */
454 pcn = pcn_lookup(pc, bs);
455 pcn_free(pcn);
4c741971 456 if (bs->refcount ||
b88113ef 457 CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
4c741971 458 return;
7555dc61
S
459
460 bs->ses_state = PTM_BFD_ADM_DOWN;
461 ptm_bfd_snd(bs, 0);
462
bc50bcc8 463 ptm_bfd_sess_del(&bpc);
d3af6147
RZ
464}
465
466/*
467 * header: command, VRF
468 * l: pid
469 */
470static void bfdd_client_register(struct stream *msg)
471{
d3af6147
RZ
472 uint32_t pid;
473
474 /* Find or allocate process context data. */
475 STREAM_GETL(msg, pid);
476
08de92af 477 pc_new(pid);
d3af6147
RZ
478
479 return;
480
481stream_failure:
259b64eb 482 zlog_err("ptm-add-client: failed to register client");
d3af6147
RZ
483}
484
a375de5c
RZ
485/*
486 * header: command, VRF
487 * l: pid
488 */
489static void bfdd_client_deregister(struct stream *msg)
490{
491 struct ptm_client *pc;
492 uint32_t pid;
493
494 /* Find or allocate process context data. */
495 STREAM_GETL(msg, pid);
496
497 pc = pc_lookup(pid);
498 if (pc == NULL) {
48da2c31
RZ
499 if (bglobal.debug_zebra)
500 zlog_debug("ptm-del-client: failed to find client: %u",
501 pid);
a375de5c
RZ
502 return;
503 }
504
505 pc_free(pc);
506
507 return;
508
509stream_failure:
259b64eb 510 zlog_err("ptm-del-client: failed to deregister client");
a375de5c
RZ
511}
512
121f9dee 513static int bfdd_replay(ZAPI_CALLBACK_ARGS)
d3af6147 514{
121f9dee 515 struct stream *msg = zclient->ibuf;
d3af6147
RZ
516 uint32_t rcmd;
517
518 STREAM_GETL(msg, rcmd);
519
520 switch (rcmd) {
521 case ZEBRA_BFD_DEST_REGISTER:
522 case ZEBRA_BFD_DEST_UPDATE:
45b000d0 523 bfdd_dest_register(msg, vrf_id);
d3af6147
RZ
524 break;
525 case ZEBRA_BFD_DEST_DEREGISTER:
45b000d0 526 bfdd_dest_deregister(msg, vrf_id);
d3af6147
RZ
527 break;
528 case ZEBRA_BFD_CLIENT_REGISTER:
529 bfdd_client_register(msg);
530 break;
a375de5c
RZ
531 case ZEBRA_BFD_CLIENT_DEREGISTER:
532 bfdd_client_deregister(msg);
533 break;
d3af6147
RZ
534
535 default:
48da2c31
RZ
536 if (bglobal.debug_zebra)
537 zlog_debug("ptm-replay: invalid message type %u", rcmd);
d3af6147
RZ
538 return -1;
539 }
540
541 return 0;
542
543stream_failure:
259b64eb 544 zlog_err("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 579 /* Interface name mismatch. */
79b4a6fc 580 if (strcmp(ifp->name, bs->key.ifname))
d245e522 581 continue;
a36898e7
DS
582 vrf = vrf_lookup_by_id(ifp->vrf_id);
583 if (!vrf)
584 continue;
b4335515
PG
585 if (bs->key.vrfname[0] &&
586 strcmp(vrf->name, bs->key.vrfname))
587 continue;
d245e522
RZ
588 /* Skip enabled sessions. */
589 if (bs->sock != -1)
590 continue;
591
592 /* Try to enable it. */
593 bfd_session_enable(bs);
594 }
595}
596
597static void bfdd_sessions_disable_interface(struct interface *ifp)
598{
599 struct bfd_session_observer *bso;
600 struct bfd_session *bs;
601
602 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
d245e522 603 bs = bso->bso_bs;
79b4a6fc 604 if (strcmp(ifp->name, bs->key.ifname))
d245e522
RZ
605 continue;
606 /* Skip disabled sessions. */
607 if (bs->sock == -1)
608 continue;
609
d245e522
RZ
610 bfd_session_disable(bs);
611
d245e522
RZ
612 }
613}
614
d24af713
PG
615void bfdd_sessions_enable_vrf(struct vrf *vrf)
616{
617 struct bfd_session_observer *bso;
618 struct bfd_session *bs;
619
620 /* it may affect configs without interfaces */
621 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
622 bs = bso->bso_bs;
f06e248c
PG
623 /* update name */
624 if (bs->vrf && bs->vrf == vrf) {
625 if (!strmatch(bs->key.vrfname, vrf->name))
626 bfd_session_update_vrf_name(bs, vrf);
627 }
d24af713
PG
628 if (bs->vrf)
629 continue;
630 if (bs->key.vrfname[0] &&
631 strcmp(vrf->name, bs->key.vrfname))
632 continue;
633 /* need to update the vrf information on
634 * bs so that callbacks are handled
635 */
636 bs->vrf = vrf;
637 /* Skip enabled sessions. */
638 if (bs->sock != -1)
639 continue;
640 /* Try to enable it. */
641 bfd_session_enable(bs);
642 }
643}
644
645void bfdd_sessions_disable_vrf(struct vrf *vrf)
646{
647 struct bfd_session_observer *bso;
648 struct bfd_session *bs;
649
650 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
d24af713
PG
651 bs = bso->bso_bs;
652 if (bs->key.vrfname[0] &&
653 strcmp(vrf->name, bs->key.vrfname))
654 continue;
655 /* Skip disabled sessions. */
656 if (bs->sock == -1)
657 continue;
658
d24af713
PG
659 bfd_session_disable(bs);
660 }
661}
662
3c3c3252 663static int bfd_ifp_destroy(struct interface *ifp)
80edb675 664{
48da2c31
RZ
665 if (bglobal.debug_zebra)
666 zlog_debug("zclient: delete interface %s", ifp->name);
667
d245e522 668 bfdd_sessions_disable_interface(ifp);
80edb675
RZ
669
670 return 0;
671}
672
121f9dee 673static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS)
b333abc2
RZ
674{
675 struct interface *ifp;
676 vrf_id_t nvrfid;
677
121f9dee 678 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid);
b333abc2
RZ
679 if (ifp == NULL)
680 return 0;
a36898e7
DS
681
682 if_update_to_new_vrf(ifp, nvrfid);
b333abc2
RZ
683
684 return 0;
685}
686
261e0ba9
RZ
687static void bfdd_sessions_enable_address(struct connected *ifc)
688{
689 struct bfd_session_observer *bso;
690 struct bfd_session *bs;
691 struct prefix prefix;
692
693 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
261e0ba9
RZ
694 /* Skip enabled sessions. */
695 bs = bso->bso_bs;
696 if (bs->sock != -1)
697 continue;
698
699 /* Check address. */
700 prefix = bso->bso_addr;
701 prefix.prefixlen = ifc->address->prefixlen;
702 if (prefix_cmp(&prefix, ifc->address))
703 continue;
704
705 /* Try to enable it. */
706 bfd_session_enable(bs);
707 }
708}
709
121f9dee 710static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
261e0ba9
RZ
711{
712 struct connected *ifc;
48da2c31 713 char buf[64];
261e0ba9 714
121f9dee 715 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
261e0ba9
RZ
716 if (ifc == NULL)
717 return 0;
718
48da2c31
RZ
719 if (bglobal.debug_zebra)
720 zlog_debug("zclient: %s local address %s",
721 cmd == ZEBRA_INTERFACE_ADDRESS_ADD ? "add"
722 : "delete",
723 prefix2str(ifc->address, buf, sizeof(buf)));
724
261e0ba9
RZ
725 bfdd_sessions_enable_address(ifc);
726
727 return 0;
728}
729
138c5a74
DS
730static int bfd_ifp_create(struct interface *ifp)
731{
48da2c31
RZ
732 if (bglobal.debug_zebra)
733 zlog_debug("zclient: add interface %s", ifp->name);
734
ef7bd2a3
DS
735 bfdd_sessions_enable_interface(ifp);
736
138c5a74
DS
737 return 0;
738}
739
d3af6147
RZ
740void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
741{
138c5a74 742 if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy);
26f63a1e 743 zclient = zclient_new(master, &zclient_options_default);
d3af6147
RZ
744 assert(zclient != NULL);
745 zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
746
747 /*
748 * We'll receive all messages through replay, however it will
749 * contain a special field with the real command inside so we
750 * avoid having to create too many handlers.
751 */
752 zclient->bfd_dest_replay = bfdd_replay;
971532e2
RZ
753
754 /* Send replay request on zebra connect. */
755 zclient->zebra_connected = bfdd_zebra_connected;
80edb675 756
b333abc2
RZ
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}