]> git.proxmox.com Git - mirror_frr.git/blame - lib/mgmt_fe_client.c
lib: msg: refactor common connection code from mgmtd
[mirror_frr.git] / lib / mgmt_fe_client.c
CommitLineData
ef43a632
CH
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * MGMTD Frontend Client Library api interfaces
4 * Copyright (C) 2021 Vmware, Inc.
5 * Pushpasis Sarkar <spushpasis@vmware.com>
6 */
7
8#include <zebra.h>
070c5e7a 9#include "compiler.h"
cfa0facb 10#include "debug.h"
ef43a632
CH
11#include "memory.h"
12#include "libfrr.h"
13#include "mgmt_fe_client.h"
f82370b4 14#include "mgmt_msg.h"
ef43a632
CH
15#include "mgmt_pb.h"
16#include "network.h"
17#include "stream.h"
18#include "sockopt.h"
19
cfa0facb
CH
20#include "lib/mgmt_fe_client_clippy.c"
21
22#define MGMTD_FE_CLIENT_DBG(fmt, ...) \
23 DEBUGD(&mgmt_dbg_fe_client, "%s:" fmt, __func__, ##__VA_ARGS__)
24#define MGMTD_FE_CLIENT_ERR(fmt, ...) \
ef43a632 25 zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
cfa0facb
CH
26#define MGMTD_DBG_FE_CLIENT_CHECK() \
27 DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_ALL)
ef43a632
CH
28
29struct mgmt_fe_client_ctx;
30
31PREDECL_LIST(mgmt_sessions);
32
33struct mgmt_fe_client_session {
34 uint64_t client_id;
35 uint64_t session_id;
36 struct mgmt_fe_client_ctx *client_ctx;
37 uintptr_t user_ctx;
38
39 struct mgmt_sessions_item list_linkage;
40};
41
42DECLARE_LIST(mgmt_sessions, struct mgmt_fe_client_session, list_linkage);
43
44DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_SESSION, "MGMTD Frontend session");
45
46struct mgmt_fe_client_ctx {
070c5e7a 47 struct msg_client client;
ef43a632 48 struct mgmt_fe_client_params client_params;
ef43a632
CH
49 struct mgmt_sessions_head client_sessions;
50};
51
ef43a632
CH
52#define FOREACH_SESSION_IN_LIST(client_ctx, session) \
53 frr_each_safe (mgmt_sessions, &(client_ctx)->client_sessions, (session))
54
cfa0facb 55struct debug mgmt_dbg_fe_client = {0, "Management frontend client operations"};
ef43a632 56
f82370b4 57static struct mgmt_fe_client_ctx mgmt_fe_client_ctx = {
070c5e7a 58 .client = {.conn = {.fd = -1}}};
ef43a632
CH
59
60static struct mgmt_fe_client_session *
61mgmt_fe_find_session_by_client_id(struct mgmt_fe_client_ctx *client_ctx,
62 uint64_t client_id)
63{
64 struct mgmt_fe_client_session *session;
65
66 FOREACH_SESSION_IN_LIST (client_ctx, session) {
67 if (session->client_id == client_id) {
68 MGMTD_FE_CLIENT_DBG(
69 "Found session %p for client-id %llu.", session,
70 (unsigned long long)client_id);
71 return session;
72 }
73 }
74
75 return NULL;
76}
77
78static struct mgmt_fe_client_session *
79mgmt_fe_find_session_by_session_id(struct mgmt_fe_client_ctx *client_ctx,
80 uint64_t session_id)
81{
82 struct mgmt_fe_client_session *session;
83
84 FOREACH_SESSION_IN_LIST (client_ctx, session) {
85 if (session->session_id == session_id) {
86 MGMTD_FE_CLIENT_DBG(
83b78f43 87 "Found session %p for session-id %llu.",
88 session, (unsigned long long)session_id);
ef43a632
CH
89 return session;
90 }
91 }
92
93 return NULL;
94}
95
f82370b4
CH
96static int mgmt_fe_client_send_msg(struct mgmt_fe_client_ctx *client_ctx,
97 Mgmtd__FeMessage *fe_msg)
ef43a632 98{
070c5e7a
CH
99 return msg_conn_send_msg(
100 &client_ctx->client.conn, MGMT_MSG_VERSION_PROTOBUF, fe_msg,
f82370b4 101 mgmtd__fe_message__get_packed_size(fe_msg),
070c5e7a 102 (size_t(*)(void *, void *))mgmtd__fe_message__pack);
ef43a632
CH
103}
104
ef43a632
CH
105static int
106mgmt_fe_send_register_req(struct mgmt_fe_client_ctx *client_ctx)
107{
108 Mgmtd__FeMessage fe_msg;
109 Mgmtd__FeRegisterReq rgstr_req;
110
111 mgmtd__fe_register_req__init(&rgstr_req);
112 rgstr_req.client_name = client_ctx->client_params.name;
113
114 mgmtd__fe_message__init(&fe_msg);
115 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ;
116 fe_msg.register_req = &rgstr_req;
117
118 MGMTD_FE_CLIENT_DBG(
119 "Sending REGISTER_REQ message to MGMTD Frontend server");
120
121 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
122}
123
124static int
125mgmt_fe_send_session_req(struct mgmt_fe_client_ctx *client_ctx,
126 struct mgmt_fe_client_session *session,
127 bool create)
128{
129 Mgmtd__FeMessage fe_msg;
130 Mgmtd__FeSessionReq sess_req;
131
132 mgmtd__fe_session_req__init(&sess_req);
133 sess_req.create = create;
134 if (create) {
135 sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID;
136 sess_req.client_conn_id = session->client_id;
137 } else {
138 sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_SESSION_ID;
139 sess_req.session_id = session->session_id;
140 }
141
142 mgmtd__fe_message__init(&fe_msg);
143 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ;
144 fe_msg.session_req = &sess_req;
145
146 MGMTD_FE_CLIENT_DBG(
147 "Sending SESSION_REQ message for %s session %llu to MGMTD Frontend server",
148 create ? "creating" : "destroying",
149 (unsigned long long)session->client_id);
150
151 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
152}
153
154static int
155mgmt_fe_send_lockds_req(struct mgmt_fe_client_ctx *client_ctx,
156 struct mgmt_fe_client_session *session, bool lock,
157 uint64_t req_id, Mgmtd__DatastoreId ds_id)
158{
159 (void)req_id;
160 Mgmtd__FeMessage fe_msg;
161 Mgmtd__FeLockDsReq lockds_req;
162
163 mgmtd__fe_lock_ds_req__init(&lockds_req);
164 lockds_req.session_id = session->session_id;
165 lockds_req.req_id = req_id;
166 lockds_req.ds_id = ds_id;
167 lockds_req.lock = lock;
168
169 mgmtd__fe_message__init(&fe_msg);
170 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ;
171 fe_msg.lockds_req = &lockds_req;
172
173 MGMTD_FE_CLIENT_DBG(
174 "Sending %sLOCK_REQ message for Ds:%d session %llu to MGMTD Frontend server",
83b78f43 175 lock ? "" : "UN", ds_id,
176 (unsigned long long)session->client_id);
ef43a632
CH
177
178 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
179}
180
181static int
182mgmt_fe_send_setcfg_req(struct mgmt_fe_client_ctx *client_ctx,
183 struct mgmt_fe_client_session *session,
184 uint64_t req_id, Mgmtd__DatastoreId ds_id,
185 Mgmtd__YangCfgDataReq **data_req, int num_data_reqs,
186 bool implicit_commit, Mgmtd__DatastoreId dst_ds_id)
187{
188 (void)req_id;
189 Mgmtd__FeMessage fe_msg;
190 Mgmtd__FeSetConfigReq setcfg_req;
191
192 mgmtd__fe_set_config_req__init(&setcfg_req);
193 setcfg_req.session_id = session->session_id;
194 setcfg_req.ds_id = ds_id;
195 setcfg_req.req_id = req_id;
196 setcfg_req.data = data_req;
197 setcfg_req.n_data = (size_t)num_data_reqs;
198 setcfg_req.implicit_commit = implicit_commit;
199 setcfg_req.commit_ds_id = dst_ds_id;
200
201 mgmtd__fe_message__init(&fe_msg);
202 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ;
203 fe_msg.setcfg_req = &setcfg_req;
204
205 MGMTD_FE_CLIENT_DBG(
206 "Sending SET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
207 ds_id, (unsigned long long)session->client_id, num_data_reqs);
208
209 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
210}
211
83b78f43 212static int mgmt_fe_send_commitcfg_req(struct mgmt_fe_client_ctx *client_ctx,
213 struct mgmt_fe_client_session *session,
214 uint64_t req_id,
215 Mgmtd__DatastoreId src_ds_id,
216 Mgmtd__DatastoreId dest_ds_id,
217 bool validate_only, bool abort)
ef43a632
CH
218{
219 (void)req_id;
220 Mgmtd__FeMessage fe_msg;
221 Mgmtd__FeCommitConfigReq commitcfg_req;
222
223 mgmtd__fe_commit_config_req__init(&commitcfg_req);
224 commitcfg_req.session_id = session->session_id;
225 commitcfg_req.src_ds_id = src_ds_id;
226 commitcfg_req.dst_ds_id = dest_ds_id;
227 commitcfg_req.req_id = req_id;
228 commitcfg_req.validate_only = validate_only;
229 commitcfg_req.abort = abort;
230
231 mgmtd__fe_message__init(&fe_msg);
232 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ;
233 fe_msg.commcfg_req = &commitcfg_req;
234
235 MGMTD_FE_CLIENT_DBG(
236 "Sending COMMIT_CONFIG_REQ message for Src-Ds:%d, Dst-Ds:%d session %llu to MGMTD Frontend server",
237 src_ds_id, dest_ds_id, (unsigned long long)session->client_id);
238
239 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
240}
241
242static int
243mgmt_fe_send_getcfg_req(struct mgmt_fe_client_ctx *client_ctx,
244 struct mgmt_fe_client_session *session,
245 uint64_t req_id, Mgmtd__DatastoreId ds_id,
246 Mgmtd__YangGetDataReq * data_req[],
247 int num_data_reqs)
248{
249 (void)req_id;
250 Mgmtd__FeMessage fe_msg;
251 Mgmtd__FeGetConfigReq getcfg_req;
252
253 mgmtd__fe_get_config_req__init(&getcfg_req);
254 getcfg_req.session_id = session->session_id;
255 getcfg_req.ds_id = ds_id;
256 getcfg_req.req_id = req_id;
257 getcfg_req.data = data_req;
258 getcfg_req.n_data = (size_t)num_data_reqs;
259
260 mgmtd__fe_message__init(&fe_msg);
261 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REQ;
262 fe_msg.getcfg_req = &getcfg_req;
263
264 MGMTD_FE_CLIENT_DBG(
265 "Sending GET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
266 ds_id, (unsigned long long)session->client_id, num_data_reqs);
267
268 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
269}
270
271static int
272mgmt_fe_send_getdata_req(struct mgmt_fe_client_ctx *client_ctx,
273 struct mgmt_fe_client_session *session,
274 uint64_t req_id, Mgmtd__DatastoreId ds_id,
275 Mgmtd__YangGetDataReq * data_req[],
276 int num_data_reqs)
277{
278 (void)req_id;
279 Mgmtd__FeMessage fe_msg;
280 Mgmtd__FeGetDataReq getdata_req;
281
282 mgmtd__fe_get_data_req__init(&getdata_req);
283 getdata_req.session_id = session->session_id;
284 getdata_req.ds_id = ds_id;
285 getdata_req.req_id = req_id;
286 getdata_req.data = data_req;
287 getdata_req.n_data = (size_t)num_data_reqs;
288
289 mgmtd__fe_message__init(&fe_msg);
290 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REQ;
291 fe_msg.getdata_req = &getdata_req;
292
293 MGMTD_FE_CLIENT_DBG(
294 "Sending GET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
295 ds_id, (unsigned long long)session->client_id, num_data_reqs);
296
297 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
298}
299
300static int mgmt_fe_send_regnotify_req(
301 struct mgmt_fe_client_ctx *client_ctx,
302 struct mgmt_fe_client_session *session, uint64_t req_id,
303 Mgmtd__DatastoreId ds_id, bool register_req,
304 Mgmtd__YangDataXPath * data_req[], int num_data_reqs)
305{
306 (void)req_id;
307 Mgmtd__FeMessage fe_msg;
308 Mgmtd__FeRegisterNotifyReq regntfy_req;
309
310 mgmtd__fe_register_notify_req__init(&regntfy_req);
311 regntfy_req.session_id = session->session_id;
312 regntfy_req.ds_id = ds_id;
313 regntfy_req.register_req = register_req;
314 regntfy_req.data_xpath = data_req;
315 regntfy_req.n_data_xpath = (size_t)num_data_reqs;
316
317 mgmtd__fe_message__init(&fe_msg);
318 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ;
319 fe_msg.regnotify_req = &regntfy_req;
320
321 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
322}
323
324static int
325mgmt_fe_client_handle_msg(struct mgmt_fe_client_ctx *client_ctx,
326 Mgmtd__FeMessage *fe_msg)
327{
328 struct mgmt_fe_client_session *session = NULL;
329
0b645fd2
CH
330 /*
331 * protobuf-c adds a max size enum with an internal, and changing by
332 * version, name; cast to an int to avoid unhandled enum warnings
333 */
334 switch ((int)fe_msg->message_case) {
ef43a632
CH
335 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY:
336 if (fe_msg->session_reply->create
337 && fe_msg->session_reply->has_client_conn_id) {
338 MGMTD_FE_CLIENT_DBG(
339 "Got Session Create Reply Msg for client-id %llu with session-id: %llu.",
340 (unsigned long long)
341 fe_msg->session_reply->client_conn_id,
342 (unsigned long long)
343 fe_msg->session_reply->session_id);
344
345 session = mgmt_fe_find_session_by_client_id(
346 client_ctx,
347 fe_msg->session_reply->client_conn_id);
348
349 if (session && fe_msg->session_reply->success) {
350 MGMTD_FE_CLIENT_DBG(
351 "Session Create for client-id %llu successful.",
83b78f43 352 (unsigned long long)
353 fe_msg->session_reply
354 ->client_conn_id);
ef43a632
CH
355 session->session_id =
356 fe_msg->session_reply->session_id;
357 } else {
358 MGMTD_FE_CLIENT_ERR(
359 "Session Create for client-id %llu failed.",
83b78f43 360 (unsigned long long)
361 fe_msg->session_reply
362 ->client_conn_id);
ef43a632
CH
363 }
364 } else if (!fe_msg->session_reply->create) {
365 MGMTD_FE_CLIENT_DBG(
366 "Got Session Destroy Reply Msg for session-id %llu",
367 (unsigned long long)
368 fe_msg->session_reply->session_id);
369
370 session = mgmt_fe_find_session_by_session_id(
371 client_ctx, fe_msg->session_req->session_id);
372 }
373
374 if (session && session->client_ctx
375 && session->client_ctx->client_params
376 .client_session_notify)
377 (*session->client_ctx->client_params
378 .client_session_notify)(
379 (uintptr_t)client_ctx,
380 client_ctx->client_params.user_data,
381 session->client_id,
382 fe_msg->session_reply->create,
383 fe_msg->session_reply->success,
384 (uintptr_t)session, session->user_ctx);
385 break;
386 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY:
387 MGMTD_FE_CLIENT_DBG(
388 "Got LockDs Reply Msg for session-id %llu",
389 (unsigned long long)
390 fe_msg->lockds_reply->session_id);
391 session = mgmt_fe_find_session_by_session_id(
392 client_ctx, fe_msg->lockds_reply->session_id);
393
394 if (session && session->client_ctx
395 && session->client_ctx->client_params
396 .lock_ds_notify)
397 (*session->client_ctx->client_params
398 .lock_ds_notify)(
399 (uintptr_t)client_ctx,
400 client_ctx->client_params.user_data,
401 session->client_id, (uintptr_t)session,
402 session->user_ctx,
403 fe_msg->lockds_reply->req_id,
404 fe_msg->lockds_reply->lock,
405 fe_msg->lockds_reply->success,
406 fe_msg->lockds_reply->ds_id,
407 fe_msg->lockds_reply->error_if_any);
408 break;
409 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY:
410 MGMTD_FE_CLIENT_DBG(
411 "Got Set Config Reply Msg for session-id %llu",
412 (unsigned long long)
413 fe_msg->setcfg_reply->session_id);
414
415 session = mgmt_fe_find_session_by_session_id(
416 client_ctx, fe_msg->setcfg_reply->session_id);
417
418 if (session && session->client_ctx
419 && session->client_ctx->client_params
420 .set_config_notify)
421 (*session->client_ctx->client_params
422 .set_config_notify)(
423 (uintptr_t)client_ctx,
424 client_ctx->client_params.user_data,
425 session->client_id, (uintptr_t)session,
426 session->user_ctx,
427 fe_msg->setcfg_reply->req_id,
428 fe_msg->setcfg_reply->success,
429 fe_msg->setcfg_reply->ds_id,
430 fe_msg->setcfg_reply->error_if_any);
431 break;
432 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY:
433 MGMTD_FE_CLIENT_DBG(
434 "Got Commit Config Reply Msg for session-id %llu",
435 (unsigned long long)
436 fe_msg->commcfg_reply->session_id);
437
438 session = mgmt_fe_find_session_by_session_id(
439 client_ctx, fe_msg->commcfg_reply->session_id);
440
441 if (session && session->client_ctx
442 && session->client_ctx->client_params
443 .commit_config_notify)
444 (*session->client_ctx->client_params
445 .commit_config_notify)(
446 (uintptr_t)client_ctx,
447 client_ctx->client_params.user_data,
448 session->client_id, (uintptr_t)session,
449 session->user_ctx,
450 fe_msg->commcfg_reply->req_id,
451 fe_msg->commcfg_reply->success,
452 fe_msg->commcfg_reply->src_ds_id,
453 fe_msg->commcfg_reply->dst_ds_id,
454 fe_msg->commcfg_reply->validate_only,
455 fe_msg->commcfg_reply->error_if_any);
456 break;
457 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REPLY:
458 MGMTD_FE_CLIENT_DBG(
459 "Got Get Config Reply Msg for session-id %llu",
460 (unsigned long long)
461 fe_msg->getcfg_reply->session_id);
462
463 session = mgmt_fe_find_session_by_session_id(
464 client_ctx, fe_msg->getcfg_reply->session_id);
465
466 if (session && session->client_ctx
467 && session->client_ctx->client_params
468 .get_data_notify)
469 (*session->client_ctx->client_params
470 .get_data_notify)(
471 (uintptr_t)client_ctx,
472 client_ctx->client_params.user_data,
473 session->client_id, (uintptr_t)session,
474 session->user_ctx,
475 fe_msg->getcfg_reply->req_id,
476 fe_msg->getcfg_reply->success,
477 fe_msg->getcfg_reply->ds_id,
478 fe_msg->getcfg_reply->data
479 ? fe_msg->getcfg_reply->data->data
480 : NULL,
481 fe_msg->getcfg_reply->data
482 ? fe_msg->getcfg_reply->data->n_data
483 : 0,
484 fe_msg->getcfg_reply->data
485 ? fe_msg->getcfg_reply->data
486 ->next_indx
487 : 0,
488 fe_msg->getcfg_reply->error_if_any);
489 break;
490 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REPLY:
491 MGMTD_FE_CLIENT_DBG(
492 "Got Get Data Reply Msg for session-id %llu",
493 (unsigned long long)
494 fe_msg->getdata_reply->session_id);
495
496 session = mgmt_fe_find_session_by_session_id(
497 client_ctx, fe_msg->getdata_reply->session_id);
498
499 if (session && session->client_ctx
500 && session->client_ctx->client_params
501 .get_data_notify)
502 (*session->client_ctx->client_params
503 .get_data_notify)(
504 (uintptr_t)client_ctx,
505 client_ctx->client_params.user_data,
506 session->client_id, (uintptr_t)session,
507 session->user_ctx,
508 fe_msg->getdata_reply->req_id,
509 fe_msg->getdata_reply->success,
510 fe_msg->getdata_reply->ds_id,
511 fe_msg->getdata_reply->data
512 ? fe_msg->getdata_reply->data->data
513 : NULL,
514 fe_msg->getdata_reply->data
515 ? fe_msg->getdata_reply->data
516 ->n_data
517 : 0,
518 fe_msg->getdata_reply->data
519 ? fe_msg->getdata_reply->data
520 ->next_indx
521 : 0,
522 fe_msg->getdata_reply->error_if_any);
523 break;
524 case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
525 case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ:
526 /*
527 * TODO: Add handling code in future.
528 */
529 break;
530 /*
531 * NOTE: The following messages are always sent from Frontend
532 * clients to MGMTd only and/or need not be handled here.
533 */
534 case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ:
535 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ:
536 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ:
537 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ:
538 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ:
539 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REQ:
540 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REQ:
541 case MGMTD__FE_MESSAGE__MESSAGE__NOT_SET:
ef43a632
CH
542 default:
543 /*
544 * A 'default' case is being added contrary to the
545 * FRR code guidelines to take care of build
546 * failures on certain build systems (courtesy of
547 * the proto-c package).
548 */
549 break;
550 }
551
552 return 0;
553}
554
070c5e7a
CH
555static void mgmt_fe_client_process_msg(uint8_t version, uint8_t *data,
556 size_t len, struct msg_conn *conn)
ef43a632 557{
070c5e7a
CH
558 struct mgmt_fe_client_ctx *client_ctx;
559 struct msg_client *client;
ef43a632 560 Mgmtd__FeMessage *fe_msg;
ef43a632 561
070c5e7a
CH
562 client = container_of(conn, struct msg_client, conn);
563 client_ctx = container_of(client, struct mgmt_fe_client_ctx, client);
564
f82370b4
CH
565 fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
566 if (!fe_msg) {
567 MGMTD_FE_CLIENT_DBG("Failed to decode %zu bytes from server.",
568 len);
569 return;
ef43a632 570 }
f82370b4
CH
571 MGMTD_FE_CLIENT_DBG(
572 "Decoded %zu bytes of message(msg: %u/%u) from server", len,
573 fe_msg->message_case, fe_msg->message_case);
574 (void)mgmt_fe_client_handle_msg(client_ctx, fe_msg);
575 mgmtd__fe_message__free_unpacked(fe_msg, NULL);
ef43a632
CH
576}
577
070c5e7a 578static int _notify_connect_disconnect(struct msg_client *client, bool connected)
ef43a632 579{
070c5e7a
CH
580 struct mgmt_fe_client_ctx *client_ctx =
581 container_of(client, struct mgmt_fe_client_ctx, client);
582 int ret;
ef43a632 583
f82370b4 584 /* Send REGISTER_REQ message */
070c5e7a
CH
585 if (connected) {
586 if ((ret = mgmt_fe_send_register_req(client_ctx)) != 0)
587 return ret;
ef43a632
CH
588 }
589
070c5e7a 590 /* Notify FE client through registered callback (if any). */
ef43a632
CH
591 if (client_ctx->client_params.client_connect_notify)
592 (void)(*client_ctx->client_params.client_connect_notify)(
593 (uintptr_t)client_ctx,
070c5e7a
CH
594 client_ctx->client_params.user_data, connected);
595 return 0;
ef43a632
CH
596}
597
070c5e7a 598static int mgmt_fe_client_notify_connect(struct msg_client *client)
ef43a632 599{
070c5e7a 600 return _notify_connect_disconnect(client, true);
ef43a632
CH
601}
602
070c5e7a 603static int mgmt_fe_client_notify_disconnect(struct msg_conn *conn)
ef43a632 604{
070c5e7a 605 struct msg_client *client = container_of(conn, struct msg_client, conn);
ef43a632 606
070c5e7a 607 return _notify_connect_disconnect(client, false);
ef43a632
CH
608}
609
ef43a632 610
cfa0facb
CH
611DEFPY(debug_mgmt_client_fe, debug_mgmt_client_fe_cmd,
612 "[no] debug mgmt client frontend",
613 NO_STR DEBUG_STR MGMTD_STR
614 "client\n"
615 "frontend\n")
616{
617 uint32_t mode = DEBUG_NODE2MODE(vty->node);
618
619 DEBUG_MODE_SET(&mgmt_dbg_fe_client, mode, !no);
620
621 return CMD_SUCCESS;
622}
623
624static void mgmt_debug_client_fe_set_all(uint32_t flags, bool set)
625{
626 DEBUG_FLAGS_SET(&mgmt_dbg_fe_client, flags, set);
627}
628
629static int mgmt_debug_fe_client_config_write(struct vty *vty)
630{
631 if (DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_CONF))
632 vty_out(vty, "debug mgmt client frontend\n");
633
634 return CMD_SUCCESS;
635}
636
637void mgmt_debug_fe_client_show_debug(struct vty *vty)
638{
639 if (MGMTD_DBG_FE_CLIENT_CHECK())
640 vty_out(vty, "debug mgmt client frontend\n");
641}
642
643static struct debug_callbacks mgmt_dbg_fe_client_cbs = {
644 .debug_set_all = mgmt_debug_client_fe_set_all};
645
646static struct cmd_node mgmt_dbg_node = {
647 .name = "mgmt client frontend",
648 .node = DEBUG_NODE,
649 .prompt = "",
650 .config_write = mgmt_debug_fe_client_config_write,
651};
652
ef43a632
CH
653/*
654 * Initialize library and try connecting with MGMTD.
655 */
656uintptr_t mgmt_fe_client_lib_init(struct mgmt_fe_client_params *params,
cd9d0537 657 struct event_loop *master_thread)
ef43a632 658{
070c5e7a
CH
659 /* Don't call twice */
660 assert(!mgmt_fe_client_ctx.client.conn.loop);
ef43a632 661
070c5e7a 662 mgmt_fe_client_ctx.client_params = *params;
ef43a632
CH
663
664 mgmt_sessions_init(&mgmt_fe_client_ctx.client_sessions);
665
070c5e7a
CH
666 msg_client_init(&mgmt_fe_client_ctx.client, master_thread,
667 MGMTD_FE_SERVER_PATH, mgmt_fe_client_notify_connect,
668 mgmt_fe_client_notify_disconnect,
669 mgmt_fe_client_process_msg, MGMTD_FE_MAX_NUM_MSG_PROC,
670 MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN,
671 "FE-client", MGMTD_DBG_FE_CLIENT_CHECK());
ef43a632
CH
672
673 MGMTD_FE_CLIENT_DBG("Initialized client '%s'", params->name);
674
675 return (uintptr_t)&mgmt_fe_client_ctx;
676}
677
cfa0facb
CH
678void mgmt_fe_client_lib_vty_init(void)
679{
680 debug_init(&mgmt_dbg_fe_client_cbs);
681 install_node(&mgmt_dbg_node);
682 install_element(ENABLE_NODE, &debug_mgmt_client_fe_cmd);
683 install_element(CONFIG_NODE, &debug_mgmt_client_fe_cmd);
684}
685
ef43a632
CH
686/*
687 * Create a new Session for a Frontend Client connection.
688 */
689enum mgmt_result mgmt_fe_create_client_session(uintptr_t lib_hndl,
690 uint64_t client_id,
691 uintptr_t user_ctx)
692{
693 struct mgmt_fe_client_ctx *client_ctx;
694 struct mgmt_fe_client_session *session;
695
696 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
697 if (!client_ctx)
698 return MGMTD_INVALID_PARAM;
699
700 session = XCALLOC(MTYPE_MGMTD_FE_SESSION,
701 sizeof(struct mgmt_fe_client_session));
702 assert(session);
703 session->user_ctx = user_ctx;
704 session->client_id = client_id;
705 session->client_ctx = client_ctx;
706 session->session_id = 0;
707
708 if (mgmt_fe_send_session_req(client_ctx, session, true) != 0) {
709 XFREE(MTYPE_MGMTD_FE_SESSION, session);
710 return MGMTD_INTERNAL_ERROR;
711 }
712 mgmt_sessions_add_tail(&client_ctx->client_sessions, session);
713
714 return MGMTD_SUCCESS;
715}
716
717/*
718 * Delete an existing Session for a Frontend Client connection.
719 */
720enum mgmt_result mgmt_fe_destroy_client_session(uintptr_t lib_hndl,
721 uint64_t client_id)
722{
723 struct mgmt_fe_client_ctx *client_ctx;
724 struct mgmt_fe_client_session *session;
725
726 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
727 if (!client_ctx)
728 return MGMTD_INVALID_PARAM;
729
730 session = mgmt_fe_find_session_by_client_id(client_ctx, client_id);
731 if (!session || session->client_ctx != client_ctx)
732 return MGMTD_INVALID_PARAM;
733
734 if (session->session_id &&
735 mgmt_fe_send_session_req(client_ctx, session, false) != 0)
736 MGMTD_FE_CLIENT_ERR(
737 "Failed to send session destroy request for the session-id %lu",
738 (unsigned long)session->session_id);
739
740 mgmt_sessions_del(&client_ctx->client_sessions, session);
741 XFREE(MTYPE_MGMTD_FE_SESSION, session);
742
743 return MGMTD_SUCCESS;
744}
745
746static void mgmt_fe_destroy_client_sessions(uintptr_t lib_hndl)
747{
748 struct mgmt_fe_client_ctx *client_ctx;
749 struct mgmt_fe_client_session *session;
750
751 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
752 if (!client_ctx)
753 return;
754
755 FOREACH_SESSION_IN_LIST (client_ctx, session)
756 mgmt_fe_destroy_client_session(lib_hndl, session->client_id);
757}
758
759/*
760 * Send UN/LOCK_DS_REQ to MGMTD for a specific Datastore DS.
761 */
762enum mgmt_result mgmt_fe_lock_ds(uintptr_t lib_hndl, uintptr_t session_id,
763 uint64_t req_id, Mgmtd__DatastoreId ds_id,
764 bool lock_ds)
765{
766 struct mgmt_fe_client_ctx *client_ctx;
767 struct mgmt_fe_client_session *session;
768
769 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
770 if (!client_ctx)
771 return MGMTD_INVALID_PARAM;
772
773 session = (struct mgmt_fe_client_session *)session_id;
774 if (!session || session->client_ctx != client_ctx)
775 return MGMTD_INVALID_PARAM;
776
777 if (mgmt_fe_send_lockds_req(client_ctx, session, lock_ds, req_id,
778 ds_id)
779 != 0)
780 return MGMTD_INTERNAL_ERROR;
781
782 return MGMTD_SUCCESS;
783}
784
785/*
786 * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
787 */
788enum mgmt_result
789mgmt_fe_set_config_data(uintptr_t lib_hndl, uintptr_t session_id,
790 uint64_t req_id, Mgmtd__DatastoreId ds_id,
791 Mgmtd__YangCfgDataReq **config_req, int num_reqs,
792 bool implicit_commit, Mgmtd__DatastoreId dst_ds_id)
793{
794 struct mgmt_fe_client_ctx *client_ctx;
795 struct mgmt_fe_client_session *session;
796
797 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
798 if (!client_ctx)
799 return MGMTD_INVALID_PARAM;
800
801 session = (struct mgmt_fe_client_session *)session_id;
802 if (!session || session->client_ctx != client_ctx)
803 return MGMTD_INVALID_PARAM;
804
805 if (mgmt_fe_send_setcfg_req(client_ctx, session, req_id, ds_id,
806 config_req, num_reqs, implicit_commit,
807 dst_ds_id)
808 != 0)
809 return MGMTD_INTERNAL_ERROR;
810
811 return MGMTD_SUCCESS;
812}
813
814/*
815 * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
816 */
817enum mgmt_result mgmt_fe_commit_config_data(uintptr_t lib_hndl,
818 uintptr_t session_id,
819 uint64_t req_id,
820 Mgmtd__DatastoreId src_ds_id,
821 Mgmtd__DatastoreId dst_ds_id,
822 bool validate_only, bool abort)
823{
824 struct mgmt_fe_client_ctx *client_ctx;
825 struct mgmt_fe_client_session *session;
826
827 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
828 if (!client_ctx)
829 return MGMTD_INVALID_PARAM;
830
831 session = (struct mgmt_fe_client_session *)session_id;
832 if (!session || session->client_ctx != client_ctx)
833 return MGMTD_INVALID_PARAM;
834
835 if (mgmt_fe_send_commitcfg_req(client_ctx, session, req_id, src_ds_id,
836 dst_ds_id, validate_only, abort)
837 != 0)
838 return MGMTD_INTERNAL_ERROR;
839
840 return MGMTD_SUCCESS;
841}
842
843/*
844 * Send GET_CONFIG_REQ to MGMTD for one or more config data item(s).
845 */
846enum mgmt_result
847mgmt_fe_get_config_data(uintptr_t lib_hndl, uintptr_t session_id,
848 uint64_t req_id, Mgmtd__DatastoreId ds_id,
849 Mgmtd__YangGetDataReq * data_req[], int num_reqs)
850{
851 struct mgmt_fe_client_ctx *client_ctx;
852 struct mgmt_fe_client_session *session;
853
854 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
855 if (!client_ctx)
856 return MGMTD_INVALID_PARAM;
857
858 session = (struct mgmt_fe_client_session *)session_id;
859 if (!session || session->client_ctx != client_ctx)
860 return MGMTD_INVALID_PARAM;
861
862 if (mgmt_fe_send_getcfg_req(client_ctx, session, req_id, ds_id,
863 data_req, num_reqs)
864 != 0)
865 return MGMTD_INTERNAL_ERROR;
866
867 return MGMTD_SUCCESS;
868}
869
870/*
871 * Send GET_DATA_REQ to MGMTD for one or more config data item(s).
872 */
873enum mgmt_result mgmt_fe_get_data(uintptr_t lib_hndl, uintptr_t session_id,
874 uint64_t req_id, Mgmtd__DatastoreId ds_id,
875 Mgmtd__YangGetDataReq * data_req[],
876 int num_reqs)
877{
878 struct mgmt_fe_client_ctx *client_ctx;
879 struct mgmt_fe_client_session *session;
880
881 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
882 if (!client_ctx)
883 return MGMTD_INVALID_PARAM;
884
885 session = (struct mgmt_fe_client_session *)session_id;
886 if (!session || session->client_ctx != client_ctx)
887 return MGMTD_INVALID_PARAM;
888
889 if (mgmt_fe_send_getdata_req(client_ctx, session, req_id, ds_id,
890 data_req, num_reqs)
891 != 0)
892 return MGMTD_INTERNAL_ERROR;
893
894 return MGMTD_SUCCESS;
895}
896
897/*
898 * Send NOTIFY_REGISTER_REQ to MGMTD daemon.
899 */
900enum mgmt_result
901mgmt_fe_register_yang_notify(uintptr_t lib_hndl, uintptr_t session_id,
902 uint64_t req_id, Mgmtd__DatastoreId ds_id,
903 bool register_req,
904 Mgmtd__YangDataXPath * data_req[],
905 int num_reqs)
906{
907 struct mgmt_fe_client_ctx *client_ctx;
908 struct mgmt_fe_client_session *session;
909
910 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
911 if (!client_ctx)
912 return MGMTD_INVALID_PARAM;
913
914 session = (struct mgmt_fe_client_session *)session_id;
915 if (!session || session->client_ctx != client_ctx)
916 return MGMTD_INVALID_PARAM;
917
918 if (mgmt_fe_send_regnotify_req(client_ctx, session, req_id, ds_id,
919 register_req, data_req, num_reqs)
920 != 0)
921 return MGMTD_INTERNAL_ERROR;
922
923 return MGMTD_SUCCESS;
924}
925
926/*
927 * Destroy library and cleanup everything.
928 */
070c5e7a 929void mgmt_fe_client_lib_destroy(void)
ef43a632 930{
070c5e7a 931 struct mgmt_fe_client_ctx *client_ctx = &mgmt_fe_client_ctx;
ef43a632
CH
932
933 MGMTD_FE_CLIENT_DBG("Destroying MGMTD Frontend Client '%s'",
934 client_ctx->client_params.name);
935
070c5e7a
CH
936 mgmt_fe_destroy_client_sessions((uintptr_t)client_ctx);
937 msg_client_cleanup(&client_ctx->client);
938 memset(client_ctx, 0, sizeof(*client_ctx));
ef43a632 939}