summaryrefslogtreecommitdiffstats
path: root/bfdd/control.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel@debian.org>2024-11-17 07:11:26 +0100
committerDaniel Baumann <daniel@debian.org>2024-11-17 07:11:26 +0100
commitd5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6 (patch)
tree705ea89e798053f9c227b85512bc9f5b437b0093 /bfdd/control.c
parentReleasing debian version 10.1.1-3. (diff)
downloadfrr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.tar.xz
frr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.zip
Merging upstream version 10.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'bfdd/control.c')
-rw-r--r--bfdd/control.c844
1 files changed, 0 insertions, 844 deletions
diff --git a/bfdd/control.c b/bfdd/control.c
deleted file mode 100644
index 98fd813e..00000000
--- a/bfdd/control.c
+++ /dev/null
@@ -1,844 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*********************************************************************
- * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * control.c: implements the BFD daemon control socket. It will be used
- * to talk with clients daemon/scripts/consumers.
- *
- * Authors
- * -------
- * Rafael Zalamena <rzalamena@opensourcerouting.org>
- */
-
-#include <zebra.h>
-
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include <sys/un.h>
-
-#include "bfd.h"
-
-/*
- * Prototypes
- */
-static int sock_set_nonblock(int fd);
-struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs);
-static void control_queue_free(struct bfd_control_socket *bcs,
- struct bfd_control_queue *bcq);
-static int control_queue_dequeue(struct bfd_control_socket *bcs);
-static int control_queue_enqueue(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm);
-static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm);
-struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
- struct bfd_session *bs);
-static void control_notifypeer_free(struct bfd_control_socket *bcs,
- struct bfd_notify_peer *bnp);
-struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
- struct bfd_session *bs);
-
-
-struct bfd_control_socket *control_new(int sd);
-static void control_free(struct bfd_control_socket *bcs);
-static void control_reset_buf(struct bfd_control_buffer *bcb);
-static void control_read(struct event *t);
-static void control_write(struct event *t);
-
-static void control_handle_request_add(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm);
-static void control_handle_request_del(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm);
-static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg);
-static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg);
-static void control_handle_notify_add(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm);
-static void control_handle_notify_del(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm);
-static void _control_handle_notify(struct hash_bucket *hb, void *arg);
-static void control_handle_notify(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm);
-static void control_response(struct bfd_control_socket *bcs, uint16_t id,
- const char *status, const char *error);
-
-static void _control_notify_config(struct bfd_control_socket *bcs,
- const char *op, struct bfd_session *bs);
-static void _control_notify(struct bfd_control_socket *bcs,
- struct bfd_session *bs);
-
-
-/*
- * Functions
- */
-static int sock_set_nonblock(int fd)
-{
- int flags;
-
- flags = fcntl(fd, F_GETFL, 0);
- if (flags == -1) {
- zlog_warn("%s: fcntl F_GETFL: %s", __func__, strerror(errno));
- return -1;
- }
-
- flags |= O_NONBLOCK;
- if (fcntl(fd, F_SETFL, flags) == -1) {
- zlog_warn("%s: fcntl F_SETFL: %s", __func__, strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-int control_init(const char *path)
-{
- int sd;
- mode_t umval;
- struct sockaddr_un sun_ = {
- .sun_family = AF_UNIX,
- };
-
- assert(path);
-
- strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path));
-
- /* Remove previously created sockets. */
- unlink(sun_.sun_path);
-
- sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
- if (sd == -1) {
- zlog_err("%s: socket: %s", __func__, strerror(errno));
- return -1;
- }
-
- umval = umask(0);
- if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) {
- zlog_err("%s: bind: %s", __func__, strerror(errno));
- close(sd);
- return -1;
- }
- umask(umval);
-
- if (listen(sd, SOMAXCONN) == -1) {
- zlog_err("%s: listen: %s", __func__, strerror(errno));
- close(sd);
- return -1;
- }
-
- sock_set_nonblock(sd);
-
- bglobal.bg_csock = sd;
-
- return 0;
-}
-
-void control_shutdown(void)
-{
- struct bfd_control_socket *bcs;
-
- event_cancel(&bglobal.bg_csockev);
-
- socket_close(&bglobal.bg_csock);
-
- while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) {
- bcs = TAILQ_FIRST(&bglobal.bg_bcslist);
- control_free(bcs);
- }
-}
-
-void control_accept(struct event *t)
-{
- int csock, sd = EVENT_FD(t);
-
- csock = accept(sd, NULL, 0);
- if (csock == -1) {
- zlog_warn("%s: accept: %s", __func__, strerror(errno));
- return;
- }
-
- control_new(csock);
-
- event_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev);
-}
-
-
-/*
- * Client handling
- */
-struct bfd_control_socket *control_new(int sd)
-{
- struct bfd_control_socket *bcs;
-
- bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs));
-
- /* Disable notifications by default. */
- bcs->bcs_notify = 0;
-
- bcs->bcs_sd = sd;
- event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
-
- TAILQ_INIT(&bcs->bcs_bcqueue);
- TAILQ_INIT(&bcs->bcs_bnplist);
- TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry);
-
- return bcs;
-}
-
-static void control_free(struct bfd_control_socket *bcs)
-{
- struct bfd_control_queue *bcq;
- struct bfd_notify_peer *bnp;
-
- event_cancel(&(bcs->bcs_ev));
- event_cancel(&(bcs->bcs_outev));
-
- close(bcs->bcs_sd);
-
- TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry);
-
- /* Empty output queue. */
- while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) {
- bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
- control_queue_free(bcs, bcq);
- }
-
- /* Empty notification list. */
- while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) {
- bnp = TAILQ_FIRST(&bcs->bcs_bnplist);
- control_notifypeer_free(bcs, bnp);
- }
-
- control_reset_buf(&bcs->bcs_bin);
- XFREE(MTYPE_BFDD_CONTROL, bcs);
-}
-
-struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
- struct bfd_session *bs)
-{
- struct bfd_notify_peer *bnp;
-
- bnp = control_notifypeer_find(bcs, bs);
- if (bnp)
- return bnp;
-
- bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp));
-
- TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry);
- bnp->bnp_bs = bs;
- bs->refcount++;
-
- return bnp;
-}
-
-static void control_notifypeer_free(struct bfd_control_socket *bcs,
- struct bfd_notify_peer *bnp)
-{
- TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry);
- bnp->bnp_bs->refcount--;
- XFREE(MTYPE_BFDD_CONTROL, bnp);
-}
-
-struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
- struct bfd_session *bs)
-{
- struct bfd_notify_peer *bnp;
-
- TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) {
- if (bnp->bnp_bs == bs)
- return bnp;
- }
-
- return NULL;
-}
-
-struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs)
-{
- struct bfd_control_queue *bcq;
-
- bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq));
-
- control_reset_buf(&bcq->bcq_bcb);
- TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry);
-
- return bcq;
-}
-
-static void control_queue_free(struct bfd_control_socket *bcs,
- struct bfd_control_queue *bcq)
-{
- control_reset_buf(&bcq->bcq_bcb);
- TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry);
- XFREE(MTYPE_BFDD_NOTIFICATION, bcq);
-}
-
-static int control_queue_dequeue(struct bfd_control_socket *bcs)
-{
- struct bfd_control_queue *bcq;
-
- /* List is empty, nothing to do. */
- if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
- goto empty_list;
-
- bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
- control_queue_free(bcs, bcq);
-
- /* Get the next buffer to send. */
- if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
- goto empty_list;
-
- bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
- bcs->bcs_bout = &bcq->bcq_bcb;
-
- bcs->bcs_outev = NULL;
- event_add_write(master, control_write, bcs, bcs->bcs_sd,
- &bcs->bcs_outev);
-
- return 1;
-
-empty_list:
- event_cancel(&(bcs->bcs_outev));
- bcs->bcs_bout = NULL;
- return 0;
-}
-
-static int control_queue_enqueue(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm)
-{
- struct bfd_control_queue *bcq;
- struct bfd_control_buffer *bcb;
-
- bcq = control_queue_new(bcs);
-
- bcb = &bcq->bcq_bcb;
- bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length);
- bcb->bcb_pos = 0;
- bcb->bcb_bcm = bcm;
-
- /* If this is the first item, then dequeue and start using it. */
- if (bcs->bcs_bout == NULL) {
- bcs->bcs_bout = bcb;
-
- /* New messages, active write events. */
- event_add_write(master, control_write, bcs, bcs->bcs_sd,
- &bcs->bcs_outev);
- }
-
- return 0;
-}
-
-static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm)
-{
- struct bfd_control_queue *bcq, *bcqn;
- struct bfd_control_buffer *bcb;
-
- /* Enqueue it somewhere. */
- if (control_queue_enqueue(bcs, bcm) == -1)
- return -1;
-
- /*
- * The item is either the first or the last. So we must first
- * check the best case where the item is already the first.
- */
- bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
- bcb = &bcq->bcq_bcb;
- if (bcm == bcb->bcb_bcm)
- return 0;
-
- /*
- * The item was not the first, so it is the last. We'll try to
- * assign it to the head of the queue, however if there is a
- * transfer in progress, then we have to make the item as the
- * next one.
- *
- * Interrupting the transfer of in progress message will cause
- * the client to lose track of the message position/data.
- */
- bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue);
- TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry);
- if (bcb->bcb_pos != 0) {
- /*
- * First position is already being sent, insert into
- * second position.
- */
- TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry);
- } else {
- /*
- * Old message didn't start being sent, we still have
- * time to put this one in the head of the queue.
- */
- TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry);
- bcb = &bcqn->bcq_bcb;
- bcs->bcs_bout = bcb;
- }
-
- return 0;
-}
-
-static void control_reset_buf(struct bfd_control_buffer *bcb)
-{
- /* Get ride of old data. */
- XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf);
- bcb->bcb_pos = 0;
- bcb->bcb_left = 0;
-}
-
-static void control_read(struct event *t)
-{
- struct bfd_control_socket *bcs = EVENT_ARG(t);
- struct bfd_control_buffer *bcb = &bcs->bcs_bin;
- int sd = bcs->bcs_sd;
- struct bfd_control_msg bcm;
- ssize_t bread;
- size_t plen;
-
- /*
- * Check if we have already downloaded message content, if so then skip
- * to
- * download the rest of it and process.
- *
- * Otherwise download a new message header and allocate the necessary
- * memory.
- */
- if (bcb->bcb_buf != NULL)
- goto skip_header;
-
- bread = read(sd, &bcm, sizeof(bcm));
- if (bread == 0) {
- control_free(bcs);
- return;
- }
- if (bread < 0) {
- if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
- goto schedule_next_read;
-
- zlog_warn("%s: read: %s", __func__, strerror(errno));
- control_free(bcs);
- return;
- }
-
- /* Validate header fields. */
- plen = ntohl(bcm.bcm_length);
- if (plen < 2) {
- zlog_debug("%s: client closed due small message length: %d",
- __func__, bcm.bcm_length);
- control_free(bcs);
- return;
- }
-
-#define FRR_BFD_MAXLEN 10 * 1024
-
- if (plen > FRR_BFD_MAXLEN) {
- zlog_debug("%s: client closed, invalid message length: %d",
- __func__, bcm.bcm_length);
- control_free(bcs);
- return;
- }
-
- if (bcm.bcm_ver != BMV_VERSION_1) {
- zlog_debug("%s: client closed due bad version: %d", __func__,
- bcm.bcm_ver);
- control_free(bcs);
- return;
- }
-
- /* Prepare the buffer to load the message. */
- bcs->bcs_version = bcm.bcm_ver;
- bcs->bcs_type = bcm.bcm_type;
-
- bcb->bcb_pos = sizeof(bcm);
- bcb->bcb_left = plen;
- bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION,
- sizeof(bcm) + bcb->bcb_left + 1);
- if (bcb->bcb_buf == NULL) {
- zlog_warn("%s: not enough memory for message size: %zu",
- __func__, bcb->bcb_left);
- control_free(bcs);
- return;
- }
-
- memcpy(bcb->bcb_buf, &bcm, sizeof(bcm));
-
- /* Terminate data string with NULL for later processing. */
- bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0;
-
-skip_header:
- /* Download the remaining data of the message and process it. */
- bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
- if (bread == 0) {
- control_free(bcs);
- return;
- }
- if (bread < 0) {
- if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
- goto schedule_next_read;
-
- zlog_warn("%s: read: %s", __func__, strerror(errno));
- control_free(bcs);
- return;
- }
-
- bcb->bcb_pos += bread;
- bcb->bcb_left -= bread;
- /* We need more data, return to wait more. */
- if (bcb->bcb_left > 0)
- goto schedule_next_read;
-
- switch (bcb->bcb_bcm->bcm_type) {
- case BMT_REQUEST_ADD:
- control_handle_request_add(bcs, bcb->bcb_bcm);
- break;
- case BMT_REQUEST_DEL:
- control_handle_request_del(bcs, bcb->bcb_bcm);
- break;
- case BMT_NOTIFY:
- control_handle_notify(bcs, bcb->bcb_bcm);
- break;
- case BMT_NOTIFY_ADD:
- control_handle_notify_add(bcs, bcb->bcb_bcm);
- break;
- case BMT_NOTIFY_DEL:
- control_handle_notify_del(bcs, bcb->bcb_bcm);
- break;
-
- default:
- zlog_debug("%s: unhandled message type: %d", __func__,
- bcb->bcb_bcm->bcm_type);
- control_response(bcs, bcb->bcb_bcm->bcm_id, BCM_RESPONSE_ERROR,
- "invalid message type");
- break;
- }
-
- bcs->bcs_version = 0;
- bcs->bcs_type = 0;
- control_reset_buf(bcb);
-
-schedule_next_read:
- bcs->bcs_ev = NULL;
- event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
-}
-
-static void control_write(struct event *t)
-{
- struct bfd_control_socket *bcs = EVENT_ARG(t);
- struct bfd_control_buffer *bcb = bcs->bcs_bout;
- int sd = bcs->bcs_sd;
- ssize_t bwrite;
-
- bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
- if (bwrite == 0) {
- control_free(bcs);
- return;
- }
- if (bwrite < 0) {
- if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
- bcs->bcs_outev = NULL;
- event_add_write(master, control_write, bcs, bcs->bcs_sd,
- &bcs->bcs_outev);
- return;
- }
-
- zlog_warn("%s: write: %s", __func__, strerror(errno));
- control_free(bcs);
- return;
- }
-
- bcb->bcb_pos += bwrite;
- bcb->bcb_left -= bwrite;
- if (bcb->bcb_left > 0) {
- bcs->bcs_outev = NULL;
- event_add_write(master, control_write, bcs, bcs->bcs_sd,
- &bcs->bcs_outev);
- return;
- }
-
- control_queue_dequeue(bcs);
-}
-
-
-/*
- * Message processing
- */
-static void control_handle_request_add(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm)
-{
- const char *json = (const char *)bcm->bcm_data;
-
- if (config_request_add(json) == 0)
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
- else
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
- "request add failed");
-}
-
-static void control_handle_request_del(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm)
-{
- const char *json = (const char *)bcm->bcm_data;
-
- if (config_request_del(json) == 0)
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
- else
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
- "request del failed");
-}
-
-static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc)
-{
- struct peer_label *pl;
-
- if (bpc->bpc_has_label) {
- pl = pl_find(bpc->bpc_label);
- if (pl)
- return pl->pl_bs;
- }
-
- return bs_peer_find(bpc);
-}
-
-static void _control_handle_notify(struct hash_bucket *hb, void *arg)
-{
- struct bfd_control_socket *bcs = arg;
- struct bfd_session *bs = hb->data;
-
- /* Notify peer configuration. */
- if (bcs->bcs_notify & BCM_NOTIFY_CONFIG)
- _control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs);
-
- /* Notify peer status. */
- if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE)
- _control_notify(bcs, bs);
-}
-
-static void control_handle_notify(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm)
-{
- memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify));
-
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
-
- /*
- * If peer asked for notification configuration, send everything that
- * was configured until the moment to sync up.
- */
- if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE))
- bfd_id_iterate(_control_handle_notify, bcs);
-}
-
-static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg)
-{
- struct bfd_control_socket *bcs = arg;
- struct bfd_session *bs = _notify_find_peer(bpc);
-
- if (bs == NULL)
- return -1;
-
- control_notifypeer_new(bcs, bs);
-
- /* Notify peer status. */
- _control_notify(bcs, bs);
-
- return 0;
-}
-
-static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg)
-{
- struct bfd_control_socket *bcs = arg;
- struct bfd_session *bs = _notify_find_peer(bpc);
- struct bfd_notify_peer *bnp;
-
- if (bs == NULL)
- return -1;
-
- bnp = control_notifypeer_find(bcs, bs);
- if (bnp)
- control_notifypeer_free(bcs, bnp);
-
- return 0;
-}
-
-static void control_handle_notify_add(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm)
-{
- const char *json = (const char *)bcm->bcm_data;
-
- if (config_notify_request(bcs, json, notify_add_cb) == 0) {
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
- return;
- }
-
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
- "failed to parse notify data");
-}
-
-static void control_handle_notify_del(struct bfd_control_socket *bcs,
- struct bfd_control_msg *bcm)
-{
- const char *json = (const char *)bcm->bcm_data;
-
- if (config_notify_request(bcs, json, notify_del_cb) == 0) {
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
- return;
- }
-
- control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
- "failed to parse notify data");
-}
-
-
-/*
- * Internal functions used by the BFD daemon.
- */
-static void control_response(struct bfd_control_socket *bcs, uint16_t id,
- const char *status, const char *error)
-{
- struct bfd_control_msg *bcm;
- char *jsonstr;
- size_t jsonstrlen;
-
- /* Generate JSON response. */
- jsonstr = config_response(status, error);
- if (jsonstr == NULL) {
- zlog_warn("%s: config_response: failed to get JSON str",
- __func__);
- return;
- }
-
- /* Allocate data and answer. */
- jsonstrlen = strlen(jsonstr);
- bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
- sizeof(struct bfd_control_msg) + jsonstrlen);
-
- bcm->bcm_length = htonl(jsonstrlen);
- bcm->bcm_ver = BMV_VERSION_1;
- bcm->bcm_type = BMT_RESPONSE;
- bcm->bcm_id = id;
- memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
- XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
-
- control_queue_enqueue_first(bcs, bcm);
-}
-
-static void _control_notify(struct bfd_control_socket *bcs,
- struct bfd_session *bs)
-{
- struct bfd_control_msg *bcm;
- char *jsonstr;
- size_t jsonstrlen;
-
- /* Generate JSON response. */
- jsonstr = config_notify(bs);
- if (jsonstr == NULL) {
- zlog_warn("%s: config_notify: failed to get JSON str",
- __func__);
- return;
- }
-
- /* Allocate data and answer. */
- jsonstrlen = strlen(jsonstr);
- bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
- sizeof(struct bfd_control_msg) + jsonstrlen);
-
- bcm->bcm_length = htonl(jsonstrlen);
- bcm->bcm_ver = BMV_VERSION_1;
- bcm->bcm_type = BMT_NOTIFY;
- bcm->bcm_id = htons(BCM_NOTIFY_ID);
- memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
- XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
-
- control_queue_enqueue(bcs, bcm);
-}
-
-int control_notify(struct bfd_session *bs, uint8_t notify_state)
-{
- struct bfd_control_socket *bcs;
- struct bfd_notify_peer *bnp;
-
- /* Notify zebra listeners as well. */
- ptm_bfd_notify(bs, notify_state);
-
- /*
- * PERFORMANCE: reuse the bfd_control_msg allocated data for
- * all control sockets to avoid wasting memory.
- */
- TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
- /*
- * Test for all notifications first, then search for
- * specific peers.
- */
- if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) {
- bnp = control_notifypeer_find(bcs, bs);
- /*
- * If the notification is not configured here,
- * don't send it.
- */
- if (bnp == NULL)
- continue;
- }
-
- _control_notify(bcs, bs);
- }
-
- return 0;
-}
-
-static void _control_notify_config(struct bfd_control_socket *bcs,
- const char *op, struct bfd_session *bs)
-{
- struct bfd_control_msg *bcm;
- char *jsonstr;
- size_t jsonstrlen;
-
- /* Generate JSON response. */
- jsonstr = config_notify_config(op, bs);
- if (jsonstr == NULL) {
- zlog_warn("%s: config_notify_config: failed to get JSON str",
- __func__);
- return;
- }
-
- /* Allocate data and answer. */
- jsonstrlen = strlen(jsonstr);
- bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
- sizeof(struct bfd_control_msg) + jsonstrlen);
-
- bcm->bcm_length = htonl(jsonstrlen);
- bcm->bcm_ver = BMV_VERSION_1;
- bcm->bcm_type = BMT_NOTIFY;
- bcm->bcm_id = htons(BCM_NOTIFY_ID);
- memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
- XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
-
- control_queue_enqueue(bcs, bcm);
-}
-
-int control_notify_config(const char *op, struct bfd_session *bs)
-{
- struct bfd_control_socket *bcs;
- struct bfd_notify_peer *bnp;
-
- /* Remove the control sockets notification for this peer. */
- if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) {
- TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
- bnp = control_notifypeer_find(bcs, bs);
- if (bnp)
- control_notifypeer_free(bcs, bnp);
- }
- }
-
- /*
- * PERFORMANCE: reuse the bfd_control_msg allocated data for
- * all control sockets to avoid wasting memory.
- */
- TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
- /*
- * Test for all notifications first, then search for
- * specific peers.
- */
- if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0)
- continue;
-
- _control_notify_config(bcs, op, bs);
- }
-
- return 0;
-}