]>
git.proxmox.com Git - mirror_frr.git/blob - bfdd/control.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*********************************************************************
3 * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
5 * control.c: implements the BFD daemon control socket. It will be used
6 * to talk with clients daemon/scripts/consumers.
10 * Rafael Zalamena <rzalamena@opensourcerouting.org>
22 static int sock_set_nonblock(int fd
);
23 struct bfd_control_queue
*control_queue_new(struct bfd_control_socket
*bcs
);
24 static void control_queue_free(struct bfd_control_socket
*bcs
,
25 struct bfd_control_queue
*bcq
);
26 static int control_queue_dequeue(struct bfd_control_socket
*bcs
);
27 static int control_queue_enqueue(struct bfd_control_socket
*bcs
,
28 struct bfd_control_msg
*bcm
);
29 static int control_queue_enqueue_first(struct bfd_control_socket
*bcs
,
30 struct bfd_control_msg
*bcm
);
31 struct bfd_notify_peer
*control_notifypeer_new(struct bfd_control_socket
*bcs
,
32 struct bfd_session
*bs
);
33 static void control_notifypeer_free(struct bfd_control_socket
*bcs
,
34 struct bfd_notify_peer
*bnp
);
35 struct bfd_notify_peer
*control_notifypeer_find(struct bfd_control_socket
*bcs
,
36 struct bfd_session
*bs
);
39 struct bfd_control_socket
*control_new(int sd
);
40 static void control_free(struct bfd_control_socket
*bcs
);
41 static void control_reset_buf(struct bfd_control_buffer
*bcb
);
42 static void control_read(struct event
*t
);
43 static void control_write(struct event
*t
);
45 static void control_handle_request_add(struct bfd_control_socket
*bcs
,
46 struct bfd_control_msg
*bcm
);
47 static void control_handle_request_del(struct bfd_control_socket
*bcs
,
48 struct bfd_control_msg
*bcm
);
49 static int notify_add_cb(struct bfd_peer_cfg
*bpc
, void *arg
);
50 static int notify_del_cb(struct bfd_peer_cfg
*bpc
, void *arg
);
51 static void control_handle_notify_add(struct bfd_control_socket
*bcs
,
52 struct bfd_control_msg
*bcm
);
53 static void control_handle_notify_del(struct bfd_control_socket
*bcs
,
54 struct bfd_control_msg
*bcm
);
55 static void _control_handle_notify(struct hash_bucket
*hb
, void *arg
);
56 static void control_handle_notify(struct bfd_control_socket
*bcs
,
57 struct bfd_control_msg
*bcm
);
58 static void control_response(struct bfd_control_socket
*bcs
, uint16_t id
,
59 const char *status
, const char *error
);
61 static void _control_notify_config(struct bfd_control_socket
*bcs
,
62 const char *op
, struct bfd_session
*bs
);
63 static void _control_notify(struct bfd_control_socket
*bcs
,
64 struct bfd_session
*bs
);
70 static int sock_set_nonblock(int fd
)
74 flags
= fcntl(fd
, F_GETFL
, 0);
76 zlog_warn("%s: fcntl F_GETFL: %s", __func__
, strerror(errno
));
81 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
82 zlog_warn("%s: fcntl F_SETFL: %s", __func__
, strerror(errno
));
89 int control_init(const char *path
)
93 struct sockaddr_un sun_
= {
94 .sun_family
= AF_UNIX
,
95 .sun_path
= BFDD_CONTROL_SOCKET
,
99 strlcpy(sun_
.sun_path
, path
, sizeof(sun_
.sun_path
));
101 /* Remove previously created sockets. */
102 unlink(sun_
.sun_path
);
104 sd
= socket(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
);
106 zlog_err("%s: socket: %s", __func__
, strerror(errno
));
111 if (bind(sd
, (struct sockaddr
*)&sun_
, sizeof(sun_
)) == -1) {
112 zlog_err("%s: bind: %s", __func__
, strerror(errno
));
118 if (listen(sd
, SOMAXCONN
) == -1) {
119 zlog_err("%s: listen: %s", __func__
, strerror(errno
));
124 sock_set_nonblock(sd
);
126 bglobal
.bg_csock
= sd
;
131 void control_shutdown(void)
133 struct bfd_control_socket
*bcs
;
135 event_cancel(&bglobal
.bg_csockev
);
137 socket_close(&bglobal
.bg_csock
);
139 while (!TAILQ_EMPTY(&bglobal
.bg_bcslist
)) {
140 bcs
= TAILQ_FIRST(&bglobal
.bg_bcslist
);
145 void control_accept(struct event
*t
)
147 int csock
, sd
= EVENT_FD(t
);
149 csock
= accept(sd
, NULL
, 0);
151 zlog_warn("%s: accept: %s", __func__
, strerror(errno
));
157 event_add_read(master
, control_accept
, NULL
, sd
, &bglobal
.bg_csockev
);
164 struct bfd_control_socket
*control_new(int sd
)
166 struct bfd_control_socket
*bcs
;
168 bcs
= XCALLOC(MTYPE_BFDD_CONTROL
, sizeof(*bcs
));
170 /* Disable notifications by default. */
174 event_add_read(master
, control_read
, bcs
, sd
, &bcs
->bcs_ev
);
176 TAILQ_INIT(&bcs
->bcs_bcqueue
);
177 TAILQ_INIT(&bcs
->bcs_bnplist
);
178 TAILQ_INSERT_TAIL(&bglobal
.bg_bcslist
, bcs
, bcs_entry
);
183 static void control_free(struct bfd_control_socket
*bcs
)
185 struct bfd_control_queue
*bcq
;
186 struct bfd_notify_peer
*bnp
;
188 event_cancel(&(bcs
->bcs_ev
));
189 event_cancel(&(bcs
->bcs_outev
));
193 TAILQ_REMOVE(&bglobal
.bg_bcslist
, bcs
, bcs_entry
);
195 /* Empty output queue. */
196 while (!TAILQ_EMPTY(&bcs
->bcs_bcqueue
)) {
197 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
198 control_queue_free(bcs
, bcq
);
201 /* Empty notification list. */
202 while (!TAILQ_EMPTY(&bcs
->bcs_bnplist
)) {
203 bnp
= TAILQ_FIRST(&bcs
->bcs_bnplist
);
204 control_notifypeer_free(bcs
, bnp
);
207 control_reset_buf(&bcs
->bcs_bin
);
208 XFREE(MTYPE_BFDD_CONTROL
, bcs
);
211 struct bfd_notify_peer
*control_notifypeer_new(struct bfd_control_socket
*bcs
,
212 struct bfd_session
*bs
)
214 struct bfd_notify_peer
*bnp
;
216 bnp
= control_notifypeer_find(bcs
, bs
);
220 bnp
= XCALLOC(MTYPE_BFDD_CONTROL
, sizeof(*bnp
));
222 TAILQ_INSERT_TAIL(&bcs
->bcs_bnplist
, bnp
, bnp_entry
);
229 static void control_notifypeer_free(struct bfd_control_socket
*bcs
,
230 struct bfd_notify_peer
*bnp
)
232 TAILQ_REMOVE(&bcs
->bcs_bnplist
, bnp
, bnp_entry
);
233 bnp
->bnp_bs
->refcount
--;
234 XFREE(MTYPE_BFDD_CONTROL
, bnp
);
237 struct bfd_notify_peer
*control_notifypeer_find(struct bfd_control_socket
*bcs
,
238 struct bfd_session
*bs
)
240 struct bfd_notify_peer
*bnp
;
242 TAILQ_FOREACH (bnp
, &bcs
->bcs_bnplist
, bnp_entry
) {
243 if (bnp
->bnp_bs
== bs
)
250 struct bfd_control_queue
*control_queue_new(struct bfd_control_socket
*bcs
)
252 struct bfd_control_queue
*bcq
;
254 bcq
= XCALLOC(MTYPE_BFDD_NOTIFICATION
, sizeof(*bcq
));
256 control_reset_buf(&bcq
->bcq_bcb
);
257 TAILQ_INSERT_TAIL(&bcs
->bcs_bcqueue
, bcq
, bcq_entry
);
262 static void control_queue_free(struct bfd_control_socket
*bcs
,
263 struct bfd_control_queue
*bcq
)
265 control_reset_buf(&bcq
->bcq_bcb
);
266 TAILQ_REMOVE(&bcs
->bcs_bcqueue
, bcq
, bcq_entry
);
267 XFREE(MTYPE_BFDD_NOTIFICATION
, bcq
);
270 static int control_queue_dequeue(struct bfd_control_socket
*bcs
)
272 struct bfd_control_queue
*bcq
;
274 /* List is empty, nothing to do. */
275 if (TAILQ_EMPTY(&bcs
->bcs_bcqueue
))
278 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
279 control_queue_free(bcs
, bcq
);
281 /* Get the next buffer to send. */
282 if (TAILQ_EMPTY(&bcs
->bcs_bcqueue
))
285 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
286 bcs
->bcs_bout
= &bcq
->bcq_bcb
;
288 bcs
->bcs_outev
= NULL
;
289 event_add_write(master
, control_write
, bcs
, bcs
->bcs_sd
,
295 event_cancel(&(bcs
->bcs_outev
));
296 bcs
->bcs_bout
= NULL
;
300 static int control_queue_enqueue(struct bfd_control_socket
*bcs
,
301 struct bfd_control_msg
*bcm
)
303 struct bfd_control_queue
*bcq
;
304 struct bfd_control_buffer
*bcb
;
306 bcq
= control_queue_new(bcs
);
309 bcb
->bcb_left
= sizeof(struct bfd_control_msg
) + ntohl(bcm
->bcm_length
);
313 /* If this is the first item, then dequeue and start using it. */
314 if (bcs
->bcs_bout
== NULL
) {
317 /* New messages, active write events. */
318 event_add_write(master
, control_write
, bcs
, bcs
->bcs_sd
,
325 static int control_queue_enqueue_first(struct bfd_control_socket
*bcs
,
326 struct bfd_control_msg
*bcm
)
328 struct bfd_control_queue
*bcq
, *bcqn
;
329 struct bfd_control_buffer
*bcb
;
331 /* Enqueue it somewhere. */
332 if (control_queue_enqueue(bcs
, bcm
) == -1)
336 * The item is either the first or the last. So we must first
337 * check the best case where the item is already the first.
339 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
341 if (bcm
== bcb
->bcb_bcm
)
345 * The item was not the first, so it is the last. We'll try to
346 * assign it to the head of the queue, however if there is a
347 * transfer in progress, then we have to make the item as the
350 * Interrupting the transfer of in progress message will cause
351 * the client to lose track of the message position/data.
353 bcqn
= TAILQ_LAST(&bcs
->bcs_bcqueue
, bcqueue
);
354 TAILQ_REMOVE(&bcs
->bcs_bcqueue
, bcqn
, bcq_entry
);
355 if (bcb
->bcb_pos
!= 0) {
357 * First position is already being sent, insert into
360 TAILQ_INSERT_AFTER(&bcs
->bcs_bcqueue
, bcq
, bcqn
, bcq_entry
);
363 * Old message didn't start being sent, we still have
364 * time to put this one in the head of the queue.
366 TAILQ_INSERT_HEAD(&bcs
->bcs_bcqueue
, bcqn
, bcq_entry
);
367 bcb
= &bcqn
->bcq_bcb
;
374 static void control_reset_buf(struct bfd_control_buffer
*bcb
)
376 /* Get ride of old data. */
377 XFREE(MTYPE_BFDD_NOTIFICATION
, bcb
->bcb_buf
);
382 static void control_read(struct event
*t
)
384 struct bfd_control_socket
*bcs
= EVENT_ARG(t
);
385 struct bfd_control_buffer
*bcb
= &bcs
->bcs_bin
;
386 int sd
= bcs
->bcs_sd
;
387 struct bfd_control_msg bcm
;
392 * Check if we have already downloaded message content, if so then skip
394 * download the rest of it and process.
396 * Otherwise download a new message header and allocate the necessary
399 if (bcb
->bcb_buf
!= NULL
)
402 bread
= read(sd
, &bcm
, sizeof(bcm
));
408 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
409 goto schedule_next_read
;
411 zlog_warn("%s: read: %s", __func__
, strerror(errno
));
416 /* Validate header fields. */
417 plen
= ntohl(bcm
.bcm_length
);
419 zlog_debug("%s: client closed due small message length: %d",
420 __func__
, bcm
.bcm_length
);
425 #define FRR_BFD_MAXLEN 10 * 1024
427 if (plen
> FRR_BFD_MAXLEN
) {
428 zlog_debug("%s: client closed, invalid message length: %d",
429 __func__
, bcm
.bcm_length
);
434 if (bcm
.bcm_ver
!= BMV_VERSION_1
) {
435 zlog_debug("%s: client closed due bad version: %d", __func__
,
441 /* Prepare the buffer to load the message. */
442 bcs
->bcs_version
= bcm
.bcm_ver
;
443 bcs
->bcs_type
= bcm
.bcm_type
;
445 bcb
->bcb_pos
= sizeof(bcm
);
446 bcb
->bcb_left
= plen
;
447 bcb
->bcb_buf
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
448 sizeof(bcm
) + bcb
->bcb_left
+ 1);
449 if (bcb
->bcb_buf
== NULL
) {
450 zlog_warn("%s: not enough memory for message size: %zu",
451 __func__
, bcb
->bcb_left
);
456 memcpy(bcb
->bcb_buf
, &bcm
, sizeof(bcm
));
458 /* Terminate data string with NULL for later processing. */
459 bcb
->bcb_buf
[sizeof(bcm
) + bcb
->bcb_left
] = 0;
462 /* Download the remaining data of the message and process it. */
463 bread
= read(sd
, &bcb
->bcb_buf
[bcb
->bcb_pos
], bcb
->bcb_left
);
469 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
470 goto schedule_next_read
;
472 zlog_warn("%s: read: %s", __func__
, strerror(errno
));
477 bcb
->bcb_pos
+= bread
;
478 bcb
->bcb_left
-= bread
;
479 /* We need more data, return to wait more. */
480 if (bcb
->bcb_left
> 0)
481 goto schedule_next_read
;
483 switch (bcb
->bcb_bcm
->bcm_type
) {
484 case BMT_REQUEST_ADD
:
485 control_handle_request_add(bcs
, bcb
->bcb_bcm
);
487 case BMT_REQUEST_DEL
:
488 control_handle_request_del(bcs
, bcb
->bcb_bcm
);
491 control_handle_notify(bcs
, bcb
->bcb_bcm
);
494 control_handle_notify_add(bcs
, bcb
->bcb_bcm
);
497 control_handle_notify_del(bcs
, bcb
->bcb_bcm
);
501 zlog_debug("%s: unhandled message type: %d", __func__
,
502 bcb
->bcb_bcm
->bcm_type
);
503 control_response(bcs
, bcb
->bcb_bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
504 "invalid message type");
508 bcs
->bcs_version
= 0;
510 control_reset_buf(bcb
);
514 event_add_read(master
, control_read
, bcs
, sd
, &bcs
->bcs_ev
);
517 static void control_write(struct event
*t
)
519 struct bfd_control_socket
*bcs
= EVENT_ARG(t
);
520 struct bfd_control_buffer
*bcb
= bcs
->bcs_bout
;
521 int sd
= bcs
->bcs_sd
;
524 bwrite
= write(sd
, &bcb
->bcb_buf
[bcb
->bcb_pos
], bcb
->bcb_left
);
530 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
) {
531 bcs
->bcs_outev
= NULL
;
532 event_add_write(master
, control_write
, bcs
, bcs
->bcs_sd
,
537 zlog_warn("%s: write: %s", __func__
, strerror(errno
));
542 bcb
->bcb_pos
+= bwrite
;
543 bcb
->bcb_left
-= bwrite
;
544 if (bcb
->bcb_left
> 0) {
545 bcs
->bcs_outev
= NULL
;
546 event_add_write(master
, control_write
, bcs
, bcs
->bcs_sd
,
551 control_queue_dequeue(bcs
);
558 static void control_handle_request_add(struct bfd_control_socket
*bcs
,
559 struct bfd_control_msg
*bcm
)
561 const char *json
= (const char *)bcm
->bcm_data
;
563 if (config_request_add(json
) == 0)
564 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
566 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
567 "request add failed");
570 static void control_handle_request_del(struct bfd_control_socket
*bcs
,
571 struct bfd_control_msg
*bcm
)
573 const char *json
= (const char *)bcm
->bcm_data
;
575 if (config_request_del(json
) == 0)
576 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
578 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
579 "request del failed");
582 static struct bfd_session
*_notify_find_peer(struct bfd_peer_cfg
*bpc
)
584 struct peer_label
*pl
;
586 if (bpc
->bpc_has_label
) {
587 pl
= pl_find(bpc
->bpc_label
);
592 return bs_peer_find(bpc
);
595 static void _control_handle_notify(struct hash_bucket
*hb
, void *arg
)
597 struct bfd_control_socket
*bcs
= arg
;
598 struct bfd_session
*bs
= hb
->data
;
600 /* Notify peer configuration. */
601 if (bcs
->bcs_notify
& BCM_NOTIFY_CONFIG
)
602 _control_notify_config(bcs
, BCM_NOTIFY_CONFIG_ADD
, bs
);
604 /* Notify peer status. */
605 if (bcs
->bcs_notify
& BCM_NOTIFY_PEER_STATE
)
606 _control_notify(bcs
, bs
);
609 static void control_handle_notify(struct bfd_control_socket
*bcs
,
610 struct bfd_control_msg
*bcm
)
612 memcpy(&bcs
->bcs_notify
, bcm
->bcm_data
, sizeof(bcs
->bcs_notify
));
614 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
617 * If peer asked for notification configuration, send everything that
618 * was configured until the moment to sync up.
620 if (bcs
->bcs_notify
& (BCM_NOTIFY_CONFIG
| BCM_NOTIFY_PEER_STATE
))
621 bfd_id_iterate(_control_handle_notify
, bcs
);
624 static int notify_add_cb(struct bfd_peer_cfg
*bpc
, void *arg
)
626 struct bfd_control_socket
*bcs
= arg
;
627 struct bfd_session
*bs
= _notify_find_peer(bpc
);
632 control_notifypeer_new(bcs
, bs
);
634 /* Notify peer status. */
635 _control_notify(bcs
, bs
);
640 static int notify_del_cb(struct bfd_peer_cfg
*bpc
, void *arg
)
642 struct bfd_control_socket
*bcs
= arg
;
643 struct bfd_session
*bs
= _notify_find_peer(bpc
);
644 struct bfd_notify_peer
*bnp
;
649 bnp
= control_notifypeer_find(bcs
, bs
);
651 control_notifypeer_free(bcs
, bnp
);
656 static void control_handle_notify_add(struct bfd_control_socket
*bcs
,
657 struct bfd_control_msg
*bcm
)
659 const char *json
= (const char *)bcm
->bcm_data
;
661 if (config_notify_request(bcs
, json
, notify_add_cb
) == 0) {
662 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
666 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
667 "failed to parse notify data");
670 static void control_handle_notify_del(struct bfd_control_socket
*bcs
,
671 struct bfd_control_msg
*bcm
)
673 const char *json
= (const char *)bcm
->bcm_data
;
675 if (config_notify_request(bcs
, json
, notify_del_cb
) == 0) {
676 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
680 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
681 "failed to parse notify data");
686 * Internal functions used by the BFD daemon.
688 static void control_response(struct bfd_control_socket
*bcs
, uint16_t id
,
689 const char *status
, const char *error
)
691 struct bfd_control_msg
*bcm
;
695 /* Generate JSON response. */
696 jsonstr
= config_response(status
, error
);
697 if (jsonstr
== NULL
) {
698 zlog_warn("%s: config_response: failed to get JSON str",
703 /* Allocate data and answer. */
704 jsonstrlen
= strlen(jsonstr
);
705 bcm
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
706 sizeof(struct bfd_control_msg
) + jsonstrlen
);
708 bcm
->bcm_length
= htonl(jsonstrlen
);
709 bcm
->bcm_ver
= BMV_VERSION_1
;
710 bcm
->bcm_type
= BMT_RESPONSE
;
712 memcpy(bcm
->bcm_data
, jsonstr
, jsonstrlen
);
713 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
715 control_queue_enqueue_first(bcs
, bcm
);
718 static void _control_notify(struct bfd_control_socket
*bcs
,
719 struct bfd_session
*bs
)
721 struct bfd_control_msg
*bcm
;
725 /* Generate JSON response. */
726 jsonstr
= config_notify(bs
);
727 if (jsonstr
== NULL
) {
728 zlog_warn("%s: config_notify: failed to get JSON str",
733 /* Allocate data and answer. */
734 jsonstrlen
= strlen(jsonstr
);
735 bcm
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
736 sizeof(struct bfd_control_msg
) + jsonstrlen
);
738 bcm
->bcm_length
= htonl(jsonstrlen
);
739 bcm
->bcm_ver
= BMV_VERSION_1
;
740 bcm
->bcm_type
= BMT_NOTIFY
;
741 bcm
->bcm_id
= htons(BCM_NOTIFY_ID
);
742 memcpy(bcm
->bcm_data
, jsonstr
, jsonstrlen
);
743 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
745 control_queue_enqueue(bcs
, bcm
);
748 int control_notify(struct bfd_session
*bs
, uint8_t notify_state
)
750 struct bfd_control_socket
*bcs
;
751 struct bfd_notify_peer
*bnp
;
753 /* Notify zebra listeners as well. */
754 ptm_bfd_notify(bs
, notify_state
);
757 * PERFORMANCE: reuse the bfd_control_msg allocated data for
758 * all control sockets to avoid wasting memory.
760 TAILQ_FOREACH (bcs
, &bglobal
.bg_bcslist
, bcs_entry
) {
762 * Test for all notifications first, then search for
765 if ((bcs
->bcs_notify
& BCM_NOTIFY_PEER_STATE
) == 0) {
766 bnp
= control_notifypeer_find(bcs
, bs
);
768 * If the notification is not configured here,
775 _control_notify(bcs
, bs
);
781 static void _control_notify_config(struct bfd_control_socket
*bcs
,
782 const char *op
, struct bfd_session
*bs
)
784 struct bfd_control_msg
*bcm
;
788 /* Generate JSON response. */
789 jsonstr
= config_notify_config(op
, bs
);
790 if (jsonstr
== NULL
) {
791 zlog_warn("%s: config_notify_config: failed to get JSON str",
796 /* Allocate data and answer. */
797 jsonstrlen
= strlen(jsonstr
);
798 bcm
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
799 sizeof(struct bfd_control_msg
) + jsonstrlen
);
801 bcm
->bcm_length
= htonl(jsonstrlen
);
802 bcm
->bcm_ver
= BMV_VERSION_1
;
803 bcm
->bcm_type
= BMT_NOTIFY
;
804 bcm
->bcm_id
= htons(BCM_NOTIFY_ID
);
805 memcpy(bcm
->bcm_data
, jsonstr
, jsonstrlen
);
806 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
808 control_queue_enqueue(bcs
, bcm
);
811 int control_notify_config(const char *op
, struct bfd_session
*bs
)
813 struct bfd_control_socket
*bcs
;
814 struct bfd_notify_peer
*bnp
;
816 /* Remove the control sockets notification for this peer. */
817 if (strcmp(op
, BCM_NOTIFY_CONFIG_DELETE
) == 0 && bs
->refcount
> 0) {
818 TAILQ_FOREACH (bcs
, &bglobal
.bg_bcslist
, bcs_entry
) {
819 bnp
= control_notifypeer_find(bcs
, bs
);
821 control_notifypeer_free(bcs
, bnp
);
826 * PERFORMANCE: reuse the bfd_control_msg allocated data for
827 * all control sockets to avoid wasting memory.
829 TAILQ_FOREACH (bcs
, &bglobal
.bg_bcslist
, bcs_entry
) {
831 * Test for all notifications first, then search for
834 if ((bcs
->bcs_notify
& BCM_NOTIFY_CONFIG
) == 0)
837 _control_notify_config(bcs
, op
, bs
);