]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/ptm_adapter.c
bfdd: constify satostr
[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
259b64eb
RZ
123 zlog_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);
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
7555dc61 156int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state)
d3af6147
RZ
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 */
7555dc61 207 switch (notify_state) {
d3af6147
RZ
208 case PTM_BFD_UP:
209 stream_putl(msg, BFD_STATUS_UP);
210 break;
211
212 case PTM_BFD_ADM_DOWN:
7555dc61
S
213 stream_putl(msg, BFD_STATUS_ADMIN_DOWN);
214 break;
215
d3af6147
RZ
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. */
79b4a6fc 227 _ptm_msg_address(msg, bs->key.family, &bs->key.local);
d3af6147 228
9beff0bd
PG
229 stream_putc(msg, bs->remote_cbit);
230
d3af6147
RZ
231 /* Write packet size. */
232 stream_putw_at(msg, 0, stream_get_endp(msg));
233
234 return zclient_send_message(zclient);
235}
236
237static 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:
259b64eb 263 zlog_warn("ptm-read-address: invalid family: %d", family);
d3af6147
RZ
264 break;
265 }
266
267stream_failure:
268 memset(sa, 0, sizeof(*sa));
269}
270
45b000d0 271static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
d3af6147
RZ
272 struct bfd_peer_cfg *bpc, struct ptm_client **pc)
273{
274 uint32_t pid;
f0d2be33 275 uint8_t ttl __attribute__((unused));
ae9eebca 276 size_t ifnamelen;
d3af6147
RZ
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
9beff0bd 305 * - c: bfd_cbit
d3af6147
RZ
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);
d3af6147
RZ
318
319 /* Register/update peer information. */
320 _ptm_msg_read_address(msg, &bpc->bpc_peer);
321
322 /* Determine IP type from peer destination. */
323 bpc->bpc_ipv4 = (bpc->bpc_peer.sa_sin.sin_family == AF_INET);
324
325 /* Get peer configuration. */
326 if (command != ZEBRA_BFD_DEST_DEREGISTER) {
327 STREAM_GETL(msg, bpc->bpc_recvinterval);
328 bpc->bpc_has_recvinterval =
329 (bpc->bpc_recvinterval != BPC_DEF_RECEIVEINTERVAL);
330
331 STREAM_GETL(msg, bpc->bpc_txinterval);
332 bpc->bpc_has_txinterval =
333 (bpc->bpc_txinterval != BPC_DEF_TRANSMITINTERVAL);
334
335 STREAM_GETC(msg, bpc->bpc_detectmultiplier);
336 bpc->bpc_has_detectmultiplier =
337 (bpc->bpc_detectmultiplier != BPC_DEF_DETECTMULTIPLIER);
338 }
339
340 /* Read (single|multi)hop and its options. */
341 STREAM_GETC(msg, bpc->bpc_mhop);
342 if (bpc->bpc_mhop) {
343 /* Read multihop source address and TTL. */
344 _ptm_msg_read_address(msg, &bpc->bpc_local);
345 STREAM_GETC(msg, ttl);
d3af6147
RZ
346 } else {
347 /* If target is IPv6, then we must obtain local address. */
348 if (bpc->bpc_ipv4 == false)
349 _ptm_msg_read_address(msg, &bpc->bpc_local);
350
351 /*
352 * Read interface name and make sure it fits our data
353 * structure, otherwise fail.
354 */
355 STREAM_GETC(msg, ifnamelen);
ae9f45a3 356 if (ifnamelen >= sizeof(bpc->bpc_localif)) {
259b64eb 357 zlog_err("ptm-read: interface name is too big");
d3af6147
RZ
358 return -1;
359 }
360
361 bpc->bpc_has_localif = ifnamelen > 0;
362 if (bpc->bpc_has_localif) {
363 STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
364 bpc->bpc_localif[ifnamelen] = 0;
365 }
366 }
45b000d0
PG
367 if (vrf_id != VRF_DEFAULT) {
368 struct vrf *vrf;
369
370 vrf = vrf_lookup_by_id(vrf_id);
371 if (vrf) {
372 bpc->bpc_has_vrfname = true;
373 strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname));
374 } else {
259b64eb
RZ
375 zlog_err("ptm-read: vrf id %u could not be identified",
376 vrf_id);
45b000d0
PG
377 return -1;
378 }
3a20889f
PG
379 } else {
380 bpc->bpc_has_vrfname = true;
381 strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
45b000d0 382 }
d3af6147 383
9beff0bd
PG
384 STREAM_GETC(msg, bpc->bpc_cbit);
385
d3af6147
RZ
386 /* Sanity check: peer and local address must match IP types. */
387 if (bpc->bpc_local.sa_sin.sin_family != 0
388 && (bpc->bpc_local.sa_sin.sin_family
389 != bpc->bpc_peer.sa_sin.sin_family)) {
259b64eb 390 zlog_warn("ptm-read: peer family doesn't match local type");
d3af6147
RZ
391 return -1;
392 }
393
394 return 0;
395
396stream_failure:
397 return -1;
398}
399
45b000d0 400static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
d3af6147
RZ
401{
402 struct ptm_client *pc;
d3af6147
RZ
403 struct bfd_session *bs;
404 struct bfd_peer_cfg bpc;
405
406 /* Read the client context and peer data. */
45b000d0 407 if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1)
d3af6147
RZ
408 return;
409
410 DEBUG_PRINTBPC(&bpc);
411
412 /* Find or start new BFD session. */
413 bs = bs_peer_find(&bpc);
414 if (bs == NULL) {
415 bs = ptm_bfd_sess_new(&bpc);
416 if (bs == NULL) {
48da2c31
RZ
417 if (bglobal.debug_zebra)
418 zlog_debug(
419 "ptm-add-dest: failed to create BFD session");
d3af6147
RZ
420 return;
421 }
422 } else {
423 /* Don't try to change echo/shutdown state. */
b88113ef 424 bpc.bpc_echo = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
d3af6147 425 bpc.bpc_shutdown =
b88113ef 426 CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
d3af6147
RZ
427 }
428
429 /* Create client peer notification register. */
08de92af 430 pcn_new(pc, bs);
d3af6147 431
7555dc61 432 ptm_bfd_notify(bs, bs->ses_state);
d3af6147
RZ
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) {
48da2c31
RZ
451 if (bglobal.debug_zebra)
452 zlog_debug("ptm-del-dest: failed to find BFD session");
d3af6147
RZ
453 return;
454 }
455
456 /* Unregister client peer notification. */
457 pcn = pcn_lookup(pc, bs);
458 pcn_free(pcn);
4c741971 459 if (bs->refcount ||
b88113ef 460 CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
4c741971 461 return;
7555dc61
S
462
463 bs->ses_state = PTM_BFD_ADM_DOWN;
464 ptm_bfd_snd(bs, 0);
465
bc50bcc8 466 ptm_bfd_sess_del(&bpc);
d3af6147
RZ
467}
468
469/*
470 * header: command, VRF
471 * l: pid
472 */
473static void bfdd_client_register(struct stream *msg)
474{
d3af6147
RZ
475 uint32_t pid;
476
477 /* Find or allocate process context data. */
478 STREAM_GETL(msg, pid);
479
08de92af 480 pc_new(pid);
d3af6147
RZ
481
482 return;
483
484stream_failure:
259b64eb 485 zlog_err("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) {
48da2c31
RZ
502 if (bglobal.debug_zebra)
503 zlog_debug("ptm-del-client: failed to find client: %u",
504 pid);
a375de5c
RZ
505 return;
506 }
507
508 pc_free(pc);
509
510 return;
511
512stream_failure:
259b64eb 513 zlog_err("ptm-del-client: failed to deregister client");
a375de5c
RZ
514}
515
121f9dee 516static int bfdd_replay(ZAPI_CALLBACK_ARGS)
d3af6147 517{
121f9dee 518 struct stream *msg = zclient->ibuf;
d3af6147
RZ
519 uint32_t rcmd;
520
521 STREAM_GETL(msg, rcmd);
522
523 switch (rcmd) {
524 case ZEBRA_BFD_DEST_REGISTER:
525 case ZEBRA_BFD_DEST_UPDATE:
45b000d0 526 bfdd_dest_register(msg, vrf_id);
d3af6147
RZ
527 break;
528 case ZEBRA_BFD_DEST_DEREGISTER:
45b000d0 529 bfdd_dest_deregister(msg, vrf_id);
d3af6147
RZ
530 break;
531 case ZEBRA_BFD_CLIENT_REGISTER:
532 bfdd_client_register(msg);
533 break;
a375de5c
RZ
534 case ZEBRA_BFD_CLIENT_DEREGISTER:
535 bfdd_client_deregister(msg);
536 break;
d3af6147
RZ
537
538 default:
48da2c31
RZ
539 if (bglobal.debug_zebra)
540 zlog_debug("ptm-replay: invalid message type %u", rcmd);
d3af6147
RZ
541 return -1;
542 }
543
544 return 0;
545
546stream_failure:
259b64eb 547 zlog_err("ptm-replay: failed to find command");
d3af6147
RZ
548 return -1;
549}
550
971532e2
RZ
551static void bfdd_zebra_connected(struct zclient *zc)
552{
553 struct stream *msg = zc->obuf;
554
788378fe
RZ
555 /* Clean-up and free ptm clients data memory. */
556 pc_free_all();
557
971532e2
RZ
558 /*
559 * The replay is an empty message just to trigger client daemons
560 * configuration replay.
561 */
562 stream_reset(msg);
563 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
564 stream_putl(msg, ZEBRA_BFD_DEST_REPLAY);
565 stream_putw_at(msg, 0, stream_get_endp(msg));
566
80edb675
RZ
567 /* Ask for interfaces information. */
568 zclient_create_header(msg, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
569
570 /* Send requests. */
971532e2
RZ
571 zclient_send_message(zclient);
572}
573
d245e522
RZ
574static void bfdd_sessions_enable_interface(struct interface *ifp)
575{
576 struct bfd_session_observer *bso;
577 struct bfd_session *bs;
a36898e7 578 struct vrf *vrf;
d245e522
RZ
579
580 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
b4335515 581 bs = bso->bso_bs;
d245e522 582 /* Interface name mismatch. */
79b4a6fc 583 if (strcmp(ifp->name, bs->key.ifname))
d245e522 584 continue;
a36898e7
DS
585 vrf = vrf_lookup_by_id(ifp->vrf_id);
586 if (!vrf)
587 continue;
b4335515
PG
588 if (bs->key.vrfname[0] &&
589 strcmp(vrf->name, bs->key.vrfname))
590 continue;
d245e522
RZ
591 /* Skip enabled sessions. */
592 if (bs->sock != -1)
593 continue;
594
595 /* Try to enable it. */
596 bfd_session_enable(bs);
597 }
598}
599
600static void bfdd_sessions_disable_interface(struct interface *ifp)
601{
602 struct bfd_session_observer *bso;
603 struct bfd_session *bs;
604
605 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
d245e522 606 bs = bso->bso_bs;
79b4a6fc 607 if (strcmp(ifp->name, bs->key.ifname))
d245e522
RZ
608 continue;
609 /* Skip disabled sessions. */
610 if (bs->sock == -1)
611 continue;
612
d245e522
RZ
613 bfd_session_disable(bs);
614
d245e522
RZ
615 }
616}
617
d24af713
PG
618void bfdd_sessions_enable_vrf(struct vrf *vrf)
619{
620 struct bfd_session_observer *bso;
621 struct bfd_session *bs;
622
623 /* it may affect configs without interfaces */
624 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
625 bs = bso->bso_bs;
f06e248c
PG
626 /* update name */
627 if (bs->vrf && bs->vrf == vrf) {
628 if (!strmatch(bs->key.vrfname, vrf->name))
629 bfd_session_update_vrf_name(bs, vrf);
630 }
d24af713
PG
631 if (bs->vrf)
632 continue;
633 if (bs->key.vrfname[0] &&
634 strcmp(vrf->name, bs->key.vrfname))
635 continue;
636 /* need to update the vrf information on
637 * bs so that callbacks are handled
638 */
639 bs->vrf = vrf;
640 /* Skip enabled sessions. */
641 if (bs->sock != -1)
642 continue;
643 /* Try to enable it. */
644 bfd_session_enable(bs);
645 }
646}
647
648void bfdd_sessions_disable_vrf(struct vrf *vrf)
649{
650 struct bfd_session_observer *bso;
651 struct bfd_session *bs;
652
653 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
d24af713
PG
654 bs = bso->bso_bs;
655 if (bs->key.vrfname[0] &&
656 strcmp(vrf->name, bs->key.vrfname))
657 continue;
658 /* Skip disabled sessions. */
659 if (bs->sock == -1)
660 continue;
661
d24af713
PG
662 bfd_session_disable(bs);
663 }
664}
665
3c3c3252 666static int bfd_ifp_destroy(struct interface *ifp)
80edb675 667{
48da2c31
RZ
668 if (bglobal.debug_zebra)
669 zlog_debug("zclient: delete interface %s", ifp->name);
670
d245e522 671 bfdd_sessions_disable_interface(ifp);
80edb675
RZ
672
673 return 0;
674}
675
121f9dee 676static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS)
b333abc2
RZ
677{
678 struct interface *ifp;
679 vrf_id_t nvrfid;
680
121f9dee 681 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid);
b333abc2
RZ
682 if (ifp == NULL)
683 return 0;
a36898e7
DS
684
685 if_update_to_new_vrf(ifp, nvrfid);
b333abc2
RZ
686
687 return 0;
688}
689
261e0ba9
RZ
690static void bfdd_sessions_enable_address(struct connected *ifc)
691{
692 struct bfd_session_observer *bso;
693 struct bfd_session *bs;
694 struct prefix prefix;
695
696 TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
261e0ba9
RZ
697 /* Skip enabled sessions. */
698 bs = bso->bso_bs;
699 if (bs->sock != -1)
700 continue;
701
702 /* Check address. */
703 prefix = bso->bso_addr;
704 prefix.prefixlen = ifc->address->prefixlen;
705 if (prefix_cmp(&prefix, ifc->address))
706 continue;
707
708 /* Try to enable it. */
709 bfd_session_enable(bs);
710 }
711}
712
121f9dee 713static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
261e0ba9
RZ
714{
715 struct connected *ifc;
48da2c31 716 char buf[64];
261e0ba9 717
121f9dee 718 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
261e0ba9
RZ
719 if (ifc == NULL)
720 return 0;
721
48da2c31
RZ
722 if (bglobal.debug_zebra)
723 zlog_debug("zclient: %s local address %s",
724 cmd == ZEBRA_INTERFACE_ADDRESS_ADD ? "add"
725 : "delete",
726 prefix2str(ifc->address, buf, sizeof(buf)));
727
261e0ba9
RZ
728 bfdd_sessions_enable_address(ifc);
729
730 return 0;
731}
732
138c5a74
DS
733static int bfd_ifp_create(struct interface *ifp)
734{
48da2c31
RZ
735 if (bglobal.debug_zebra)
736 zlog_debug("zclient: add interface %s", ifp->name);
737
ef7bd2a3
DS
738 bfdd_sessions_enable_interface(ifp);
739
138c5a74
DS
740 return 0;
741}
742
d3af6147
RZ
743void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
744{
138c5a74 745 if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy);
26f63a1e 746 zclient = zclient_new(master, &zclient_options_default);
d3af6147
RZ
747 assert(zclient != NULL);
748 zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
749
750 /*
751 * We'll receive all messages through replay, however it will
752 * contain a special field with the real command inside so we
753 * avoid having to create too many handlers.
754 */
755 zclient->bfd_dest_replay = bfdd_replay;
971532e2
RZ
756
757 /* Send replay request on zebra connect. */
758 zclient->zebra_connected = bfdd_zebra_connected;
80edb675 759
b333abc2
RZ
760 /* Learn about interface VRF. */
761 zclient->interface_vrf_update = bfdd_interface_vrf_update;
261e0ba9
RZ
762
763 /* Learn about new addresses being registered. */
764 zclient->interface_address_add = bfdd_interface_address_update;
765 zclient->interface_address_delete = bfdd_interface_address_update;
d3af6147
RZ
766}
767
54aadda1
PG
768void bfdd_zclient_register(vrf_id_t vrf_id)
769{
770 if (!zclient || zclient->sock < 0)
771 return;
772 zclient_send_reg_requests(zclient, vrf_id);
773}
774
775void bfdd_zclient_unregister(vrf_id_t vrf_id)
776{
777 if (!zclient || zclient->sock < 0)
778 return;
779 zclient_send_dereg_requests(zclient, vrf_id);
780}
781
d3af6147
RZ
782void bfdd_zclient_stop(void)
783{
784 zclient_stop(zclient);
788378fe
RZ
785
786 /* Clean-up and free ptm clients data memory. */
787 pc_free_all();
d3af6147
RZ
788}
789
790
791/*
792 * Client handling.
793 */
794static struct ptm_client *pc_lookup(uint32_t pid)
795{
796 struct ptm_client *pc;
797
798 TAILQ_FOREACH (pc, &pcqueue, pc_entry) {
799 if (pc->pc_pid != pid)
800 continue;
801
802 break;
803 }
804
805 return pc;
806}
807
808static struct ptm_client *pc_new(uint32_t pid)
809{
810 struct ptm_client *pc;
811
812 /* Look up first, if not found create the client. */
813 pc = pc_lookup(pid);
814 if (pc != NULL)
815 return pc;
816
817 /* Allocate the client data and save it. */
818 pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc));
d3af6147
RZ
819
820 pc->pc_pid = pid;
821 TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
822 return pc;
823}
824
a375de5c
RZ
825static void pc_free(struct ptm_client *pc)
826{
827 struct ptm_client_notification *pcn;
828
829 if (pc == NULL)
830 return;
831
832 TAILQ_REMOVE(&pcqueue, pc, pc_entry);
833
834 while (!TAILQ_EMPTY(&pc->pc_pcnqueue)) {
835 pcn = TAILQ_FIRST(&pc->pc_pcnqueue);
836 pcn_free(pcn);
837 }
838
839 XFREE(MTYPE_BFDD_CONTROL, pc);
840}
841
788378fe
RZ
842static void pc_free_all(void)
843{
844 struct ptm_client *pc;
845
846 while (!TAILQ_EMPTY(&pcqueue)) {
847 pc = TAILQ_FIRST(&pcqueue);
848 pc_free(pc);
849 }
850}
851
d3af6147
RZ
852static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
853 struct bfd_session *bs)
854{
855 struct ptm_client_notification *pcn;
856
857 /* Try to find an existing pcn fist. */
858 pcn = pcn_lookup(pc, bs);
859 if (pcn != NULL)
860 return pcn;
861
862 /* Save the client notification data. */
863 pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn));
d3af6147
RZ
864
865 TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
866 pcn->pcn_pc = pc;
867 pcn->pcn_bs = bs;
868 bs->refcount++;
869
870 return pcn;
871}
872
873static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
874 struct bfd_session *bs)
875{
876 struct ptm_client_notification *pcn;
877
878 TAILQ_FOREACH (pcn, &pc->pc_pcnqueue, pcn_entry) {
879 if (pcn->pcn_bs != bs)
880 continue;
881
882 break;
883 }
884
885 return pcn;
886}
887
888static void pcn_free(struct ptm_client_notification *pcn)
889{
890 struct ptm_client *pc;
891 struct bfd_session *bs;
892
893 if (pcn == NULL)
894 return;
895
896 /* Handle session de-registration. */
897 bs = pcn->pcn_bs;
898 pcn->pcn_bs = NULL;
899 bs->refcount--;
900
901 /* Handle ptm_client deregistration. */
902 pc = pcn->pcn_pc;
903 pcn->pcn_pc = NULL;
904 TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
905
906 XFREE(MTYPE_BFDD_NOTIFICATION, pcn);
907}