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