]>
git.proxmox.com Git - mirror_frr.git/blob - bfdd/control.c
1 /*********************************************************************
2 * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * control.c: implements the BFD daemon control socket. It will be used
19 * to talk with clients daemon/scripts/consumers.
23 * Rafael Zalamena <rzalamena@opensourcerouting.org>
35 static int sock_set_nonblock(int fd
);
36 struct bfd_control_queue
*control_queue_new(struct bfd_control_socket
*bcs
);
37 static void control_queue_free(struct bfd_control_socket
*bcs
,
38 struct bfd_control_queue
*bcq
);
39 static int control_queue_dequeue(struct bfd_control_socket
*bcs
);
40 static int control_queue_enqueue(struct bfd_control_socket
*bcs
,
41 struct bfd_control_msg
*bcm
);
42 static int control_queue_enqueue_first(struct bfd_control_socket
*bcs
,
43 struct bfd_control_msg
*bcm
);
44 struct bfd_notify_peer
*control_notifypeer_new(struct bfd_control_socket
*bcs
,
45 struct bfd_session
*bs
);
46 static void control_notifypeer_free(struct bfd_control_socket
*bcs
,
47 struct bfd_notify_peer
*bnp
);
48 struct bfd_notify_peer
*control_notifypeer_find(struct bfd_control_socket
*bcs
,
49 struct bfd_session
*bs
);
52 struct bfd_control_socket
*control_new(int sd
);
53 static void control_free(struct bfd_control_socket
*bcs
);
54 static void control_reset_buf(struct bfd_control_buffer
*bcb
);
55 static int control_read(struct thread
*t
);
56 static int control_write(struct thread
*t
);
58 static void control_handle_request_add(struct bfd_control_socket
*bcs
,
59 struct bfd_control_msg
*bcm
);
60 static void control_handle_request_del(struct bfd_control_socket
*bcs
,
61 struct bfd_control_msg
*bcm
);
62 static int notify_add_cb(struct bfd_peer_cfg
*bpc
, void *arg
);
63 static int notify_del_cb(struct bfd_peer_cfg
*bpc
, void *arg
);
64 static void control_handle_notify_add(struct bfd_control_socket
*bcs
,
65 struct bfd_control_msg
*bcm
);
66 static void control_handle_notify_del(struct bfd_control_socket
*bcs
,
67 struct bfd_control_msg
*bcm
);
68 static void _control_handle_notify(struct hash_bucket
*hb
, void *arg
);
69 static void control_handle_notify(struct bfd_control_socket
*bcs
,
70 struct bfd_control_msg
*bcm
);
71 static void control_response(struct bfd_control_socket
*bcs
, uint16_t id
,
72 const char *status
, const char *error
);
74 static void _control_notify_config(struct bfd_control_socket
*bcs
,
75 const char *op
, struct bfd_session
*bs
);
76 static void _control_notify(struct bfd_control_socket
*bcs
,
77 struct bfd_session
*bs
);
83 static int sock_set_nonblock(int fd
)
87 flags
= fcntl(fd
, F_GETFL
, 0);
89 log_warning("%s: fcntl F_GETFL: %s", __func__
, strerror(errno
));
94 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
95 log_warning("%s: fcntl F_SETFL: %s", __func__
, strerror(errno
));
102 int control_init(const char *path
)
106 struct sockaddr_un sun_
= {
107 .sun_family
= AF_UNIX
,
108 .sun_path
= BFDD_CONTROL_SOCKET
,
112 strlcpy(sun_
.sun_path
, path
, sizeof(sun_
.sun_path
));
114 /* Remove previously created sockets. */
115 unlink(sun_
.sun_path
);
117 sd
= socket(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
);
119 log_error("%s: socket: %s", __func__
, strerror(errno
));
124 if (bind(sd
, (struct sockaddr
*)&sun_
, sizeof(sun_
)) == -1) {
125 log_error("%s: bind: %s", __func__
, strerror(errno
));
131 if (listen(sd
, SOMAXCONN
) == -1) {
132 log_error("%s: listen: %s", __func__
, strerror(errno
));
137 sock_set_nonblock(sd
);
139 bglobal
.bg_csock
= sd
;
144 void control_shutdown(void)
146 struct bfd_control_socket
*bcs
;
148 if (bglobal
.bg_csockev
) {
149 thread_cancel(bglobal
.bg_csockev
);
150 bglobal
.bg_csockev
= NULL
;
153 socket_close(&bglobal
.bg_csock
);
155 while (!TAILQ_EMPTY(&bglobal
.bg_bcslist
)) {
156 bcs
= TAILQ_FIRST(&bglobal
.bg_bcslist
);
161 int control_accept(struct thread
*t
)
163 int csock
, sd
= THREAD_FD(t
);
165 csock
= accept(sd
, NULL
, 0);
167 log_warning("%s: accept: %s", __func__
, strerror(errno
));
171 if (control_new(csock
) == NULL
)
174 bglobal
.bg_csockev
= NULL
;
175 thread_add_read(master
, control_accept
, NULL
, sd
, &bglobal
.bg_csockev
);
184 struct bfd_control_socket
*control_new(int sd
)
186 struct bfd_control_socket
*bcs
;
188 bcs
= XCALLOC(MTYPE_BFDD_CONTROL
, sizeof(*bcs
));
192 /* Disable notifications by default. */
196 thread_add_read(master
, control_read
, bcs
, sd
, &bcs
->bcs_ev
);
198 TAILQ_INIT(&bcs
->bcs_bcqueue
);
199 TAILQ_INIT(&bcs
->bcs_bnplist
);
200 TAILQ_INSERT_TAIL(&bglobal
.bg_bcslist
, bcs
, bcs_entry
);
205 static void control_free(struct bfd_control_socket
*bcs
)
207 struct bfd_control_queue
*bcq
;
208 struct bfd_notify_peer
*bnp
;
211 thread_cancel(bcs
->bcs_ev
);
215 if (bcs
->bcs_outev
) {
216 thread_cancel(bcs
->bcs_outev
);
217 bcs
->bcs_outev
= NULL
;
222 TAILQ_REMOVE(&bglobal
.bg_bcslist
, bcs
, bcs_entry
);
224 /* Empty output queue. */
225 while (!TAILQ_EMPTY(&bcs
->bcs_bcqueue
)) {
226 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
227 control_queue_free(bcs
, bcq
);
230 /* Empty notification list. */
231 while (!TAILQ_EMPTY(&bcs
->bcs_bnplist
)) {
232 bnp
= TAILQ_FIRST(&bcs
->bcs_bnplist
);
233 control_notifypeer_free(bcs
, bnp
);
236 control_reset_buf(&bcs
->bcs_bin
);
237 XFREE(MTYPE_BFDD_CONTROL
, bcs
);
240 struct bfd_notify_peer
*control_notifypeer_new(struct bfd_control_socket
*bcs
,
241 struct bfd_session
*bs
)
243 struct bfd_notify_peer
*bnp
;
245 bnp
= control_notifypeer_find(bcs
, bs
);
249 bnp
= XCALLOC(MTYPE_BFDD_CONTROL
, sizeof(*bnp
));
251 log_warning("%s: calloc: %s", __func__
, strerror(errno
));
255 TAILQ_INSERT_TAIL(&bcs
->bcs_bnplist
, bnp
, bnp_entry
);
262 static void control_notifypeer_free(struct bfd_control_socket
*bcs
,
263 struct bfd_notify_peer
*bnp
)
265 TAILQ_REMOVE(&bcs
->bcs_bnplist
, bnp
, bnp_entry
);
266 bnp
->bnp_bs
->refcount
--;
267 XFREE(MTYPE_BFDD_CONTROL
, bnp
);
270 struct bfd_notify_peer
*control_notifypeer_find(struct bfd_control_socket
*bcs
,
271 struct bfd_session
*bs
)
273 struct bfd_notify_peer
*bnp
;
275 TAILQ_FOREACH (bnp
, &bcs
->bcs_bnplist
, bnp_entry
) {
276 if (bnp
->bnp_bs
== bs
)
283 struct bfd_control_queue
*control_queue_new(struct bfd_control_socket
*bcs
)
285 struct bfd_control_queue
*bcq
;
287 bcq
= XCALLOC(MTYPE_BFDD_NOTIFICATION
, sizeof(*bcq
));
289 log_warning("%s: calloc: %s", __func__
, strerror(errno
));
293 control_reset_buf(&bcq
->bcq_bcb
);
294 TAILQ_INSERT_TAIL(&bcs
->bcs_bcqueue
, bcq
, bcq_entry
);
299 static void control_queue_free(struct bfd_control_socket
*bcs
,
300 struct bfd_control_queue
*bcq
)
302 control_reset_buf(&bcq
->bcq_bcb
);
303 TAILQ_REMOVE(&bcs
->bcs_bcqueue
, bcq
, bcq_entry
);
304 XFREE(MTYPE_BFDD_NOTIFICATION
, bcq
);
307 static int control_queue_dequeue(struct bfd_control_socket
*bcs
)
309 struct bfd_control_queue
*bcq
;
311 /* List is empty, nothing to do. */
312 if (TAILQ_EMPTY(&bcs
->bcs_bcqueue
))
315 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
316 control_queue_free(bcs
, bcq
);
318 /* Get the next buffer to send. */
319 if (TAILQ_EMPTY(&bcs
->bcs_bcqueue
))
322 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
323 bcs
->bcs_bout
= &bcq
->bcq_bcb
;
325 bcs
->bcs_outev
= NULL
;
326 thread_add_write(master
, control_write
, bcs
, bcs
->bcs_sd
,
332 if (bcs
->bcs_outev
) {
333 thread_cancel(bcs
->bcs_outev
);
334 bcs
->bcs_outev
= NULL
;
336 bcs
->bcs_bout
= NULL
;
340 static int control_queue_enqueue(struct bfd_control_socket
*bcs
,
341 struct bfd_control_msg
*bcm
)
343 struct bfd_control_queue
*bcq
;
344 struct bfd_control_buffer
*bcb
;
346 bcq
= control_queue_new(bcs
);
351 bcb
->bcb_left
= sizeof(struct bfd_control_msg
) + ntohl(bcm
->bcm_length
);
355 /* If this is the first item, then dequeue and start using it. */
356 if (bcs
->bcs_bout
== NULL
) {
359 /* New messages, active write events. */
360 thread_add_write(master
, control_write
, bcs
, bcs
->bcs_sd
,
367 static int control_queue_enqueue_first(struct bfd_control_socket
*bcs
,
368 struct bfd_control_msg
*bcm
)
370 struct bfd_control_queue
*bcq
, *bcqn
;
371 struct bfd_control_buffer
*bcb
;
373 /* Enqueue it somewhere. */
374 if (control_queue_enqueue(bcs
, bcm
) == -1)
378 * The item is either the first or the last. So we must first
379 * check the best case where the item is already the first.
381 bcq
= TAILQ_FIRST(&bcs
->bcs_bcqueue
);
383 if (bcm
== bcb
->bcb_bcm
)
387 * The item was not the first, so it is the last. We'll try to
388 * assign it to the head of the queue, however if there is a
389 * transfer in progress, then we have to make the item as the
392 * Interrupting the transfer of in progress message will cause
393 * the client to lose track of the message position/data.
395 bcqn
= TAILQ_LAST(&bcs
->bcs_bcqueue
, bcqueue
);
396 TAILQ_REMOVE(&bcs
->bcs_bcqueue
, bcqn
, bcq_entry
);
397 if (bcb
->bcb_pos
!= 0) {
399 * First position is already being sent, insert into
402 TAILQ_INSERT_AFTER(&bcs
->bcs_bcqueue
, bcq
, bcqn
, bcq_entry
);
405 * Old message didn't start being sent, we still have
406 * time to put this one in the head of the queue.
408 TAILQ_INSERT_HEAD(&bcs
->bcs_bcqueue
, bcqn
, bcq_entry
);
409 bcb
= &bcqn
->bcq_bcb
;
416 static void control_reset_buf(struct bfd_control_buffer
*bcb
)
418 /* Get ride of old data. */
419 XFREE(MTYPE_BFDD_NOTIFICATION
, bcb
->bcb_buf
);
425 static int control_read(struct thread
*t
)
427 struct bfd_control_socket
*bcs
= THREAD_ARG(t
);
428 struct bfd_control_buffer
*bcb
= &bcs
->bcs_bin
;
429 int sd
= bcs
->bcs_sd
;
430 struct bfd_control_msg bcm
;
435 * Check if we have already downloaded message content, if so then skip
437 * download the rest of it and process.
439 * Otherwise download a new message header and allocate the necessary
442 if (bcb
->bcb_buf
!= NULL
)
445 bread
= read(sd
, &bcm
, sizeof(bcm
));
451 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
452 goto schedule_next_read
;
454 log_warning("%s: read: %s", __func__
, strerror(errno
));
459 /* Validate header fields. */
460 plen
= ntohl(bcm
.bcm_length
);
462 log_debug("%s: client closed due small message length: %d",
463 __func__
, bcm
.bcm_length
);
468 if (bcm
.bcm_ver
!= BMV_VERSION_1
) {
469 log_debug("%s: client closed due bad version: %d", __func__
,
475 /* Prepare the buffer to load the message. */
476 bcs
->bcs_version
= bcm
.bcm_ver
;
477 bcs
->bcs_type
= bcm
.bcm_type
;
479 bcb
->bcb_pos
= sizeof(bcm
);
480 bcb
->bcb_left
= plen
;
481 bcb
->bcb_buf
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
482 sizeof(bcm
) + bcb
->bcb_left
+ 1);
483 if (bcb
->bcb_buf
== NULL
) {
484 log_warning("%s: not enough memory for message size: %u",
485 __func__
, bcb
->bcb_left
);
490 memcpy(bcb
->bcb_buf
, &bcm
, sizeof(bcm
));
492 /* Terminate data string with NULL for later processing. */
493 bcb
->bcb_buf
[sizeof(bcm
) + bcb
->bcb_left
] = 0;
496 /* Download the remaining data of the message and process it. */
497 bread
= read(sd
, &bcb
->bcb_buf
[bcb
->bcb_pos
], bcb
->bcb_left
);
503 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
504 goto schedule_next_read
;
506 log_warning("%s: read: %s", __func__
, strerror(errno
));
511 bcb
->bcb_pos
+= bread
;
512 bcb
->bcb_left
-= bread
;
513 /* We need more data, return to wait more. */
514 if (bcb
->bcb_left
> 0)
515 goto schedule_next_read
;
517 switch (bcb
->bcb_bcm
->bcm_type
) {
518 case BMT_REQUEST_ADD
:
519 control_handle_request_add(bcs
, bcb
->bcb_bcm
);
521 case BMT_REQUEST_DEL
:
522 control_handle_request_del(bcs
, bcb
->bcb_bcm
);
525 control_handle_notify(bcs
, bcb
->bcb_bcm
);
528 control_handle_notify_add(bcs
, bcb
->bcb_bcm
);
531 control_handle_notify_del(bcs
, bcb
->bcb_bcm
);
535 log_debug("%s: unhandled message type: %d", __func__
,
536 bcb
->bcb_bcm
->bcm_type
);
537 control_response(bcs
, bcb
->bcb_bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
538 "invalid message type");
542 bcs
->bcs_version
= 0;
544 control_reset_buf(bcb
);
548 thread_add_read(master
, control_read
, bcs
, sd
, &bcs
->bcs_ev
);
553 static int control_write(struct thread
*t
)
555 struct bfd_control_socket
*bcs
= THREAD_ARG(t
);
556 struct bfd_control_buffer
*bcb
= bcs
->bcs_bout
;
557 int sd
= bcs
->bcs_sd
;
560 bwrite
= write(sd
, &bcb
->bcb_buf
[bcb
->bcb_pos
], bcb
->bcb_left
);
566 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
) {
567 bcs
->bcs_outev
= NULL
;
568 thread_add_write(master
, control_write
, bcs
,
569 bcs
->bcs_sd
, &bcs
->bcs_outev
);
573 log_warning("%s: write: %s", __func__
, strerror(errno
));
578 bcb
->bcb_pos
+= bwrite
;
579 bcb
->bcb_left
-= bwrite
;
580 if (bcb
->bcb_left
> 0) {
581 bcs
->bcs_outev
= NULL
;
582 thread_add_write(master
, control_write
, bcs
, bcs
->bcs_sd
,
587 control_queue_dequeue(bcs
);
596 static void control_handle_request_add(struct bfd_control_socket
*bcs
,
597 struct bfd_control_msg
*bcm
)
599 const char *json
= (const char *)bcm
->bcm_data
;
601 if (config_request_add(json
) == 0)
602 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
604 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
605 "request add failed");
608 static void control_handle_request_del(struct bfd_control_socket
*bcs
,
609 struct bfd_control_msg
*bcm
)
611 const char *json
= (const char *)bcm
->bcm_data
;
613 if (config_request_del(json
) == 0)
614 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
616 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
617 "request del failed");
620 static struct bfd_session
*_notify_find_peer(struct bfd_peer_cfg
*bpc
)
622 struct peer_label
*pl
;
624 if (bpc
->bpc_has_label
) {
625 pl
= pl_find(bpc
->bpc_label
);
630 return bs_peer_find(bpc
);
633 static void _control_handle_notify(struct hash_bucket
*hb
, void *arg
)
635 struct bfd_control_socket
*bcs
= arg
;
636 struct bfd_session
*bs
= hb
->data
;
638 /* Notify peer configuration. */
639 if (bcs
->bcs_notify
& BCM_NOTIFY_CONFIG
)
640 _control_notify_config(bcs
, BCM_NOTIFY_CONFIG_ADD
, bs
);
642 /* Notify peer status. */
643 if (bcs
->bcs_notify
& BCM_NOTIFY_PEER_STATE
)
644 _control_notify(bcs
, bs
);
647 static void control_handle_notify(struct bfd_control_socket
*bcs
,
648 struct bfd_control_msg
*bcm
)
650 memcpy(&bcs
->bcs_notify
, bcm
->bcm_data
, sizeof(bcs
->bcs_notify
));
652 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
655 * If peer asked for notification configuration, send everything that
656 * was configured until the moment to sync up.
658 if (bcs
->bcs_notify
& (BCM_NOTIFY_CONFIG
| BCM_NOTIFY_PEER_STATE
))
659 bfd_id_iterate(_control_handle_notify
, bcs
);
662 static int notify_add_cb(struct bfd_peer_cfg
*bpc
, void *arg
)
664 struct bfd_control_socket
*bcs
= arg
;
665 struct bfd_session
*bs
= _notify_find_peer(bpc
);
670 if (control_notifypeer_new(bcs
, bs
) == NULL
)
673 /* Notify peer status. */
674 _control_notify(bcs
, bs
);
679 static int notify_del_cb(struct bfd_peer_cfg
*bpc
, void *arg
)
681 struct bfd_control_socket
*bcs
= arg
;
682 struct bfd_session
*bs
= _notify_find_peer(bpc
);
683 struct bfd_notify_peer
*bnp
;
688 bnp
= control_notifypeer_find(bcs
, bs
);
690 control_notifypeer_free(bcs
, bnp
);
695 static void control_handle_notify_add(struct bfd_control_socket
*bcs
,
696 struct bfd_control_msg
*bcm
)
698 const char *json
= (const char *)bcm
->bcm_data
;
700 if (config_notify_request(bcs
, json
, notify_add_cb
) == 0) {
701 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
705 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
706 "failed to parse notify data");
709 static void control_handle_notify_del(struct bfd_control_socket
*bcs
,
710 struct bfd_control_msg
*bcm
)
712 const char *json
= (const char *)bcm
->bcm_data
;
714 if (config_notify_request(bcs
, json
, notify_del_cb
) == 0) {
715 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_OK
, NULL
);
719 control_response(bcs
, bcm
->bcm_id
, BCM_RESPONSE_ERROR
,
720 "failed to parse notify data");
725 * Internal functions used by the BFD daemon.
727 static void control_response(struct bfd_control_socket
*bcs
, uint16_t id
,
728 const char *status
, const char *error
)
730 struct bfd_control_msg
*bcm
;
734 /* Generate JSON response. */
735 jsonstr
= config_response(status
, error
);
736 if (jsonstr
== NULL
) {
737 log_warning("%s: config_response: failed to get JSON str",
742 /* Allocate data and answer. */
743 jsonstrlen
= strlen(jsonstr
);
744 bcm
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
745 sizeof(struct bfd_control_msg
) + jsonstrlen
);
747 log_warning("%s: malloc: %s", __func__
, strerror(errno
));
748 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
752 bcm
->bcm_length
= htonl(jsonstrlen
);
753 bcm
->bcm_ver
= BMV_VERSION_1
;
754 bcm
->bcm_type
= BMT_RESPONSE
;
756 memcpy(bcm
->bcm_data
, jsonstr
, jsonstrlen
);
757 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
759 control_queue_enqueue_first(bcs
, bcm
);
762 static void _control_notify(struct bfd_control_socket
*bcs
,
763 struct bfd_session
*bs
)
765 struct bfd_control_msg
*bcm
;
769 /* Generate JSON response. */
770 jsonstr
= config_notify(bs
);
771 if (jsonstr
== NULL
) {
772 log_warning("%s: config_notify: failed to get JSON str",
777 /* Allocate data and answer. */
778 jsonstrlen
= strlen(jsonstr
);
779 bcm
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
780 sizeof(struct bfd_control_msg
) + jsonstrlen
);
782 log_warning("%s: malloc: %s", __func__
, strerror(errno
));
783 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
787 bcm
->bcm_length
= htonl(jsonstrlen
);
788 bcm
->bcm_ver
= BMV_VERSION_1
;
789 bcm
->bcm_type
= BMT_NOTIFY
;
790 bcm
->bcm_id
= htons(BCM_NOTIFY_ID
);
791 memcpy(bcm
->bcm_data
, jsonstr
, jsonstrlen
);
792 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
794 control_queue_enqueue(bcs
, bcm
);
797 int control_notify(struct bfd_session
*bs
)
799 struct bfd_control_socket
*bcs
;
800 struct bfd_notify_peer
*bnp
;
802 /* Notify zebra listeners as well. */
806 * PERFORMANCE: reuse the bfd_control_msg allocated data for
807 * all control sockets to avoid wasting memory.
809 TAILQ_FOREACH (bcs
, &bglobal
.bg_bcslist
, bcs_entry
) {
811 * Test for all notifications first, then search for
814 if ((bcs
->bcs_notify
& BCM_NOTIFY_PEER_STATE
) == 0) {
815 bnp
= control_notifypeer_find(bcs
, bs
);
817 * If the notification is not configured here,
824 _control_notify(bcs
, bs
);
830 static void _control_notify_config(struct bfd_control_socket
*bcs
,
831 const char *op
, struct bfd_session
*bs
)
833 struct bfd_control_msg
*bcm
;
837 /* Generate JSON response. */
838 jsonstr
= config_notify_config(op
, bs
);
839 if (jsonstr
== NULL
) {
840 log_warning("%s: config_notify_config: failed to get JSON str",
845 /* Allocate data and answer. */
846 jsonstrlen
= strlen(jsonstr
);
847 bcm
= XMALLOC(MTYPE_BFDD_NOTIFICATION
,
848 sizeof(struct bfd_control_msg
) + jsonstrlen
);
850 log_warning("%s: malloc: %s", __func__
, strerror(errno
));
851 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
855 bcm
->bcm_length
= htonl(jsonstrlen
);
856 bcm
->bcm_ver
= BMV_VERSION_1
;
857 bcm
->bcm_type
= BMT_NOTIFY
;
858 bcm
->bcm_id
= htons(BCM_NOTIFY_ID
);
859 memcpy(bcm
->bcm_data
, jsonstr
, jsonstrlen
);
860 XFREE(MTYPE_BFDD_NOTIFICATION
, jsonstr
);
862 control_queue_enqueue(bcs
, bcm
);
865 int control_notify_config(const char *op
, struct bfd_session
*bs
)
867 struct bfd_control_socket
*bcs
;
868 struct bfd_notify_peer
*bnp
;
870 /* Remove the control sockets notification for this peer. */
871 if (strcmp(op
, BCM_NOTIFY_CONFIG_DELETE
) == 0 && bs
->refcount
> 0) {
872 TAILQ_FOREACH (bcs
, &bglobal
.bg_bcslist
, bcs_entry
) {
873 bnp
= control_notifypeer_find(bcs
, bs
);
875 control_notifypeer_free(bcs
, bnp
);
880 * PERFORMANCE: reuse the bfd_control_msg allocated data for
881 * all control sockets to avoid wasting memory.
883 TAILQ_FOREACH (bcs
, &bglobal
.bg_bcslist
, bcs_entry
) {
885 * Test for all notifications first, then search for
888 if ((bcs
->bcs_notify
& BCM_NOTIFY_CONFIG
) == 0)
891 _control_notify_config(bcs
, op
, bs
);