]>
Commit | Line | Data |
---|---|---|
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> | |
cfa0facb | 9 | #include "debug.h" |
070c5e7a | 10 | #include "compiler.h" |
7d65b7b7 CH |
11 | #include "libfrr.h" |
12 | #include "mgmtd/mgmt.h" | |
13 | #include "mgmt_be_client.h" | |
f82370b4 | 14 | #include "mgmt_msg.h" |
7d65b7b7 CH |
15 | #include "mgmt_pb.h" |
16 | #include "network.h" | |
cfa0facb | 17 | #include "northbound.h" |
7d65b7b7 CH |
18 | #include "stream.h" |
19 | #include "sockopt.h" | |
20 | ||
cfa0facb CH |
21 | #include "lib/mgmt_be_client_clippy.c" |
22 | ||
83b78f43 | 23 | #define MGMTD_BE_CLIENT_DBG(fmt, ...) \ |
08e8019c CH |
24 | DEBUGD(&mgmt_dbg_be_client, "BE-CLIENT: %s:" fmt, __func__, \ |
25 | ##__VA_ARGS__) | |
83b78f43 | 26 | #define MGMTD_BE_CLIENT_ERR(fmt, ...) \ |
08e8019c | 27 | zlog_err("BE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__) |
cfa0facb CH |
28 | #define MGMTD_DBG_BE_CLIENT_CHECK() \ |
29 | DEBUG_MODE_CHECK(&mgmt_dbg_be_client, DEBUG_MODE_ALL) | |
7d65b7b7 | 30 | |
7aecb863 CH |
31 | DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_CLIENT, "backend client"); |
32 | DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_CLIENT_NAME, "backend client name"); | |
df6eb0bd DS |
33 | DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_BATCH, "backend transaction batch data"); |
34 | DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_TXN, "backend transaction data"); | |
7d65b7b7 CH |
35 | |
36 | enum mgmt_be_txn_event { | |
37 | MGMTD_BE_TXN_PROC_SETCFG = 1, | |
38 | MGMTD_BE_TXN_PROC_GETCFG, | |
39 | MGMTD_BE_TXN_PROC_GETDATA | |
40 | }; | |
41 | ||
42 | struct mgmt_be_set_cfg_req { | |
43 | struct nb_cfg_change cfg_changes[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; | |
44 | uint16_t num_cfg_changes; | |
45 | }; | |
46 | ||
47 | struct mgmt_be_get_data_req { | |
48 | char *xpaths[MGMTD_MAX_NUM_DATA_REQ_IN_BATCH]; | |
49 | uint16_t num_xpaths; | |
50 | }; | |
51 | ||
52 | struct mgmt_be_txn_req { | |
53 | enum mgmt_be_txn_event event; | |
54 | union { | |
55 | struct mgmt_be_set_cfg_req set_cfg; | |
56 | struct mgmt_be_get_data_req get_data; | |
57 | } req; | |
58 | }; | |
59 | ||
60 | PREDECL_LIST(mgmt_be_batches); | |
61 | struct mgmt_be_batch_ctx { | |
62 | /* Batch-Id as assigned by MGMTD */ | |
63 | uint64_t batch_id; | |
64 | ||
65 | struct mgmt_be_txn_req txn_req; | |
66 | ||
67 | uint32_t flags; | |
68 | ||
69 | struct mgmt_be_batches_item list_linkage; | |
70 | }; | |
71 | #define MGMTD_BE_BATCH_FLAGS_CFG_PREPARED (1U << 0) | |
72 | #define MGMTD_BE_TXN_FLAGS_CFG_APPLIED (1U << 1) | |
73 | DECLARE_LIST(mgmt_be_batches, struct mgmt_be_batch_ctx, list_linkage); | |
74 | ||
7d65b7b7 CH |
75 | PREDECL_LIST(mgmt_be_txns); |
76 | struct mgmt_be_txn_ctx { | |
77 | /* Txn-Id as assigned by MGMTD */ | |
78 | uint64_t txn_id; | |
79 | uint32_t flags; | |
80 | ||
81 | struct mgmt_be_client_txn_ctx client_data; | |
7aecb863 | 82 | struct mgmt_be_client *client; |
7d65b7b7 CH |
83 | |
84 | /* List of batches belonging to this transaction */ | |
85 | struct mgmt_be_batches_head cfg_batches; | |
86 | struct mgmt_be_batches_head apply_cfgs; | |
87 | ||
88 | struct mgmt_be_txns_item list_linkage; | |
89 | ||
90 | struct nb_transaction *nb_txn; | |
91 | uint32_t nb_txn_id; | |
92 | }; | |
93 | #define MGMTD_BE_TXN_FLAGS_CFGPREP_FAILED (1U << 1) | |
94 | ||
95 | DECLARE_LIST(mgmt_be_txns, struct mgmt_be_txn_ctx, list_linkage); | |
96 | ||
97 | #define FOREACH_BE_TXN_BATCH_IN_LIST(txn, batch) \ | |
98 | frr_each_safe (mgmt_be_batches, &(txn)->cfg_batches, (batch)) | |
99 | ||
100 | #define FOREACH_BE_APPLY_BATCH_IN_LIST(txn, batch) \ | |
101 | frr_each_safe (mgmt_be_batches, &(txn)->apply_cfgs, (batch)) | |
102 | ||
7aecb863 | 103 | struct mgmt_be_client { |
070c5e7a | 104 | struct msg_client client; |
7d65b7b7 | 105 | |
7aecb863 CH |
106 | char *name; |
107 | ||
7d65b7b7 CH |
108 | struct nb_config *candidate_config; |
109 | struct nb_config *running_config; | |
110 | ||
7d65b7b7 CH |
111 | unsigned long num_edit_nb_cfg; |
112 | unsigned long avg_edit_nb_cfg_tm; | |
113 | unsigned long num_prep_nb_cfg; | |
114 | unsigned long avg_prep_nb_cfg_tm; | |
115 | unsigned long num_apply_nb_cfg; | |
116 | unsigned long avg_apply_nb_cfg_tm; | |
117 | ||
118 | struct mgmt_be_txns_head txn_head; | |
7aecb863 CH |
119 | |
120 | struct mgmt_be_client_cbs cbs; | |
121 | uintptr_t user_data; | |
7d65b7b7 CH |
122 | }; |
123 | ||
7d65b7b7 CH |
124 | #define FOREACH_BE_TXN_IN_LIST(client_ctx, txn) \ |
125 | frr_each_safe (mgmt_be_txns, &(client_ctx)->txn_head, (txn)) | |
126 | ||
cfa0facb | 127 | struct debug mgmt_dbg_be_client = {0, "Management backend client operations"}; |
7d65b7b7 | 128 | |
7d65b7b7 | 129 | const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = { |
7d65b7b7 CH |
130 | #ifdef HAVE_STATICD |
131 | [MGMTD_BE_CLIENT_ID_STATICD] = "staticd", | |
7d65b7b7 CH |
132 | #endif |
133 | [MGMTD_BE_CLIENT_ID_MAX] = "Unknown/Invalid", | |
134 | }; | |
135 | ||
7aecb863 | 136 | static int mgmt_be_client_send_msg(struct mgmt_be_client *client_ctx, |
070c5e7a | 137 | Mgmtd__BeMessage *be_msg) |
7d65b7b7 | 138 | { |
070c5e7a CH |
139 | return msg_conn_send_msg( |
140 | &client_ctx->client.conn, MGMT_MSG_VERSION_PROTOBUF, be_msg, | |
141 | mgmtd__be_message__get_packed_size(be_msg), | |
5f05ff58 | 142 | (size_t(*)(void *, void *))mgmtd__be_message__pack, false); |
7d65b7b7 CH |
143 | } |
144 | ||
145 | static struct mgmt_be_batch_ctx * | |
146 | mgmt_be_find_batch_by_id(struct mgmt_be_txn_ctx *txn, | |
147 | uint64_t batch_id) | |
148 | { | |
149 | struct mgmt_be_batch_ctx *batch = NULL; | |
150 | ||
151 | FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) { | |
152 | if (batch->batch_id == batch_id) | |
153 | return batch; | |
154 | } | |
155 | ||
156 | return NULL; | |
157 | } | |
158 | ||
159 | static struct mgmt_be_batch_ctx * | |
160 | mgmt_be_batch_create(struct mgmt_be_txn_ctx *txn, uint64_t batch_id) | |
161 | { | |
162 | struct mgmt_be_batch_ctx *batch = NULL; | |
163 | ||
164 | batch = mgmt_be_find_batch_by_id(txn, batch_id); | |
165 | if (!batch) { | |
166 | batch = XCALLOC(MTYPE_MGMTD_BE_BATCH, | |
167 | sizeof(struct mgmt_be_batch_ctx)); | |
168 | assert(batch); | |
169 | ||
170 | batch->batch_id = batch_id; | |
171 | mgmt_be_batches_add_tail(&txn->cfg_batches, batch); | |
172 | ||
218625aa CH |
173 | MGMTD_BE_CLIENT_DBG("Added new batch-id: %" PRIu64 |
174 | " to transaction", | |
175 | batch_id); | |
7d65b7b7 CH |
176 | } |
177 | ||
178 | return batch; | |
179 | } | |
180 | ||
181 | static void mgmt_be_batch_delete(struct mgmt_be_txn_ctx *txn, | |
182 | struct mgmt_be_batch_ctx **batch) | |
183 | { | |
184 | uint16_t indx; | |
185 | ||
186 | if (!batch) | |
187 | return; | |
188 | ||
189 | mgmt_be_batches_del(&txn->cfg_batches, *batch); | |
190 | if ((*batch)->txn_req.event == MGMTD_BE_TXN_PROC_SETCFG) { | |
191 | for (indx = 0; indx < MGMTD_MAX_CFG_CHANGES_IN_BATCH; indx++) { | |
192 | if ((*batch)->txn_req.req.set_cfg.cfg_changes[indx] | |
193 | .value) { | |
194 | free((char *)(*batch) | |
195 | ->txn_req.req.set_cfg | |
196 | .cfg_changes[indx] | |
197 | .value); | |
198 | } | |
199 | } | |
200 | } | |
201 | ||
202 | XFREE(MTYPE_MGMTD_BE_BATCH, *batch); | |
203 | *batch = NULL; | |
204 | } | |
205 | ||
206 | static void mgmt_be_cleanup_all_batches(struct mgmt_be_txn_ctx *txn) | |
207 | { | |
208 | struct mgmt_be_batch_ctx *batch = NULL; | |
209 | ||
210 | FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) { | |
211 | mgmt_be_batch_delete(txn, &batch); | |
212 | } | |
213 | ||
214 | FOREACH_BE_APPLY_BATCH_IN_LIST (txn, batch) { | |
215 | mgmt_be_batch_delete(txn, &batch); | |
216 | } | |
217 | } | |
218 | ||
219 | static struct mgmt_be_txn_ctx * | |
7aecb863 | 220 | mgmt_be_find_txn_by_id(struct mgmt_be_client *client_ctx, uint64_t txn_id) |
7d65b7b7 CH |
221 | { |
222 | struct mgmt_be_txn_ctx *txn = NULL; | |
223 | ||
224 | FOREACH_BE_TXN_IN_LIST (client_ctx, txn) { | |
225 | if (txn->txn_id == txn_id) | |
226 | return txn; | |
227 | } | |
228 | ||
229 | return NULL; | |
230 | } | |
231 | ||
232 | static struct mgmt_be_txn_ctx * | |
7aecb863 | 233 | mgmt_be_txn_create(struct mgmt_be_client *client_ctx, uint64_t txn_id) |
7d65b7b7 CH |
234 | { |
235 | struct mgmt_be_txn_ctx *txn = NULL; | |
236 | ||
237 | txn = mgmt_be_find_txn_by_id(client_ctx, txn_id); | |
238 | if (!txn) { | |
239 | txn = XCALLOC(MTYPE_MGMTD_BE_TXN, | |
240 | sizeof(struct mgmt_be_txn_ctx)); | |
241 | assert(txn); | |
242 | ||
243 | txn->txn_id = txn_id; | |
7aecb863 | 244 | txn->client = client_ctx; |
7d65b7b7 CH |
245 | mgmt_be_batches_init(&txn->cfg_batches); |
246 | mgmt_be_batches_init(&txn->apply_cfgs); | |
247 | mgmt_be_txns_add_tail(&client_ctx->txn_head, txn); | |
248 | ||
218625aa | 249 | MGMTD_BE_CLIENT_DBG("Added new txn-id: %" PRIu64, txn_id); |
7d65b7b7 CH |
250 | } |
251 | ||
252 | return txn; | |
253 | } | |
254 | ||
7aecb863 CH |
255 | static void mgmt_be_txn_delete(struct mgmt_be_client *client_ctx, |
256 | struct mgmt_be_txn_ctx **txn) | |
7d65b7b7 CH |
257 | { |
258 | char err_msg[] = "MGMT Transaction Delete"; | |
259 | ||
260 | if (!txn) | |
261 | return; | |
262 | ||
263 | /* | |
264 | * Remove the transaction from the list of transactions | |
265 | * so that future lookups with the same transaction id | |
266 | * does not return this one. | |
267 | */ | |
268 | mgmt_be_txns_del(&client_ctx->txn_head, *txn); | |
269 | ||
270 | /* | |
271 | * Time to delete the transaction which should also | |
272 | * take care of cleaning up all batches created via | |
273 | * CFGDATA_CREATE_REQs. But first notify the client | |
274 | * about the transaction delete. | |
275 | */ | |
7aecb863 CH |
276 | if (client_ctx->cbs.txn_notify) |
277 | (void)(*client_ctx->cbs.txn_notify)(client_ctx, | |
278 | client_ctx->user_data, | |
279 | &(*txn)->client_data, true); | |
7d65b7b7 CH |
280 | |
281 | mgmt_be_cleanup_all_batches(*txn); | |
282 | if ((*txn)->nb_txn) | |
283 | nb_candidate_commit_abort((*txn)->nb_txn, err_msg, | |
284 | sizeof(err_msg)); | |
285 | XFREE(MTYPE_MGMTD_BE_TXN, *txn); | |
286 | ||
287 | *txn = NULL; | |
288 | } | |
289 | ||
7aecb863 | 290 | static void mgmt_be_cleanup_all_txns(struct mgmt_be_client *client_ctx) |
7d65b7b7 CH |
291 | { |
292 | struct mgmt_be_txn_ctx *txn = NULL; | |
293 | ||
294 | FOREACH_BE_TXN_IN_LIST (client_ctx, txn) { | |
295 | mgmt_be_txn_delete(client_ctx, &txn); | |
296 | } | |
297 | } | |
298 | ||
7aecb863 CH |
299 | static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx, |
300 | uint64_t txn_id, bool create, bool success) | |
7d65b7b7 CH |
301 | { |
302 | Mgmtd__BeMessage be_msg; | |
303 | Mgmtd__BeTxnReply txn_reply; | |
304 | ||
305 | mgmtd__be_txn_reply__init(&txn_reply); | |
306 | txn_reply.create = create; | |
307 | txn_reply.txn_id = txn_id; | |
308 | txn_reply.success = success; | |
309 | ||
310 | mgmtd__be_message__init(&be_msg); | |
311 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY; | |
312 | be_msg.txn_reply = &txn_reply; | |
313 | ||
218625aa | 314 | MGMTD_BE_CLIENT_DBG("Sending TXN_REPLY txn-id %" PRIu64, txn_id); |
7d65b7b7 CH |
315 | |
316 | return mgmt_be_client_send_msg(client_ctx, &be_msg); | |
317 | } | |
318 | ||
7aecb863 CH |
319 | static int mgmt_be_process_txn_req(struct mgmt_be_client *client_ctx, |
320 | uint64_t txn_id, bool create) | |
7d65b7b7 CH |
321 | { |
322 | struct mgmt_be_txn_ctx *txn; | |
323 | ||
324 | txn = mgmt_be_find_txn_by_id(client_ctx, txn_id); | |
325 | if (create) { | |
326 | if (txn) { | |
327 | /* | |
328 | * Transaction with same txn-id already exists. | |
329 | * Should not happen under any circumstances. | |
330 | */ | |
331 | MGMTD_BE_CLIENT_ERR( | |
218625aa | 332 | "txn-id: %" PRIu64 " already exists", txn_id); |
7d65b7b7 CH |
333 | mgmt_be_send_txn_reply(client_ctx, txn_id, create, |
334 | false); | |
335 | } | |
336 | ||
218625aa | 337 | MGMTD_BE_CLIENT_DBG("Created new txn-id %" PRIu64, txn_id); |
7d65b7b7 CH |
338 | txn = mgmt_be_txn_create(client_ctx, txn_id); |
339 | ||
7aecb863 CH |
340 | if (client_ctx->cbs.txn_notify) |
341 | (void)(*client_ctx->cbs.txn_notify)( | |
342 | client_ctx, client_ctx->user_data, | |
7d65b7b7 CH |
343 | &txn->client_data, false); |
344 | } else { | |
345 | if (!txn) { | |
346 | /* | |
347 | * Transaction with same txn-id does not exists. | |
348 | * Return sucess anyways. | |
349 | */ | |
218625aa CH |
350 | MGMTD_BE_CLIENT_DBG("txn-id: %" PRIu64 |
351 | " for delete does NOT exists", | |
352 | txn_id); | |
7d65b7b7 | 353 | } else { |
218625aa | 354 | MGMTD_BE_CLIENT_DBG("Delete txn-id: %" PRIu64, txn_id); |
7d65b7b7 CH |
355 | mgmt_be_txn_delete(client_ctx, &txn); |
356 | } | |
357 | } | |
358 | ||
359 | mgmt_be_send_txn_reply(client_ctx, txn_id, create, true); | |
360 | ||
361 | return 0; | |
362 | } | |
363 | ||
7aecb863 CH |
364 | static int mgmt_be_send_cfgdata_create_reply(struct mgmt_be_client *client_ctx, |
365 | uint64_t txn_id, uint64_t batch_id, | |
366 | bool success, | |
367 | const char *error_if_any) | |
7d65b7b7 CH |
368 | { |
369 | Mgmtd__BeMessage be_msg; | |
370 | Mgmtd__BeCfgDataCreateReply cfgdata_reply; | |
371 | ||
372 | mgmtd__be_cfg_data_create_reply__init(&cfgdata_reply); | |
373 | cfgdata_reply.txn_id = (uint64_t)txn_id; | |
374 | cfgdata_reply.batch_id = (uint64_t)batch_id; | |
375 | cfgdata_reply.success = success; | |
376 | if (error_if_any) | |
377 | cfgdata_reply.error_if_any = (char *)error_if_any; | |
378 | ||
379 | mgmtd__be_message__init(&be_msg); | |
380 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY; | |
381 | be_msg.cfg_data_reply = &cfgdata_reply; | |
382 | ||
218625aa CH |
383 | MGMTD_BE_CLIENT_DBG("Sending CFGDATA_CREATE_REPLY txn-id: %" PRIu64 |
384 | " batch-id: %" PRIu64, | |
385 | txn_id, batch_id); | |
7d65b7b7 CH |
386 | |
387 | return mgmt_be_client_send_msg(client_ctx, &be_msg); | |
388 | } | |
389 | ||
390 | static void mgmt_be_txn_cfg_abort(struct mgmt_be_txn_ctx *txn) | |
391 | { | |
392 | char errmsg[BUFSIZ] = {0}; | |
393 | ||
7aecb863 | 394 | assert(txn && txn->client); |
7d65b7b7 CH |
395 | if (txn->nb_txn) { |
396 | MGMTD_BE_CLIENT_ERR( | |
218625aa CH |
397 | "Aborting configs after prep for txn-id: %" PRIu64, |
398 | txn->txn_id); | |
7d65b7b7 CH |
399 | nb_candidate_commit_abort(txn->nb_txn, errmsg, sizeof(errmsg)); |
400 | txn->nb_txn = 0; | |
401 | } | |
402 | ||
403 | /* | |
404 | * revert candidate back to running | |
405 | * | |
406 | * This is one txn ctx but the candidate_config is per client ctx, how | |
407 | * does that work? | |
408 | */ | |
409 | MGMTD_BE_CLIENT_DBG( | |
218625aa CH |
410 | "Reset candidate configurations after abort of txn-id: %" PRIu64, |
411 | txn->txn_id); | |
7aecb863 CH |
412 | nb_config_replace(txn->client->candidate_config, |
413 | txn->client->running_config, true); | |
7d65b7b7 CH |
414 | } |
415 | ||
416 | static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn) | |
417 | { | |
7aecb863 | 418 | struct mgmt_be_client *client_ctx; |
7d65b7b7 CH |
419 | struct mgmt_be_txn_req *txn_req = NULL; |
420 | struct nb_context nb_ctx = {0}; | |
421 | struct timeval edit_nb_cfg_start; | |
422 | struct timeval edit_nb_cfg_end; | |
423 | unsigned long edit_nb_cfg_tm; | |
424 | struct timeval prep_nb_cfg_start; | |
425 | struct timeval prep_nb_cfg_end; | |
426 | unsigned long prep_nb_cfg_tm; | |
427 | struct mgmt_be_batch_ctx *batch; | |
428 | bool error; | |
429 | char err_buf[BUFSIZ]; | |
430 | size_t num_processed; | |
7d65b7b7 CH |
431 | int err; |
432 | ||
7aecb863 CH |
433 | assert(txn && txn->client); |
434 | client_ctx = txn->client; | |
7d65b7b7 CH |
435 | |
436 | num_processed = 0; | |
437 | FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) { | |
438 | txn_req = &batch->txn_req; | |
439 | error = false; | |
440 | nb_ctx.client = NB_CLIENT_CLI; | |
7aecb863 | 441 | nb_ctx.user = (void *)client_ctx->user_data; |
7d65b7b7 CH |
442 | |
443 | if (!txn->nb_txn) { | |
444 | /* | |
445 | * This happens when the current backend client is only | |
446 | * interested in consuming the config items but is not | |
447 | * interested in validating it. | |
448 | */ | |
449 | error = false; | |
cfa0facb CH |
450 | |
451 | gettimeofday(&edit_nb_cfg_start, NULL); | |
7d65b7b7 CH |
452 | nb_candidate_edit_config_changes( |
453 | client_ctx->candidate_config, | |
454 | txn_req->req.set_cfg.cfg_changes, | |
455 | (size_t)txn_req->req.set_cfg.num_cfg_changes, | |
456 | NULL, NULL, 0, err_buf, sizeof(err_buf), | |
457 | &error); | |
458 | if (error) { | |
459 | err_buf[sizeof(err_buf) - 1] = 0; | |
460 | MGMTD_BE_CLIENT_ERR( | |
218625aa CH |
461 | "Failed to update configs for txn-id: %" PRIu64 |
462 | " batch-id: %" PRIu64 | |
463 | " to candidate, err: '%s'", | |
464 | txn->txn_id, batch->batch_id, err_buf); | |
7d65b7b7 CH |
465 | return -1; |
466 | } | |
cfa0facb CH |
467 | gettimeofday(&edit_nb_cfg_end, NULL); |
468 | edit_nb_cfg_tm = timeval_elapsed(edit_nb_cfg_end, | |
469 | edit_nb_cfg_start); | |
470 | client_ctx->avg_edit_nb_cfg_tm = | |
471 | ((client_ctx->avg_edit_nb_cfg_tm * | |
472 | client_ctx->num_edit_nb_cfg) + | |
473 | edit_nb_cfg_tm) / | |
474 | (client_ctx->num_edit_nb_cfg + 1); | |
7d65b7b7 CH |
475 | client_ctx->num_edit_nb_cfg++; |
476 | } | |
477 | ||
478 | num_processed++; | |
479 | } | |
480 | ||
481 | if (!num_processed) | |
482 | return 0; | |
483 | ||
484 | /* | |
485 | * Now prepare all the batches we have applied in one go. | |
486 | */ | |
487 | nb_ctx.client = NB_CLIENT_CLI; | |
7aecb863 | 488 | nb_ctx.user = (void *)client_ctx->user_data; |
cfa0facb CH |
489 | |
490 | gettimeofday(&prep_nb_cfg_start, NULL); | |
7d65b7b7 CH |
491 | err = nb_candidate_commit_prepare(nb_ctx, client_ctx->candidate_config, |
492 | "MGMTD Backend Txn", &txn->nb_txn, | |
493 | #ifdef MGMTD_LOCAL_VALIDATIONS_ENABLED | |
494 | true, true, | |
495 | #else | |
496 | false, true, | |
497 | #endif | |
498 | err_buf, sizeof(err_buf) - 1); | |
499 | if (err != NB_OK) { | |
500 | err_buf[sizeof(err_buf) - 1] = 0; | |
501 | if (err == NB_ERR_VALIDATION) | |
502 | MGMTD_BE_CLIENT_ERR( | |
218625aa CH |
503 | "Failed to validate configs txn-id: %" PRIu64 |
504 | " %zu batches, err: '%s'", | |
505 | txn->txn_id, num_processed, err_buf); | |
7d65b7b7 CH |
506 | else |
507 | MGMTD_BE_CLIENT_ERR( | |
218625aa CH |
508 | "Failed to prepare configs for txn-id: %" PRIu64 |
509 | " %zu batches, err: '%s'", | |
510 | txn->txn_id, num_processed, err_buf); | |
7d65b7b7 CH |
511 | error = true; |
512 | SET_FLAG(txn->flags, MGMTD_BE_TXN_FLAGS_CFGPREP_FAILED); | |
513 | } else | |
218625aa CH |
514 | MGMTD_BE_CLIENT_DBG("Prepared configs for txn-id: %" PRIu64 |
515 | " %zu batches", | |
516 | txn->txn_id, num_processed); | |
cfa0facb CH |
517 | |
518 | gettimeofday(&prep_nb_cfg_end, NULL); | |
519 | prep_nb_cfg_tm = timeval_elapsed(prep_nb_cfg_end, prep_nb_cfg_start); | |
520 | client_ctx->avg_prep_nb_cfg_tm = ((client_ctx->avg_prep_nb_cfg_tm * | |
521 | client_ctx->num_prep_nb_cfg) + | |
522 | prep_nb_cfg_tm) / | |
523 | (client_ctx->num_prep_nb_cfg + 1); | |
7d65b7b7 CH |
524 | client_ctx->num_prep_nb_cfg++; |
525 | ||
526 | FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) { | |
527 | mgmt_be_send_cfgdata_create_reply( | |
528 | client_ctx, txn->txn_id, batch->batch_id, | |
529 | error ? false : true, error ? err_buf : NULL); | |
530 | if (!error) { | |
531 | SET_FLAG(batch->flags, | |
532 | MGMTD_BE_BATCH_FLAGS_CFG_PREPARED); | |
533 | mgmt_be_batches_del(&txn->cfg_batches, batch); | |
534 | mgmt_be_batches_add_tail(&txn->apply_cfgs, batch); | |
535 | } | |
536 | } | |
537 | ||
cfa0facb CH |
538 | MGMTD_BE_CLIENT_DBG( |
539 | "Avg-nb-edit-duration %lu uSec, nb-prep-duration %lu (avg: %lu) uSec, batch size %u", | |
540 | client_ctx->avg_edit_nb_cfg_tm, prep_nb_cfg_tm, | |
541 | client_ctx->avg_prep_nb_cfg_tm, (uint32_t)num_processed); | |
7d65b7b7 CH |
542 | |
543 | if (error) | |
544 | mgmt_be_txn_cfg_abort(txn); | |
545 | ||
546 | return 0; | |
547 | } | |
548 | ||
549 | /* | |
550 | * Process all CFG_DATA_REQs received so far and prepare them all in one go. | |
551 | */ | |
7aecb863 CH |
552 | static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx, |
553 | struct mgmt_be_txn_ctx *txn, | |
554 | uint64_t batch_id, | |
555 | Mgmtd__YangCfgDataReq *cfg_req[], | |
556 | int num_req) | |
7d65b7b7 CH |
557 | { |
558 | struct mgmt_be_batch_ctx *batch = NULL; | |
559 | struct mgmt_be_txn_req *txn_req = NULL; | |
560 | int index; | |
561 | struct nb_cfg_change *cfg_chg; | |
562 | ||
563 | batch = mgmt_be_batch_create(txn, batch_id); | |
564 | if (!batch) { | |
565 | MGMTD_BE_CLIENT_ERR("Batch create failed!"); | |
566 | return -1; | |
567 | } | |
568 | ||
569 | txn_req = &batch->txn_req; | |
570 | txn_req->event = MGMTD_BE_TXN_PROC_SETCFG; | |
218625aa CH |
571 | MGMTD_BE_CLIENT_DBG("Created SETCFG request for batch-id: %" PRIu64 |
572 | " txn-id: %" PRIu64 " cfg-items:%d", | |
573 | batch_id, txn->txn_id, num_req); | |
7d65b7b7 CH |
574 | |
575 | txn_req->req.set_cfg.num_cfg_changes = num_req; | |
576 | for (index = 0; index < num_req; index++) { | |
577 | cfg_chg = &txn_req->req.set_cfg.cfg_changes[index]; | |
578 | ||
579 | if (cfg_req[index]->req_type | |
580 | == MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA) | |
581 | cfg_chg->operation = NB_OP_DESTROY; | |
582 | else | |
583 | cfg_chg->operation = NB_OP_CREATE; | |
584 | ||
585 | strlcpy(cfg_chg->xpath, cfg_req[index]->data->xpath, | |
586 | sizeof(cfg_chg->xpath)); | |
587 | cfg_chg->value = (cfg_req[index]->data->value | |
588 | && cfg_req[index] | |
589 | ->data->value | |
590 | ->encoded_str_val | |
591 | ? strdup(cfg_req[index] | |
592 | ->data->value | |
593 | ->encoded_str_val) | |
594 | : NULL); | |
595 | if (cfg_chg->value | |
596 | && !strncmp(cfg_chg->value, MGMTD_BE_CONTAINER_NODE_VAL, | |
597 | strlen(MGMTD_BE_CONTAINER_NODE_VAL))) { | |
598 | free((char *)cfg_chg->value); | |
599 | cfg_chg->value = NULL; | |
600 | } | |
601 | } | |
602 | ||
603 | return 0; | |
604 | } | |
605 | ||
7aecb863 CH |
606 | static int mgmt_be_process_cfgdata_req(struct mgmt_be_client *client_ctx, |
607 | uint64_t txn_id, uint64_t batch_id, | |
608 | Mgmtd__YangCfgDataReq *cfg_req[], | |
609 | int num_req, bool end_of_data) | |
7d65b7b7 CH |
610 | { |
611 | struct mgmt_be_txn_ctx *txn; | |
612 | ||
613 | txn = mgmt_be_find_txn_by_id(client_ctx, txn_id); | |
614 | if (!txn) { | |
218625aa CH |
615 | MGMTD_BE_CLIENT_ERR("Invalid txn-id: %" PRIu64 |
616 | " from MGMTD server", | |
617 | txn_id); | |
7d65b7b7 CH |
618 | mgmt_be_send_cfgdata_create_reply( |
619 | client_ctx, txn_id, batch_id, false, | |
620 | "Transaction context not created yet"); | |
621 | } else { | |
622 | mgmt_be_update_setcfg_in_batch(client_ctx, txn, batch_id, | |
623 | cfg_req, num_req); | |
624 | } | |
625 | ||
626 | if (txn && end_of_data) { | |
627 | MGMTD_BE_CLIENT_DBG("Triggering CFG_PREPARE_REQ processing"); | |
628 | mgmt_be_txn_cfg_prepare(txn); | |
629 | } | |
630 | ||
631 | return 0; | |
632 | } | |
633 | ||
7aecb863 CH |
634 | static int mgmt_be_send_apply_reply(struct mgmt_be_client *client_ctx, |
635 | uint64_t txn_id, uint64_t batch_ids[], | |
636 | size_t num_batch_ids, bool success, | |
637 | const char *error_if_any) | |
7d65b7b7 CH |
638 | { |
639 | Mgmtd__BeMessage be_msg; | |
640 | Mgmtd__BeCfgDataApplyReply apply_reply; | |
641 | ||
642 | mgmtd__be_cfg_data_apply_reply__init(&apply_reply); | |
643 | apply_reply.success = success; | |
644 | apply_reply.txn_id = txn_id; | |
645 | apply_reply.batch_ids = (uint64_t *)batch_ids; | |
646 | apply_reply.n_batch_ids = num_batch_ids; | |
647 | ||
648 | if (error_if_any) | |
649 | apply_reply.error_if_any = (char *)error_if_any; | |
650 | ||
651 | mgmtd__be_message__init(&be_msg); | |
652 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY; | |
653 | be_msg.cfg_apply_reply = &apply_reply; | |
654 | ||
655 | MGMTD_BE_CLIENT_DBG( | |
218625aa CH |
656 | "Sending CFG_APPLY_REPLY txn-id %" PRIu64 |
657 | " %zu batch ids %" PRIu64 " - %" PRIu64, | |
658 | txn_id, num_batch_ids, | |
659 | success && num_batch_ids ? batch_ids[0] : 0, | |
660 | success && num_batch_ids ? batch_ids[num_batch_ids - 1] : 0); | |
7d65b7b7 CH |
661 | |
662 | return mgmt_be_client_send_msg(client_ctx, &be_msg); | |
663 | } | |
664 | ||
665 | static int mgmt_be_txn_proc_cfgapply(struct mgmt_be_txn_ctx *txn) | |
666 | { | |
7aecb863 | 667 | struct mgmt_be_client *client_ctx; |
7d65b7b7 CH |
668 | struct timeval apply_nb_cfg_start; |
669 | struct timeval apply_nb_cfg_end; | |
670 | unsigned long apply_nb_cfg_tm; | |
671 | struct mgmt_be_batch_ctx *batch; | |
672 | char err_buf[BUFSIZ]; | |
673 | size_t num_processed; | |
674 | static uint64_t batch_ids[MGMTD_BE_MAX_BATCH_IDS_IN_REQ]; | |
7d65b7b7 | 675 | |
7aecb863 CH |
676 | assert(txn && txn->client); |
677 | client_ctx = txn->client; | |
7d65b7b7 CH |
678 | |
679 | assert(txn->nb_txn); | |
680 | num_processed = 0; | |
681 | ||
682 | /* | |
683 | * Now apply all the batches we have applied in one go. | |
684 | */ | |
cfa0facb | 685 | gettimeofday(&apply_nb_cfg_start, NULL); |
7d65b7b7 CH |
686 | (void)nb_candidate_commit_apply(txn->nb_txn, true, &txn->nb_txn_id, |
687 | err_buf, sizeof(err_buf) - 1); | |
cfa0facb CH |
688 | gettimeofday(&apply_nb_cfg_end, NULL); |
689 | ||
690 | apply_nb_cfg_tm = timeval_elapsed(apply_nb_cfg_end, apply_nb_cfg_start); | |
691 | client_ctx->avg_apply_nb_cfg_tm = ((client_ctx->avg_apply_nb_cfg_tm * | |
692 | client_ctx->num_apply_nb_cfg) + | |
693 | apply_nb_cfg_tm) / | |
694 | (client_ctx->num_apply_nb_cfg + 1); | |
7d65b7b7 CH |
695 | client_ctx->num_apply_nb_cfg++; |
696 | txn->nb_txn = NULL; | |
697 | ||
698 | /* | |
699 | * Send back CFG_APPLY_REPLY for all batches applied. | |
700 | */ | |
701 | FOREACH_BE_APPLY_BATCH_IN_LIST (txn, batch) { | |
702 | /* | |
703 | * No need to delete the batch yet. Will be deleted during | |
704 | * transaction cleanup on receiving TXN_DELETE_REQ. | |
705 | */ | |
706 | SET_FLAG(batch->flags, MGMTD_BE_TXN_FLAGS_CFG_APPLIED); | |
707 | mgmt_be_batches_del(&txn->apply_cfgs, batch); | |
708 | mgmt_be_batches_add_tail(&txn->cfg_batches, batch); | |
709 | ||
710 | batch_ids[num_processed] = batch->batch_id; | |
711 | num_processed++; | |
712 | if (num_processed == MGMTD_BE_MAX_BATCH_IDS_IN_REQ) { | |
713 | mgmt_be_send_apply_reply(client_ctx, txn->txn_id, | |
714 | batch_ids, num_processed, | |
715 | true, NULL); | |
716 | num_processed = 0; | |
717 | } | |
718 | } | |
719 | ||
720 | mgmt_be_send_apply_reply(client_ctx, txn->txn_id, batch_ids, | |
721 | num_processed, true, NULL); | |
722 | ||
cfa0facb CH |
723 | MGMTD_BE_CLIENT_DBG("Nb-apply-duration %lu (avg: %lu) uSec", |
724 | apply_nb_cfg_tm, client_ctx->avg_apply_nb_cfg_tm); | |
7d65b7b7 CH |
725 | |
726 | return 0; | |
727 | } | |
728 | ||
7aecb863 CH |
729 | static int mgmt_be_process_cfg_apply(struct mgmt_be_client *client_ctx, |
730 | uint64_t txn_id) | |
7d65b7b7 CH |
731 | { |
732 | struct mgmt_be_txn_ctx *txn; | |
733 | ||
734 | txn = mgmt_be_find_txn_by_id(client_ctx, txn_id); | |
735 | if (!txn) { | |
736 | mgmt_be_send_apply_reply(client_ctx, txn_id, NULL, 0, false, | |
737 | "Transaction not created yet!"); | |
738 | return -1; | |
739 | } | |
740 | ||
741 | MGMTD_BE_CLIENT_DBG("Trigger CFG_APPLY_REQ processing"); | |
742 | mgmt_be_txn_proc_cfgapply(txn); | |
743 | ||
744 | return 0; | |
745 | } | |
746 | ||
7aecb863 CH |
747 | static int mgmt_be_client_handle_msg(struct mgmt_be_client *client_ctx, |
748 | Mgmtd__BeMessage *be_msg) | |
7d65b7b7 | 749 | { |
0b645fd2 CH |
750 | /* |
751 | * protobuf-c adds a max size enum with an internal, and changing by | |
752 | * version, name; cast to an int to avoid unhandled enum warnings | |
753 | */ | |
754 | switch ((int)be_msg->message_case) { | |
7d65b7b7 | 755 | case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY: |
218625aa CH |
756 | MGMTD_BE_CLIENT_DBG("Got SUBSCR_REPLY success %u", |
757 | be_msg->subscr_reply->success); | |
7d65b7b7 CH |
758 | break; |
759 | case MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ: | |
218625aa CH |
760 | MGMTD_BE_CLIENT_DBG("Got TXN_REQ %s txn-id: %" PRIu64, |
761 | be_msg->txn_req->create ? "Create" | |
762 | : "Delete", | |
763 | be_msg->txn_req->txn_id); | |
7d65b7b7 CH |
764 | mgmt_be_process_txn_req(client_ctx, |
765 | be_msg->txn_req->txn_id, | |
766 | be_msg->txn_req->create); | |
767 | break; | |
768 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ: | |
218625aa CH |
769 | MGMTD_BE_CLIENT_DBG("Got CFG_DATA_REQ txn-id: %" PRIu64 |
770 | " batch-id: %" PRIu64 " end-of-data %u", | |
771 | be_msg->cfg_data_req->txn_id, | |
772 | be_msg->cfg_data_req->batch_id, | |
773 | be_msg->cfg_data_req->end_of_data); | |
7d65b7b7 CH |
774 | mgmt_be_process_cfgdata_req( |
775 | client_ctx, be_msg->cfg_data_req->txn_id, | |
776 | be_msg->cfg_data_req->batch_id, | |
777 | be_msg->cfg_data_req->data_req, | |
778 | be_msg->cfg_data_req->n_data_req, | |
779 | be_msg->cfg_data_req->end_of_data); | |
780 | break; | |
781 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ: | |
218625aa CH |
782 | MGMTD_BE_CLIENT_DBG("Got CFG_APPLY_REQ txn-id: %" PRIu64, |
783 | be_msg->cfg_data_req->txn_id); | |
7d65b7b7 CH |
784 | mgmt_be_process_cfg_apply( |
785 | client_ctx, (uint64_t)be_msg->cfg_apply_req->txn_id); | |
786 | break; | |
787 | case MGMTD__BE_MESSAGE__MESSAGE_GET_REQ: | |
788 | case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ: | |
789 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_CMD_REQ: | |
790 | case MGMTD__BE_MESSAGE__MESSAGE_SHOW_CMD_REQ: | |
218625aa CH |
791 | MGMTD_BE_CLIENT_ERR("Got unhandled message type %u", |
792 | be_msg->message_case); | |
7d65b7b7 CH |
793 | /* |
794 | * TODO: Add handling code in future. | |
795 | */ | |
796 | break; | |
797 | /* | |
798 | * NOTE: The following messages are always sent from Backend | |
799 | * clients to MGMTd only and/or need not be handled here. | |
800 | */ | |
801 | case MGMTD__BE_MESSAGE__MESSAGE_GET_REPLY: | |
802 | case MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY: | |
803 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY: | |
804 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY: | |
805 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_CMD_REPLY: | |
806 | case MGMTD__BE_MESSAGE__MESSAGE_SHOW_CMD_REPLY: | |
807 | case MGMTD__BE_MESSAGE__MESSAGE_NOTIFY_DATA: | |
808 | case MGMTD__BE_MESSAGE__MESSAGE__NOT_SET: | |
7d65b7b7 CH |
809 | default: |
810 | /* | |
811 | * A 'default' case is being added contrary to the | |
812 | * FRR code guidelines to take care of build | |
813 | * failures on certain build systems (courtesy of | |
814 | * the proto-c package). | |
815 | */ | |
816 | break; | |
817 | } | |
818 | ||
819 | return 0; | |
820 | } | |
821 | ||
070c5e7a CH |
822 | static void mgmt_be_client_process_msg(uint8_t version, uint8_t *data, |
823 | size_t len, struct msg_conn *conn) | |
7d65b7b7 | 824 | { |
7aecb863 | 825 | struct mgmt_be_client *client_ctx; |
070c5e7a | 826 | struct msg_client *client; |
7d65b7b7 | 827 | Mgmtd__BeMessage *be_msg; |
7d65b7b7 | 828 | |
070c5e7a | 829 | client = container_of(conn, struct msg_client, conn); |
7aecb863 | 830 | client_ctx = container_of(client, struct mgmt_be_client, client); |
070c5e7a | 831 | |
f82370b4 CH |
832 | be_msg = mgmtd__be_message__unpack(NULL, len, data); |
833 | if (!be_msg) { | |
834 | MGMTD_BE_CLIENT_DBG("Failed to decode %zu bytes from server", | |
835 | len); | |
836 | return; | |
7d65b7b7 | 837 | } |
f82370b4 CH |
838 | MGMTD_BE_CLIENT_DBG( |
839 | "Decoded %zu bytes of message(msg: %u/%u) from server", len, | |
840 | be_msg->message_case, be_msg->message_case); | |
841 | (void)mgmt_be_client_handle_msg(client_ctx, be_msg); | |
842 | mgmtd__be_message__free_unpacked(be_msg, NULL); | |
7d65b7b7 CH |
843 | } |
844 | ||
7aecb863 CH |
845 | int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx, |
846 | bool subscr_xpaths, int num_xpaths, | |
847 | char **reg_xpaths) | |
7d65b7b7 CH |
848 | { |
849 | Mgmtd__BeMessage be_msg; | |
850 | Mgmtd__BeSubscribeReq subscr_req; | |
851 | ||
852 | mgmtd__be_subscribe_req__init(&subscr_req); | |
7aecb863 CH |
853 | subscr_req.client_name = client_ctx->name; |
854 | subscr_req.n_xpath_reg = num_xpaths; | |
855 | if (num_xpaths) | |
7d65b7b7 CH |
856 | subscr_req.xpath_reg = reg_xpaths; |
857 | else | |
858 | subscr_req.xpath_reg = NULL; | |
859 | subscr_req.subscribe_xpaths = subscr_xpaths; | |
860 | ||
861 | mgmtd__be_message__init(&be_msg); | |
862 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ; | |
863 | be_msg.subscr_req = &subscr_req; | |
864 | ||
218625aa CH |
865 | MGMTD_FE_CLIENT_DBG( |
866 | "Sending SUBSCR_REQ name: %s subscr_xpaths: %u num_xpaths: %zu", | |
867 | subscr_req.client_name, subscr_req.subscribe_xpaths, | |
868 | subscr_req.n_xpath_reg); | |
869 | ||
7d65b7b7 CH |
870 | return mgmt_be_client_send_msg(client_ctx, &be_msg); |
871 | } | |
872 | ||
7aecb863 CH |
873 | static int _notify_conenct_disconnect(struct msg_client *msg_client, |
874 | bool connected) | |
7d65b7b7 | 875 | { |
7aecb863 CH |
876 | struct mgmt_be_client *client = |
877 | container_of(msg_client, struct mgmt_be_client, client); | |
070c5e7a CH |
878 | int ret; |
879 | ||
880 | if (connected) { | |
7aecb863 CH |
881 | assert(msg_client->conn.fd != -1); |
882 | ret = mgmt_be_send_subscr_req(client, false, 0, NULL); | |
070c5e7a CH |
883 | if (ret) |
884 | return ret; | |
7d65b7b7 CH |
885 | } |
886 | ||
070c5e7a | 887 | /* Notify BE client through registered callback (if any) */ |
7aecb863 CH |
888 | if (client->cbs.client_connect_notify) |
889 | (void)(*client->cbs.client_connect_notify)( | |
890 | client, client->user_data, connected); | |
070c5e7a | 891 | return 0; |
7d65b7b7 CH |
892 | } |
893 | ||
070c5e7a | 894 | static int mgmt_be_client_notify_conenct(struct msg_client *client) |
7d65b7b7 | 895 | { |
070c5e7a | 896 | return _notify_conenct_disconnect(client, true); |
7d65b7b7 CH |
897 | } |
898 | ||
070c5e7a | 899 | static int mgmt_be_client_notify_disconenct(struct msg_conn *conn) |
7d65b7b7 | 900 | { |
070c5e7a | 901 | struct msg_client *client = container_of(conn, struct msg_client, conn); |
7d65b7b7 | 902 | |
070c5e7a | 903 | return _notify_conenct_disconnect(client, false); |
7d65b7b7 CH |
904 | } |
905 | ||
7aecb863 CH |
906 | /* |
907 | * Debug Flags | |
908 | */ | |
909 | ||
cfa0facb CH |
910 | DEFPY(debug_mgmt_client_be, debug_mgmt_client_be_cmd, |
911 | "[no] debug mgmt client backend", | |
912 | NO_STR DEBUG_STR MGMTD_STR | |
913 | "client\n" | |
914 | "backend\n") | |
915 | { | |
916 | uint32_t mode = DEBUG_NODE2MODE(vty->node); | |
917 | ||
918 | DEBUG_MODE_SET(&mgmt_dbg_be_client, mode, !no); | |
919 | ||
920 | return CMD_SUCCESS; | |
921 | } | |
922 | ||
923 | static void mgmt_debug_client_be_set_all(uint32_t flags, bool set) | |
924 | { | |
925 | DEBUG_FLAGS_SET(&mgmt_dbg_be_client, flags, set); | |
926 | } | |
927 | ||
928 | static int mgmt_debug_be_client_config_write(struct vty *vty) | |
929 | { | |
930 | if (DEBUG_MODE_CHECK(&mgmt_dbg_be_client, DEBUG_MODE_CONF)) | |
931 | vty_out(vty, "debug mgmt client frontend\n"); | |
932 | ||
933 | return 1; | |
934 | } | |
935 | ||
936 | void mgmt_debug_be_client_show_debug(struct vty *vty) | |
937 | { | |
938 | if (MGMTD_DBG_BE_CLIENT_CHECK()) | |
939 | vty_out(vty, "debug mgmt client backend\n"); | |
940 | } | |
941 | ||
942 | static struct debug_callbacks mgmt_dbg_be_client_cbs = { | |
943 | .debug_set_all = mgmt_debug_client_be_set_all}; | |
944 | ||
945 | static struct cmd_node mgmt_dbg_node = { | |
946 | .name = "mgmt backend client", | |
947 | .node = DEBUG_NODE, | |
948 | .prompt = "", | |
949 | .config_write = mgmt_debug_be_client_config_write, | |
950 | }; | |
7d65b7b7 | 951 | |
7aecb863 CH |
952 | struct mgmt_be_client *mgmt_be_client_create(const char *client_name, |
953 | struct mgmt_be_client_cbs *cbs, | |
954 | uintptr_t user_data, | |
955 | struct event_loop *event_loop) | |
7d65b7b7 | 956 | { |
7aecb863 CH |
957 | struct mgmt_be_client *client = |
958 | XCALLOC(MTYPE_MGMTD_BE_CLIENT, sizeof(*client)); | |
7d65b7b7 | 959 | |
070c5e7a CH |
960 | /* Only call after frr_init() */ |
961 | assert(running_config); | |
7d65b7b7 | 962 | |
7aecb863 CH |
963 | client->name = XSTRDUP(MTYPE_MGMTD_BE_CLIENT_NAME, client_name); |
964 | client->running_config = running_config; | |
965 | client->candidate_config = nb_config_new(NULL); | |
966 | if (cbs) | |
967 | client->cbs = *cbs; | |
968 | mgmt_be_txns_init(&client->txn_head); | |
969 | msg_client_init(&client->client, event_loop, MGMTD_BE_SERVER_PATH, | |
970 | mgmt_be_client_notify_conenct, | |
070c5e7a CH |
971 | mgmt_be_client_notify_disconenct, |
972 | mgmt_be_client_process_msg, MGMTD_BE_MAX_NUM_MSG_PROC, | |
5f05ff58 | 973 | MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MSG_MAX_LEN, false, |
070c5e7a | 974 | "BE-client", MGMTD_DBG_BE_CLIENT_CHECK()); |
7d65b7b7 | 975 | |
7aecb863 | 976 | MGMTD_BE_CLIENT_DBG("Initialized client '%s'", client_name); |
7d65b7b7 | 977 | |
7aecb863 | 978 | return client; |
7d65b7b7 CH |
979 | } |
980 | ||
cfa0facb CH |
981 | |
982 | void mgmt_be_client_lib_vty_init(void) | |
983 | { | |
984 | debug_init(&mgmt_dbg_be_client_cbs); | |
985 | install_node(&mgmt_dbg_node); | |
986 | install_element(ENABLE_NODE, &debug_mgmt_client_be_cmd); | |
987 | install_element(CONFIG_NODE, &debug_mgmt_client_be_cmd); | |
988 | } | |
989 | ||
7aecb863 | 990 | void mgmt_be_client_destroy(struct mgmt_be_client *client) |
7d65b7b7 | 991 | { |
7d65b7b7 | 992 | MGMTD_BE_CLIENT_DBG("Destroying MGMTD Backend Client '%s'", |
7aecb863 | 993 | client->name); |
7d65b7b7 | 994 | |
7aecb863 CH |
995 | msg_client_cleanup(&client->client); |
996 | mgmt_be_cleanup_all_txns(client); | |
997 | mgmt_be_txns_fini(&client->txn_head); | |
998 | nb_config_free(client->candidate_config); | |
070c5e7a | 999 | |
7aecb863 CH |
1000 | XFREE(MTYPE_MGMTD_BE_CLIENT_NAME, client->name); |
1001 | XFREE(MTYPE_MGMTD_BE_CLIENT, client); | |
7d65b7b7 | 1002 | } |