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