]> git.proxmox.com Git - mirror_frr.git/blame - lib/mgmt_be_client.c
mgmtd: Fixing code coverity issues in mgmtd
[mirror_frr.git] / lib / mgmt_be_client.c
CommitLineData
7d65b7b7
CH
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * MGMTD Backend Client Library api interfaces
4 * Copyright (C) 2021 Vmware, Inc.
5 * Pushpasis Sarkar <spushpasis@vmware.com>
6 */
7
8#include <zebra.h>
9#include "libfrr.h"
10#include "mgmtd/mgmt.h"
11#include "mgmt_be_client.h"
f82370b4 12#include "mgmt_msg.h"
7d65b7b7
CH
13#include "mgmt_pb.h"
14#include "network.h"
15#include "stream.h"
16#include "sockopt.h"
17
18#ifdef REDIRECT_DEBUG_TO_STDERR
19#define MGMTD_BE_CLIENT_DBG(fmt, ...) \
20 fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
21#define MGMTD_BE_CLIENT_ERR(fmt, ...) \
22 fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
23#else /* REDIRECT_DEBUG_TO_STDERR */
24#define MGMTD_BE_CLIENT_DBG(fmt, ...) \
25 do { \
26 if (mgmt_debug_be_client) \
27 zlog_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
28 } while (0)
29#define MGMTD_BE_CLIENT_ERR(fmt, ...) \
30 zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
31#endif /* REDIRECT_DEBUG_TO_STDERR */
32
33DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_BATCH,
34 "MGMTD backend transaction batch data");
35DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_TXN, "MGMTD backend transaction data");
36
37enum mgmt_be_txn_event {
38 MGMTD_BE_TXN_PROC_SETCFG = 1,
39 MGMTD_BE_TXN_PROC_GETCFG,
40 MGMTD_BE_TXN_PROC_GETDATA
41};
42
43struct mgmt_be_set_cfg_req {
44 struct nb_cfg_change cfg_changes[MGMTD_MAX_CFG_CHANGES_IN_BATCH];
45 uint16_t num_cfg_changes;
46};
47
48struct mgmt_be_get_data_req {
49 char *xpaths[MGMTD_MAX_NUM_DATA_REQ_IN_BATCH];
50 uint16_t num_xpaths;
51};
52
53struct mgmt_be_txn_req {
54 enum mgmt_be_txn_event event;
55 union {
56 struct mgmt_be_set_cfg_req set_cfg;
57 struct mgmt_be_get_data_req get_data;
58 } req;
59};
60
61PREDECL_LIST(mgmt_be_batches);
62struct mgmt_be_batch_ctx {
63 /* Batch-Id as assigned by MGMTD */
64 uint64_t batch_id;
65
66 struct mgmt_be_txn_req txn_req;
67
68 uint32_t flags;
69
70 struct mgmt_be_batches_item list_linkage;
71};
72#define MGMTD_BE_BATCH_FLAGS_CFG_PREPARED (1U << 0)
73#define MGMTD_BE_TXN_FLAGS_CFG_APPLIED (1U << 1)
74DECLARE_LIST(mgmt_be_batches, struct mgmt_be_batch_ctx, list_linkage);
75
76struct mgmt_be_client_ctx;
77
78PREDECL_LIST(mgmt_be_txns);
79struct mgmt_be_txn_ctx {
80 /* Txn-Id as assigned by MGMTD */
81 uint64_t txn_id;
82 uint32_t flags;
83
84 struct mgmt_be_client_txn_ctx client_data;
85 struct mgmt_be_client_ctx *client_ctx;
86
87 /* List of batches belonging to this transaction */
88 struct mgmt_be_batches_head cfg_batches;
89 struct mgmt_be_batches_head apply_cfgs;
90
91 struct mgmt_be_txns_item list_linkage;
92
93 struct nb_transaction *nb_txn;
94 uint32_t nb_txn_id;
95};
96#define MGMTD_BE_TXN_FLAGS_CFGPREP_FAILED (1U << 1)
97
98DECLARE_LIST(mgmt_be_txns, struct mgmt_be_txn_ctx, list_linkage);
99
100#define FOREACH_BE_TXN_BATCH_IN_LIST(txn, batch) \
101 frr_each_safe (mgmt_be_batches, &(txn)->cfg_batches, (batch))
102
103#define FOREACH_BE_APPLY_BATCH_IN_LIST(txn, batch) \
104 frr_each_safe (mgmt_be_batches, &(txn)->apply_cfgs, (batch))
105
106struct mgmt_be_client_ctx {
107 int conn_fd;
cd9d0537 108 struct event_loop *tm;
e6685141
DS
109 struct event *conn_retry_tmr;
110 struct event *conn_read_ev;
111 struct event *conn_write_ev;
112 struct event *conn_writes_on;
113 struct event *msg_proc_ev;
7d65b7b7 114 uint32_t flags;
7d65b7b7 115
f82370b4 116 struct mgmt_msg_state mstate;
7d65b7b7
CH
117
118 struct nb_config *candidate_config;
119 struct nb_config *running_config;
120
121 unsigned long num_batch_find;
122 unsigned long avg_batch_find_tm;
123 unsigned long num_edit_nb_cfg;
124 unsigned long avg_edit_nb_cfg_tm;
125 unsigned long num_prep_nb_cfg;
126 unsigned long avg_prep_nb_cfg_tm;
127 unsigned long num_apply_nb_cfg;
128 unsigned long avg_apply_nb_cfg_tm;
129
130 struct mgmt_be_txns_head txn_head;
131 struct mgmt_be_client_params client_params;
132};
133
134#define MGMTD_BE_CLIENT_FLAGS_WRITES_OFF (1U << 0)
135
136#define FOREACH_BE_TXN_IN_LIST(client_ctx, txn) \
137 frr_each_safe (mgmt_be_txns, &(client_ctx)->txn_head, (txn))
138
139static bool mgmt_debug_be_client;
140
f82370b4
CH
141static struct mgmt_be_client_ctx mgmt_be_client_ctx = {
142 .conn_fd = -1,
143};
7d65b7b7
CH
144
145const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = {
7d65b7b7
CH
146#ifdef HAVE_STATICD
147 [MGMTD_BE_CLIENT_ID_STATICD] = "staticd",
7d65b7b7
CH
148#endif
149 [MGMTD_BE_CLIENT_ID_MAX] = "Unknown/Invalid",
150};
151
152/* Forward declarations */
153static void
154mgmt_be_client_register_event(struct mgmt_be_client_ctx *client_ctx,
155 enum mgmt_be_event event);
156static void
157mgmt_be_client_schedule_conn_retry(struct mgmt_be_client_ctx *client_ctx,
158 unsigned long intvl_secs);
159static int mgmt_be_client_send_msg(struct mgmt_be_client_ctx *client_ctx,
160 Mgmtd__BeMessage *be_msg);
161
162static void
163mgmt_be_server_disconnect(struct mgmt_be_client_ctx *client_ctx,
164 bool reconnect)
165{
166 /* Notify client through registered callback (if any) */
167 if (client_ctx->client_params.client_connect_notify)
f82370b4 168 (void)(*client_ctx->client_params.client_connect_notify)(
7d65b7b7
CH
169 (uintptr_t)client_ctx,
170 client_ctx->client_params.user_data, false);
171
f82370b4 172 if (client_ctx->conn_fd != -1) {
7d65b7b7 173 close(client_ctx->conn_fd);
f82370b4 174 client_ctx->conn_fd = -1;
7d65b7b7
CH
175 }
176
177 if (reconnect)
178 mgmt_be_client_schedule_conn_retry(
179 client_ctx,
180 client_ctx->client_params.conn_retry_intvl_sec);
181}
182
183static struct mgmt_be_batch_ctx *
184mgmt_be_find_batch_by_id(struct mgmt_be_txn_ctx *txn,
185 uint64_t batch_id)
186{
187 struct mgmt_be_batch_ctx *batch = NULL;
188
189 FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) {
190 if (batch->batch_id == batch_id)
191 return batch;
192 }
193
194 return NULL;
195}
196
197static struct mgmt_be_batch_ctx *
198mgmt_be_batch_create(struct mgmt_be_txn_ctx *txn, uint64_t batch_id)
199{
200 struct mgmt_be_batch_ctx *batch = NULL;
201
202 batch = mgmt_be_find_batch_by_id(txn, batch_id);
203 if (!batch) {
204 batch = XCALLOC(MTYPE_MGMTD_BE_BATCH,
205 sizeof(struct mgmt_be_batch_ctx));
206 assert(batch);
207
208 batch->batch_id = batch_id;
209 mgmt_be_batches_add_tail(&txn->cfg_batches, batch);
210
211 MGMTD_BE_CLIENT_DBG("Added new batch 0x%llx to transaction",
212 (unsigned long long)batch_id);
213 }
214
215 return batch;
216}
217
218static void mgmt_be_batch_delete(struct mgmt_be_txn_ctx *txn,
219 struct mgmt_be_batch_ctx **batch)
220{
221 uint16_t indx;
222
223 if (!batch)
224 return;
225
226 mgmt_be_batches_del(&txn->cfg_batches, *batch);
227 if ((*batch)->txn_req.event == MGMTD_BE_TXN_PROC_SETCFG) {
228 for (indx = 0; indx < MGMTD_MAX_CFG_CHANGES_IN_BATCH; indx++) {
229 if ((*batch)->txn_req.req.set_cfg.cfg_changes[indx]
230 .value) {
231 free((char *)(*batch)
232 ->txn_req.req.set_cfg
233 .cfg_changes[indx]
234 .value);
235 }
236 }
237 }
238
239 XFREE(MTYPE_MGMTD_BE_BATCH, *batch);
240 *batch = NULL;
241}
242
243static void mgmt_be_cleanup_all_batches(struct mgmt_be_txn_ctx *txn)
244{
245 struct mgmt_be_batch_ctx *batch = NULL;
246
247 FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) {
248 mgmt_be_batch_delete(txn, &batch);
249 }
250
251 FOREACH_BE_APPLY_BATCH_IN_LIST (txn, batch) {
252 mgmt_be_batch_delete(txn, &batch);
253 }
254}
255
256static struct mgmt_be_txn_ctx *
257mgmt_be_find_txn_by_id(struct mgmt_be_client_ctx *client_ctx,
258 uint64_t txn_id)
259{
260 struct mgmt_be_txn_ctx *txn = NULL;
261
262 FOREACH_BE_TXN_IN_LIST (client_ctx, txn) {
263 if (txn->txn_id == txn_id)
264 return txn;
265 }
266
267 return NULL;
268}
269
270static struct mgmt_be_txn_ctx *
271mgmt_be_txn_create(struct mgmt_be_client_ctx *client_ctx,
272 uint64_t txn_id)
273{
274 struct mgmt_be_txn_ctx *txn = NULL;
275
276 txn = mgmt_be_find_txn_by_id(client_ctx, txn_id);
277 if (!txn) {
278 txn = XCALLOC(MTYPE_MGMTD_BE_TXN,
279 sizeof(struct mgmt_be_txn_ctx));
280 assert(txn);
281
282 txn->txn_id = txn_id;
283 txn->client_ctx = client_ctx;
284 mgmt_be_batches_init(&txn->cfg_batches);
285 mgmt_be_batches_init(&txn->apply_cfgs);
286 mgmt_be_txns_add_tail(&client_ctx->txn_head, txn);
287
288 MGMTD_BE_CLIENT_DBG("Added new transaction 0x%llx",
289 (unsigned long long)txn_id);
290 }
291
292 return txn;
293}
294
295static void mgmt_be_txn_delete(struct mgmt_be_client_ctx *client_ctx,
296 struct mgmt_be_txn_ctx **txn)
297{
298 char err_msg[] = "MGMT Transaction Delete";
299
300 if (!txn)
301 return;
302
303 /*
304 * Remove the transaction from the list of transactions
305 * so that future lookups with the same transaction id
306 * does not return this one.
307 */
308 mgmt_be_txns_del(&client_ctx->txn_head, *txn);
309
310 /*
311 * Time to delete the transaction which should also
312 * take care of cleaning up all batches created via
313 * CFGDATA_CREATE_REQs. But first notify the client
314 * about the transaction delete.
315 */
316 if (client_ctx->client_params.txn_notify)
317 (void)(*client_ctx->client_params
318 .txn_notify)(
319 (uintptr_t)client_ctx,
320 client_ctx->client_params.user_data,
321 &(*txn)->client_data, true);
322
323 mgmt_be_cleanup_all_batches(*txn);
324 if ((*txn)->nb_txn)
325 nb_candidate_commit_abort((*txn)->nb_txn, err_msg,
326 sizeof(err_msg));
327 XFREE(MTYPE_MGMTD_BE_TXN, *txn);
328
329 *txn = NULL;
330}
331
332static void
333mgmt_be_cleanup_all_txns(struct mgmt_be_client_ctx *client_ctx)
334{
335 struct mgmt_be_txn_ctx *txn = NULL;
336
337 FOREACH_BE_TXN_IN_LIST (client_ctx, txn) {
338 mgmt_be_txn_delete(client_ctx, &txn);
339 }
340}
341
342static int mgmt_be_send_txn_reply(struct mgmt_be_client_ctx *client_ctx,
343 uint64_t txn_id, bool create,
344 bool success)
345{
346 Mgmtd__BeMessage be_msg;
347 Mgmtd__BeTxnReply txn_reply;
348
349 mgmtd__be_txn_reply__init(&txn_reply);
350 txn_reply.create = create;
351 txn_reply.txn_id = txn_id;
352 txn_reply.success = success;
353
354 mgmtd__be_message__init(&be_msg);
355 be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY;
356 be_msg.txn_reply = &txn_reply;
357
358 MGMTD_BE_CLIENT_DBG(
359 "Sending TXN_REPLY message to MGMTD for txn 0x%llx",
360 (unsigned long long)txn_id);
361
362 return mgmt_be_client_send_msg(client_ctx, &be_msg);
363}
364
365static int mgmt_be_process_txn_req(struct mgmt_be_client_ctx *client_ctx,
366 uint64_t txn_id, bool create)
367{
368 struct mgmt_be_txn_ctx *txn;
369
370 txn = mgmt_be_find_txn_by_id(client_ctx, txn_id);
371 if (create) {
372 if (txn) {
373 /*
374 * Transaction with same txn-id already exists.
375 * Should not happen under any circumstances.
376 */
377 MGMTD_BE_CLIENT_ERR(
378 "Transaction 0x%llx already exists!!!",
379 (unsigned long long)txn_id);
380 mgmt_be_send_txn_reply(client_ctx, txn_id, create,
381 false);
382 }
383
384 MGMTD_BE_CLIENT_DBG("Created new transaction 0x%llx",
385 (unsigned long long)txn_id);
386 txn = mgmt_be_txn_create(client_ctx, txn_id);
387
388 if (client_ctx->client_params.txn_notify)
389 (void)(*client_ctx->client_params
390 .txn_notify)(
391 (uintptr_t)client_ctx,
392 client_ctx->client_params.user_data,
393 &txn->client_data, false);
394 } else {
395 if (!txn) {
396 /*
397 * Transaction with same txn-id does not exists.
398 * Return sucess anyways.
399 */
400 MGMTD_BE_CLIENT_DBG(
401 "Transaction to delete 0x%llx does NOT exists!!!",
402 (unsigned long long)txn_id);
403 } else {
404 MGMTD_BE_CLIENT_DBG("Delete transaction 0x%llx",
405 (unsigned long long)txn_id);
406 mgmt_be_txn_delete(client_ctx, &txn);
407 }
408 }
409
410 mgmt_be_send_txn_reply(client_ctx, txn_id, create, true);
411
412 return 0;
413}
414
415static int
416mgmt_be_send_cfgdata_create_reply(struct mgmt_be_client_ctx *client_ctx,
417 uint64_t txn_id, uint64_t batch_id,
418 bool success, const char *error_if_any)
419{
420 Mgmtd__BeMessage be_msg;
421 Mgmtd__BeCfgDataCreateReply cfgdata_reply;
422
423 mgmtd__be_cfg_data_create_reply__init(&cfgdata_reply);
424 cfgdata_reply.txn_id = (uint64_t)txn_id;
425 cfgdata_reply.batch_id = (uint64_t)batch_id;
426 cfgdata_reply.success = success;
427 if (error_if_any)
428 cfgdata_reply.error_if_any = (char *)error_if_any;
429
430 mgmtd__be_message__init(&be_msg);
431 be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY;
432 be_msg.cfg_data_reply = &cfgdata_reply;
433
434 MGMTD_BE_CLIENT_DBG(
435 "Sending CFGDATA_CREATE_REPLY message to MGMTD for txn 0x%llx batch 0x%llx",
436 (unsigned long long)txn_id, (unsigned long long)batch_id);
437
438 return mgmt_be_client_send_msg(client_ctx, &be_msg);
439}
440
441static void mgmt_be_txn_cfg_abort(struct mgmt_be_txn_ctx *txn)
442{
443 char errmsg[BUFSIZ] = {0};
444
445 assert(txn && txn->client_ctx);
446 if (txn->nb_txn) {
447 MGMTD_BE_CLIENT_ERR(
448 "Aborting configurations after prep for Txn 0x%llx",
449 (unsigned long long)txn->txn_id);
450 nb_candidate_commit_abort(txn->nb_txn, errmsg, sizeof(errmsg));
451 txn->nb_txn = 0;
452 }
453
454 /*
455 * revert candidate back to running
456 *
457 * This is one txn ctx but the candidate_config is per client ctx, how
458 * does that work?
459 */
460 MGMTD_BE_CLIENT_DBG(
461 "Reset candidate configurations after abort of Txn 0x%llx",
462 (unsigned long long)txn->txn_id);
463 nb_config_replace(txn->client_ctx->candidate_config,
464 txn->client_ctx->running_config, true);
465}
466
467static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn)
468{
469 struct mgmt_be_client_ctx *client_ctx;
470 struct mgmt_be_txn_req *txn_req = NULL;
471 struct nb_context nb_ctx = {0};
472 struct timeval edit_nb_cfg_start;
473 struct timeval edit_nb_cfg_end;
474 unsigned long edit_nb_cfg_tm;
475 struct timeval prep_nb_cfg_start;
476 struct timeval prep_nb_cfg_end;
477 unsigned long prep_nb_cfg_tm;
478 struct mgmt_be_batch_ctx *batch;
479 bool error;
480 char err_buf[BUFSIZ];
481 size_t num_processed;
482 bool debug_be = mgmt_debug_be_client;
483 int err;
484
485 assert(txn && txn->client_ctx);
486 client_ctx = txn->client_ctx;
487
488 num_processed = 0;
489 FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) {
490 txn_req = &batch->txn_req;
491 error = false;
492 nb_ctx.client = NB_CLIENT_CLI;
493 nb_ctx.user = (void *)client_ctx->client_params.user_data;
494
495 if (!txn->nb_txn) {
496 /*
497 * This happens when the current backend client is only
498 * interested in consuming the config items but is not
499 * interested in validating it.
500 */
501 error = false;
502 if (debug_be)
503 gettimeofday(&edit_nb_cfg_start, NULL);
504 nb_candidate_edit_config_changes(
505 client_ctx->candidate_config,
506 txn_req->req.set_cfg.cfg_changes,
507 (size_t)txn_req->req.set_cfg.num_cfg_changes,
508 NULL, NULL, 0, err_buf, sizeof(err_buf),
509 &error);
510 if (error) {
511 err_buf[sizeof(err_buf) - 1] = 0;
512 MGMTD_BE_CLIENT_ERR(
513 "Failed to update configs for Txn %llx Batch %llx to Candidate! Err: '%s'",
514 (unsigned long long)txn->txn_id,
515 (unsigned long long)batch->batch_id,
516 err_buf);
517 return -1;
518 }
519 if (debug_be) {
520 gettimeofday(&edit_nb_cfg_end, NULL);
521 edit_nb_cfg_tm = timeval_elapsed(
522 edit_nb_cfg_end, edit_nb_cfg_start);
523 client_ctx->avg_edit_nb_cfg_tm =
524 ((client_ctx->avg_edit_nb_cfg_tm
525 * client_ctx->num_edit_nb_cfg)
526 + edit_nb_cfg_tm)
527 / (client_ctx->num_edit_nb_cfg + 1);
528 }
529 client_ctx->num_edit_nb_cfg++;
530 }
531
532 num_processed++;
533 }
534
535 if (!num_processed)
536 return 0;
537
538 /*
539 * Now prepare all the batches we have applied in one go.
540 */
541 nb_ctx.client = NB_CLIENT_CLI;
542 nb_ctx.user = (void *)client_ctx->client_params.user_data;
543 if (debug_be)
544 gettimeofday(&prep_nb_cfg_start, NULL);
545 err = nb_candidate_commit_prepare(nb_ctx, client_ctx->candidate_config,
546 "MGMTD Backend Txn", &txn->nb_txn,
547#ifdef MGMTD_LOCAL_VALIDATIONS_ENABLED
548 true, true,
549#else
550 false, true,
551#endif
552 err_buf, sizeof(err_buf) - 1);
553 if (err != NB_OK) {
554 err_buf[sizeof(err_buf) - 1] = 0;
555 if (err == NB_ERR_VALIDATION)
556 MGMTD_BE_CLIENT_ERR(
557 "Failed to validate configs for Txn %llx %u Batches! Err: '%s'",
558 (unsigned long long)txn->txn_id,
559 (uint32_t)num_processed, err_buf);
560 else
561 MGMTD_BE_CLIENT_ERR(
562 "Failed to prepare configs for Txn %llx, %u Batches! Err: '%s'",
563 (unsigned long long)txn->txn_id,
564 (uint32_t)num_processed, err_buf);
565 error = true;
566 SET_FLAG(txn->flags, MGMTD_BE_TXN_FLAGS_CFGPREP_FAILED);
567 } else
568 MGMTD_BE_CLIENT_DBG(
569 "Prepared configs for Txn %llx, %u Batches! successfully!",
570 (unsigned long long)txn->txn_id,
571 (uint32_t)num_processed);
572 if (debug_be) {
573 gettimeofday(&prep_nb_cfg_end, NULL);
574 prep_nb_cfg_tm =
575 timeval_elapsed(prep_nb_cfg_end, prep_nb_cfg_start);
576 client_ctx->avg_prep_nb_cfg_tm =
577 ((client_ctx->avg_prep_nb_cfg_tm
578 * client_ctx->num_prep_nb_cfg)
579 + prep_nb_cfg_tm)
580 / (client_ctx->num_prep_nb_cfg + 1);
581 }
582 client_ctx->num_prep_nb_cfg++;
583
584 FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) {
585 mgmt_be_send_cfgdata_create_reply(
586 client_ctx, txn->txn_id, batch->batch_id,
587 error ? false : true, error ? err_buf : NULL);
588 if (!error) {
589 SET_FLAG(batch->flags,
590 MGMTD_BE_BATCH_FLAGS_CFG_PREPARED);
591 mgmt_be_batches_del(&txn->cfg_batches, batch);
592 mgmt_be_batches_add_tail(&txn->apply_cfgs, batch);
593 }
594 }
595
596 if (debug_be)
597 MGMTD_BE_CLIENT_DBG(
598 "Avg-nb-edit-duration %lu uSec, nb-prep-duration %lu (avg: %lu) uSec, batch size %u",
599 client_ctx->avg_edit_nb_cfg_tm, prep_nb_cfg_tm,
600 client_ctx->avg_prep_nb_cfg_tm, (uint32_t)num_processed);
601
602 if (error)
603 mgmt_be_txn_cfg_abort(txn);
604
605 return 0;
606}
607
608/*
609 * Process all CFG_DATA_REQs received so far and prepare them all in one go.
610 */
611static int
612mgmt_be_update_setcfg_in_batch(struct mgmt_be_client_ctx *client_ctx,
613 struct mgmt_be_txn_ctx *txn,
614 uint64_t batch_id,
615 Mgmtd__YangCfgDataReq * cfg_req[],
616 int num_req)
617{
618 struct mgmt_be_batch_ctx *batch = NULL;
619 struct mgmt_be_txn_req *txn_req = NULL;
620 int index;
621 struct nb_cfg_change *cfg_chg;
622
623 batch = mgmt_be_batch_create(txn, batch_id);
624 if (!batch) {
625 MGMTD_BE_CLIENT_ERR("Batch create failed!");
626 return -1;
627 }
628
629 txn_req = &batch->txn_req;
630 txn_req->event = MGMTD_BE_TXN_PROC_SETCFG;
631 MGMTD_BE_CLIENT_DBG(
632 "Created Set-Config request for batch 0x%llx, txn id 0x%llx, cfg-items:%d",
633 (unsigned long long)batch_id, (unsigned long long)txn->txn_id,
634 num_req);
635
636 txn_req->req.set_cfg.num_cfg_changes = num_req;
637 for (index = 0; index < num_req; index++) {
638 cfg_chg = &txn_req->req.set_cfg.cfg_changes[index];
639
640 if (cfg_req[index]->req_type
641 == MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA)
642 cfg_chg->operation = NB_OP_DESTROY;
643 else
644 cfg_chg->operation = NB_OP_CREATE;
645
646 strlcpy(cfg_chg->xpath, cfg_req[index]->data->xpath,
647 sizeof(cfg_chg->xpath));
648 cfg_chg->value = (cfg_req[index]->data->value
649 && cfg_req[index]
650 ->data->value
651 ->encoded_str_val
652 ? strdup(cfg_req[index]
653 ->data->value
654 ->encoded_str_val)
655 : NULL);
656 if (cfg_chg->value
657 && !strncmp(cfg_chg->value, MGMTD_BE_CONTAINER_NODE_VAL,
658 strlen(MGMTD_BE_CONTAINER_NODE_VAL))) {
659 free((char *)cfg_chg->value);
660 cfg_chg->value = NULL;
661 }
662 }
663
664 return 0;
665}
666
667static int
668mgmt_be_process_cfgdata_req(struct mgmt_be_client_ctx *client_ctx,
669 uint64_t txn_id, uint64_t batch_id,
670 Mgmtd__YangCfgDataReq * cfg_req[], int num_req,
671 bool end_of_data)
672{
673 struct mgmt_be_txn_ctx *txn;
674
675 txn = mgmt_be_find_txn_by_id(client_ctx, txn_id);
676 if (!txn) {
677 MGMTD_BE_CLIENT_ERR(
678 "Invalid txn-id 0x%llx provided from MGMTD server",
679 (unsigned long long)txn_id);
680 mgmt_be_send_cfgdata_create_reply(
681 client_ctx, txn_id, batch_id, false,
682 "Transaction context not created yet");
683 } else {
684 mgmt_be_update_setcfg_in_batch(client_ctx, txn, batch_id,
685 cfg_req, num_req);
686 }
687
688 if (txn && end_of_data) {
689 MGMTD_BE_CLIENT_DBG("Triggering CFG_PREPARE_REQ processing");
690 mgmt_be_txn_cfg_prepare(txn);
691 }
692
693 return 0;
694}
695
696static int mgmt_be_send_apply_reply(struct mgmt_be_client_ctx *client_ctx,
697 uint64_t txn_id, uint64_t batch_ids[],
698 size_t num_batch_ids, bool success,
699 const char *error_if_any)
700{
701 Mgmtd__BeMessage be_msg;
702 Mgmtd__BeCfgDataApplyReply apply_reply;
703
704 mgmtd__be_cfg_data_apply_reply__init(&apply_reply);
705 apply_reply.success = success;
706 apply_reply.txn_id = txn_id;
707 apply_reply.batch_ids = (uint64_t *)batch_ids;
708 apply_reply.n_batch_ids = num_batch_ids;
709
710 if (error_if_any)
711 apply_reply.error_if_any = (char *)error_if_any;
712
713 mgmtd__be_message__init(&be_msg);
714 be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY;
715 be_msg.cfg_apply_reply = &apply_reply;
716
717 MGMTD_BE_CLIENT_DBG(
718 "Sending CFG_APPLY_REPLY message to MGMTD for txn 0x%llx, %d batches [0x%llx - 0x%llx]",
719 (unsigned long long)txn_id, (int)num_batch_ids,
720 success && num_batch_ids ?
721 (unsigned long long)batch_ids[0] : 0,
722 success && num_batch_ids ?
723 (unsigned long long)batch_ids[num_batch_ids - 1] : 0);
724
725 return mgmt_be_client_send_msg(client_ctx, &be_msg);
726}
727
728static int mgmt_be_txn_proc_cfgapply(struct mgmt_be_txn_ctx *txn)
729{
730 struct mgmt_be_client_ctx *client_ctx;
731 struct timeval apply_nb_cfg_start;
732 struct timeval apply_nb_cfg_end;
733 unsigned long apply_nb_cfg_tm;
734 struct mgmt_be_batch_ctx *batch;
735 char err_buf[BUFSIZ];
736 size_t num_processed;
737 static uint64_t batch_ids[MGMTD_BE_MAX_BATCH_IDS_IN_REQ];
738 bool debug_be = mgmt_debug_be_client;
739
740 assert(txn && txn->client_ctx);
741 client_ctx = txn->client_ctx;
742
743 assert(txn->nb_txn);
744 num_processed = 0;
745
746 /*
747 * Now apply all the batches we have applied in one go.
748 */
749 if (debug_be)
750 gettimeofday(&apply_nb_cfg_start, NULL);
751 (void)nb_candidate_commit_apply(txn->nb_txn, true, &txn->nb_txn_id,
752 err_buf, sizeof(err_buf) - 1);
753 if (debug_be) {
754 gettimeofday(&apply_nb_cfg_end, NULL);
755 apply_nb_cfg_tm =
756 timeval_elapsed(apply_nb_cfg_end, apply_nb_cfg_start);
757 client_ctx->avg_apply_nb_cfg_tm =
758 ((client_ctx->avg_apply_nb_cfg_tm
759 * client_ctx->num_apply_nb_cfg)
760 + apply_nb_cfg_tm)
761 / (client_ctx->num_apply_nb_cfg + 1);
762 }
763 client_ctx->num_apply_nb_cfg++;
764 txn->nb_txn = NULL;
765
766 /*
767 * Send back CFG_APPLY_REPLY for all batches applied.
768 */
769 FOREACH_BE_APPLY_BATCH_IN_LIST (txn, batch) {
770 /*
771 * No need to delete the batch yet. Will be deleted during
772 * transaction cleanup on receiving TXN_DELETE_REQ.
773 */
774 SET_FLAG(batch->flags, MGMTD_BE_TXN_FLAGS_CFG_APPLIED);
775 mgmt_be_batches_del(&txn->apply_cfgs, batch);
776 mgmt_be_batches_add_tail(&txn->cfg_batches, batch);
777
778 batch_ids[num_processed] = batch->batch_id;
779 num_processed++;
780 if (num_processed == MGMTD_BE_MAX_BATCH_IDS_IN_REQ) {
781 mgmt_be_send_apply_reply(client_ctx, txn->txn_id,
782 batch_ids, num_processed,
783 true, NULL);
784 num_processed = 0;
785 }
786 }
787
788 mgmt_be_send_apply_reply(client_ctx, txn->txn_id, batch_ids,
789 num_processed, true, NULL);
790
791 if (debug_be)
792 MGMTD_BE_CLIENT_DBG("Nb-apply-duration %lu (avg: %lu) uSec",
793 apply_nb_cfg_tm,
794 client_ctx->avg_apply_nb_cfg_tm);
795
796 return 0;
797}
798
799static int
800mgmt_be_process_cfg_apply(struct mgmt_be_client_ctx *client_ctx,
801 uint64_t txn_id)
802{
803 struct mgmt_be_txn_ctx *txn;
804
805 txn = mgmt_be_find_txn_by_id(client_ctx, txn_id);
806 if (!txn) {
807 mgmt_be_send_apply_reply(client_ctx, txn_id, NULL, 0, false,
808 "Transaction not created yet!");
809 return -1;
810 }
811
812 MGMTD_BE_CLIENT_DBG("Trigger CFG_APPLY_REQ processing");
813 mgmt_be_txn_proc_cfgapply(txn);
814
815 return 0;
816}
817
818static int
819mgmt_be_client_handle_msg(struct mgmt_be_client_ctx *client_ctx,
820 Mgmtd__BeMessage *be_msg)
821{
0b645fd2
CH
822 /*
823 * protobuf-c adds a max size enum with an internal, and changing by
824 * version, name; cast to an int to avoid unhandled enum warnings
825 */
826 switch ((int)be_msg->message_case) {
7d65b7b7
CH
827 case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY:
828 MGMTD_BE_CLIENT_DBG("Subscribe Reply Msg from mgmt, status %u",
829 be_msg->subscr_reply->success);
830 break;
831 case MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ:
832 mgmt_be_process_txn_req(client_ctx,
833 be_msg->txn_req->txn_id,
834 be_msg->txn_req->create);
835 break;
836 case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ:
837 mgmt_be_process_cfgdata_req(
838 client_ctx, be_msg->cfg_data_req->txn_id,
839 be_msg->cfg_data_req->batch_id,
840 be_msg->cfg_data_req->data_req,
841 be_msg->cfg_data_req->n_data_req,
842 be_msg->cfg_data_req->end_of_data);
843 break;
844 case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ:
845 mgmt_be_process_cfg_apply(
846 client_ctx, (uint64_t)be_msg->cfg_apply_req->txn_id);
847 break;
848 case MGMTD__BE_MESSAGE__MESSAGE_GET_REQ:
849 case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ:
850 case MGMTD__BE_MESSAGE__MESSAGE_CFG_CMD_REQ:
851 case MGMTD__BE_MESSAGE__MESSAGE_SHOW_CMD_REQ:
852 /*
853 * TODO: Add handling code in future.
854 */
855 break;
856 /*
857 * NOTE: The following messages are always sent from Backend
858 * clients to MGMTd only and/or need not be handled here.
859 */
860 case MGMTD__BE_MESSAGE__MESSAGE_GET_REPLY:
861 case MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY:
862 case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY:
863 case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY:
864 case MGMTD__BE_MESSAGE__MESSAGE_CFG_CMD_REPLY:
865 case MGMTD__BE_MESSAGE__MESSAGE_SHOW_CMD_REPLY:
866 case MGMTD__BE_MESSAGE__MESSAGE_NOTIFY_DATA:
867 case MGMTD__BE_MESSAGE__MESSAGE__NOT_SET:
7d65b7b7
CH
868 default:
869 /*
870 * A 'default' case is being added contrary to the
871 * FRR code guidelines to take care of build
872 * failures on certain build systems (courtesy of
873 * the proto-c package).
874 */
875 break;
876 }
877
878 return 0;
879}
880
f82370b4
CH
881static void mgmt_be_client_process_msg(void *user_ctx, uint8_t *data,
882 size_t len)
7d65b7b7 883{
f82370b4 884 struct mgmt_be_client_ctx *client_ctx = user_ctx;
7d65b7b7 885 Mgmtd__BeMessage *be_msg;
7d65b7b7 886
f82370b4
CH
887 be_msg = mgmtd__be_message__unpack(NULL, len, data);
888 if (!be_msg) {
889 MGMTD_BE_CLIENT_DBG("Failed to decode %zu bytes from server",
890 len);
891 return;
7d65b7b7 892 }
f82370b4
CH
893 MGMTD_BE_CLIENT_DBG(
894 "Decoded %zu bytes of message(msg: %u/%u) from server", len,
895 be_msg->message_case, be_msg->message_case);
896 (void)mgmt_be_client_handle_msg(client_ctx, be_msg);
897 mgmtd__be_message__free_unpacked(be_msg, NULL);
7d65b7b7
CH
898}
899
e6685141 900static void mgmt_be_client_proc_msgbufs(struct event *thread)
7d65b7b7 901{
e16d030c 902 struct mgmt_be_client_ctx *client_ctx = EVENT_ARG(thread);
7d65b7b7 903
f82370b4
CH
904 if (mgmt_msg_procbufs(&client_ctx->mstate, mgmt_be_client_process_msg,
905 client_ctx, mgmt_debug_be_client))
906 mgmt_be_client_register_event(client_ctx, MGMTD_BE_PROC_MSG);
7d65b7b7
CH
907}
908
e6685141 909static void mgmt_be_client_read(struct event *thread)
7d65b7b7 910{
e16d030c 911 struct mgmt_be_client_ctx *client_ctx = EVENT_ARG(thread);
f82370b4 912 enum mgmt_msg_rsched rv;
7d65b7b7 913
f82370b4
CH
914 rv = mgmt_msg_read(&client_ctx->mstate, client_ctx->conn_fd,
915 mgmt_debug_be_client);
916 if (rv == MSR_DISCONNECT) {
917 mgmt_be_server_disconnect(client_ctx, true);
918 return;
7d65b7b7 919 }
f82370b4
CH
920 if (rv == MSR_SCHED_BOTH)
921 mgmt_be_client_register_event(client_ctx, MGMTD_BE_PROC_MSG);
7d65b7b7
CH
922 mgmt_be_client_register_event(client_ctx, MGMTD_BE_CONN_READ);
923}
924
925static inline void
926mgmt_be_client_sched_msg_write(struct mgmt_be_client_ctx *client_ctx)
927{
928 if (!CHECK_FLAG(client_ctx->flags, MGMTD_BE_CLIENT_FLAGS_WRITES_OFF))
929 mgmt_be_client_register_event(client_ctx,
930 MGMTD_BE_CONN_WRITE);
931}
932
933static inline void
934mgmt_be_client_writes_on(struct mgmt_be_client_ctx *client_ctx)
935{
936 MGMTD_BE_CLIENT_DBG("Resume writing msgs");
937 UNSET_FLAG(client_ctx->flags, MGMTD_BE_CLIENT_FLAGS_WRITES_OFF);
f82370b4 938 mgmt_be_client_sched_msg_write(client_ctx);
7d65b7b7
CH
939}
940
941static inline void
942mgmt_be_client_writes_off(struct mgmt_be_client_ctx *client_ctx)
943{
944 SET_FLAG(client_ctx->flags, MGMTD_BE_CLIENT_FLAGS_WRITES_OFF);
945 MGMTD_BE_CLIENT_DBG("Paused writing msgs");
946}
947
948static int mgmt_be_client_send_msg(struct mgmt_be_client_ctx *client_ctx,
f82370b4 949 Mgmtd__BeMessage *be_msg)
7d65b7b7 950{
f82370b4
CH
951 if (client_ctx->conn_fd == -1) {
952 MGMTD_BE_CLIENT_DBG("can't send message on closed connection");
7d65b7b7
CH
953 return -1;
954 }
955
f82370b4
CH
956 int rv = mgmt_msg_send_msg(
957 &client_ctx->mstate, be_msg,
958 mgmtd__be_message__get_packed_size(be_msg),
959 (size_t(*)(void *, void *))mgmtd__be_message__pack,
960 mgmt_debug_be_client);
7d65b7b7 961 mgmt_be_client_sched_msg_write(client_ctx);
f82370b4 962 return rv;
7d65b7b7
CH
963}
964
e6685141 965static void mgmt_be_client_write(struct event *thread)
7d65b7b7 966{
e16d030c 967 struct mgmt_be_client_ctx *client_ctx = EVENT_ARG(thread);
f82370b4
CH
968 enum mgmt_msg_wsched rv;
969
970 rv = mgmt_msg_write(&client_ctx->mstate, client_ctx->conn_fd,
971 mgmt_debug_be_client);
972 if (rv == MSW_SCHED_STREAM)
973 mgmt_be_client_register_event(client_ctx, MGMTD_BE_CONN_WRITE);
974 else if (rv == MSW_DISCONNECT)
975 mgmt_be_server_disconnect(client_ctx, true);
976 else if (rv == MSW_SCHED_WRITES_OFF) {
7d65b7b7
CH
977 mgmt_be_client_writes_off(client_ctx);
978 mgmt_be_client_register_event(client_ctx,
f82370b4
CH
979 MGMTD_BE_CONN_WRITES_ON);
980 } else
981 assert(rv == MSW_SCHED_NONE);
7d65b7b7
CH
982}
983
e6685141 984static void mgmt_be_client_resume_writes(struct event *thread)
7d65b7b7
CH
985{
986 struct mgmt_be_client_ctx *client_ctx;
987
e16d030c 988 client_ctx = (struct mgmt_be_client_ctx *)EVENT_ARG(thread);
f82370b4 989 assert(client_ctx && client_ctx->conn_fd != -1);
7d65b7b7
CH
990
991 mgmt_be_client_writes_on(client_ctx);
992}
993
994static int mgmt_be_send_subscr_req(struct mgmt_be_client_ctx *client_ctx,
f82370b4
CH
995 bool subscr_xpaths, uint16_t num_reg_xpaths,
996 char **reg_xpaths)
7d65b7b7
CH
997{
998 Mgmtd__BeMessage be_msg;
999 Mgmtd__BeSubscribeReq subscr_req;
1000
1001 mgmtd__be_subscribe_req__init(&subscr_req);
1002 subscr_req.client_name = client_ctx->client_params.name;
1003 subscr_req.n_xpath_reg = num_reg_xpaths;
1004 if (num_reg_xpaths)
1005 subscr_req.xpath_reg = reg_xpaths;
1006 else
1007 subscr_req.xpath_reg = NULL;
1008 subscr_req.subscribe_xpaths = subscr_xpaths;
1009
1010 mgmtd__be_message__init(&be_msg);
1011 be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ;
1012 be_msg.subscr_req = &subscr_req;
1013
1014 return mgmt_be_client_send_msg(client_ctx, &be_msg);
1015}
1016
f82370b4 1017static void mgmt_be_server_connect(struct mgmt_be_client_ctx *client_ctx)
7d65b7b7 1018{
f82370b4 1019 const char *dbgtag = mgmt_debug_be_client ? "BE-client" : NULL;
7d65b7b7 1020
f82370b4
CH
1021 assert(client_ctx->conn_fd == -1);
1022 client_ctx->conn_fd = mgmt_msg_connect(
1023 MGMTD_BE_SERVER_PATH, MGMTD_SOCKET_BE_SEND_BUF_SIZE,
1024 MGMTD_SOCKET_BE_RECV_BUF_SIZE, dbgtag);
7d65b7b7 1025
f82370b4
CH
1026 /* Send SUBSCRIBE_REQ message */
1027 if (client_ctx->conn_fd == -1 ||
1028 mgmt_be_send_subscr_req(client_ctx, false, 0, NULL) != 0) {
1029 mgmt_be_server_disconnect(client_ctx, true);
1030 return;
7d65b7b7
CH
1031 }
1032
f82370b4 1033 /* Start reading from the socket */
7d65b7b7
CH
1034 mgmt_be_client_register_event(client_ctx, MGMTD_BE_CONN_READ);
1035
1036 /* Notify client through registered callback (if any) */
1037 if (client_ctx->client_params.client_connect_notify)
f82370b4 1038 (void)(*client_ctx->client_params.client_connect_notify)(
7d65b7b7
CH
1039 (uintptr_t)client_ctx,
1040 client_ctx->client_params.user_data, true);
7d65b7b7
CH
1041}
1042
e6685141 1043static void mgmt_be_client_conn_timeout(struct event *thread)
7d65b7b7 1044{
e16d030c 1045 mgmt_be_server_connect(EVENT_ARG(thread));
7d65b7b7
CH
1046}
1047
1048static void
1049mgmt_be_client_register_event(struct mgmt_be_client_ctx *client_ctx,
1050 enum mgmt_be_event event)
1051{
1052 struct timeval tv = {0};
1053
1054 switch (event) {
1055 case MGMTD_BE_CONN_READ:
907a2395 1056 event_add_read(client_ctx->tm, mgmt_be_client_read,
7d65b7b7
CH
1057 client_ctx, client_ctx->conn_fd,
1058 &client_ctx->conn_read_ev);
7d65b7b7
CH
1059 break;
1060 case MGMTD_BE_CONN_WRITE:
907a2395 1061 event_add_write(client_ctx->tm, mgmt_be_client_write,
7d65b7b7
CH
1062 client_ctx, client_ctx->conn_fd,
1063 &client_ctx->conn_write_ev);
7d65b7b7
CH
1064 break;
1065 case MGMTD_BE_PROC_MSG:
1066 tv.tv_usec = MGMTD_BE_MSG_PROC_DELAY_USEC;
907a2395 1067 event_add_timer_tv(client_ctx->tm, mgmt_be_client_proc_msgbufs,
f82370b4 1068 client_ctx, &tv, &client_ctx->msg_proc_ev);
7d65b7b7
CH
1069 break;
1070 case MGMTD_BE_CONN_WRITES_ON:
907a2395 1071 event_add_timer_msec(client_ctx->tm,
f82370b4
CH
1072 mgmt_be_client_resume_writes, client_ctx,
1073 MGMTD_BE_MSG_WRITE_DELAY_MSEC,
1074 &client_ctx->conn_writes_on);
7d65b7b7
CH
1075 break;
1076 case MGMTD_BE_SERVER:
1077 case MGMTD_BE_CONN_INIT:
1078 case MGMTD_BE_SCHED_CFG_PREPARE:
1079 case MGMTD_BE_RESCHED_CFG_PREPARE:
1080 case MGMTD_BE_SCHED_CFG_APPLY:
1081 case MGMTD_BE_RESCHED_CFG_APPLY:
1082 assert(!"mgmt_be_client_post_event() called incorrectly");
1083 break;
1084 }
1085}
1086
1087static void
1088mgmt_be_client_schedule_conn_retry(struct mgmt_be_client_ctx *client_ctx,
1089 unsigned long intvl_secs)
1090{
1091 MGMTD_BE_CLIENT_DBG(
1092 "Scheduling MGMTD Backend server connection retry after %lu seconds",
1093 intvl_secs);
907a2395 1094 event_add_timer(client_ctx->tm, mgmt_be_client_conn_timeout,
7d65b7b7
CH
1095 (void *)client_ctx, intvl_secs,
1096 &client_ctx->conn_retry_tmr);
1097}
1098
1099extern struct nb_config *running_config;
1100
1101/*
1102 * Initialize library and try connecting with MGMTD.
1103 */
1104uintptr_t mgmt_be_client_lib_init(struct mgmt_be_client_params *params,
cd9d0537 1105 struct event_loop *master_thread)
7d65b7b7
CH
1106{
1107 assert(master_thread && params && strlen(params->name)
1108 && !mgmt_be_client_ctx.tm);
1109
1110 mgmt_be_client_ctx.tm = master_thread;
1111
1112 if (!running_config)
1113 assert(!"MGMTD Be Client lib_init() after frr_init() only!");
1114 mgmt_be_client_ctx.running_config = running_config;
1115 mgmt_be_client_ctx.candidate_config = nb_config_new(NULL);
1116
1117 memcpy(&mgmt_be_client_ctx.client_params, params,
1118 sizeof(mgmt_be_client_ctx.client_params));
1119 if (!mgmt_be_client_ctx.client_params.conn_retry_intvl_sec)
1120 mgmt_be_client_ctx.client_params.conn_retry_intvl_sec =
1121 MGMTD_BE_DEFAULT_CONN_RETRY_INTVL_SEC;
1122
7d65b7b7 1123 mgmt_be_txns_init(&mgmt_be_client_ctx.txn_head);
f82370b4
CH
1124 mgmt_msg_init(&mgmt_be_client_ctx.mstate, MGMTD_BE_MAX_NUM_MSG_PROC,
1125 MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MSG_MAX_LEN,
1126 "BE-client");
7d65b7b7
CH
1127
1128 /* Start trying to connect to MGMTD backend server immediately */
1129 mgmt_be_client_schedule_conn_retry(&mgmt_be_client_ctx, 1);
1130
1131 MGMTD_BE_CLIENT_DBG("Initialized client '%s'", params->name);
1132
1133 return (uintptr_t)&mgmt_be_client_ctx;
1134}
1135
1136/*
1137 * Subscribe with MGMTD for one or more YANG subtree(s).
1138 */
1139enum mgmt_result mgmt_be_subscribe_yang_data(uintptr_t lib_hndl,
1140 char *reg_yang_xpaths[],
1141 int num_reg_xpaths)
1142{
1143 struct mgmt_be_client_ctx *client_ctx;
1144
1145 client_ctx = (struct mgmt_be_client_ctx *)lib_hndl;
1146 if (!client_ctx)
1147 return MGMTD_INVALID_PARAM;
1148
1149 if (mgmt_be_send_subscr_req(client_ctx, true, num_reg_xpaths,
1150 reg_yang_xpaths)
1151 != 0)
1152 return MGMTD_INTERNAL_ERROR;
1153
1154 return MGMTD_SUCCESS;
1155}
1156
1157/*
1158 * Unsubscribe with MGMTD for one or more YANG subtree(s).
1159 */
1160enum mgmt_result mgmt_be_unsubscribe_yang_data(uintptr_t lib_hndl,
1161 char *reg_yang_xpaths[],
1162 int num_reg_xpaths)
1163{
1164 struct mgmt_be_client_ctx *client_ctx;
1165
1166 client_ctx = (struct mgmt_be_client_ctx *)lib_hndl;
1167 if (!client_ctx)
1168 return MGMTD_INVALID_PARAM;
1169
1170
1171 if (mgmt_be_send_subscr_req(client_ctx, false, num_reg_xpaths,
1172 reg_yang_xpaths)
1173 < 0)
1174 return MGMTD_INTERNAL_ERROR;
1175
1176 return MGMTD_SUCCESS;
1177}
1178
1179/*
1180 * Send one or more YANG notifications to MGMTD daemon.
1181 */
1182enum mgmt_result mgmt_be_send_yang_notify(uintptr_t lib_hndl,
1183 Mgmtd__YangData * data_elems[],
1184 int num_elems)
1185{
1186 struct mgmt_be_client_ctx *client_ctx;
1187
1188 client_ctx = (struct mgmt_be_client_ctx *)lib_hndl;
1189 if (!client_ctx)
1190 return MGMTD_INVALID_PARAM;
1191
1192 return MGMTD_SUCCESS;
1193}
1194
1195/*
1196 * Destroy library and cleanup everything.
1197 */
1198void mgmt_be_client_lib_destroy(uintptr_t lib_hndl)
1199{
1200 struct mgmt_be_client_ctx *client_ctx;
1201
1202 client_ctx = (struct mgmt_be_client_ctx *)lib_hndl;
1203 assert(client_ctx);
1204
1205 MGMTD_BE_CLIENT_DBG("Destroying MGMTD Backend Client '%s'",
f82370b4 1206 client_ctx->client_params.name);
7d65b7b7
CH
1207
1208 mgmt_be_server_disconnect(client_ctx, false);
1209
f82370b4 1210 mgmt_msg_destroy(&client_ctx->mstate);
7d65b7b7 1211
e16d030c
DS
1212 EVENT_OFF(client_ctx->conn_retry_tmr);
1213 EVENT_OFF(client_ctx->conn_read_ev);
1214 EVENT_OFF(client_ctx->conn_write_ev);
1215 EVENT_OFF(client_ctx->conn_writes_on);
1216 EVENT_OFF(client_ctx->msg_proc_ev);
7d65b7b7
CH
1217 mgmt_be_cleanup_all_txns(client_ctx);
1218 mgmt_be_txns_fini(&client_ctx->txn_head);
1219}