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