]> git.proxmox.com Git - mirror_frr.git/blob - lib/mgmt_fe_client.c
Merge pull request #13242 from LabNConsulting/chopps/no_rip_in_lib
[mirror_frr.git] / lib / mgmt_fe_client.c
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>
9 #include "memory.h"
10 #include "libfrr.h"
11 #include "mgmt_fe_client.h"
12 #include "mgmt_msg.h"
13 #include "mgmt_pb.h"
14 #include "network.h"
15 #include "stream.h"
16 #include "sockopt.h"
17
18 #ifdef REDIRECT_DEBUG_TO_STDERR
19 #define MGMTD_FE_CLIENT_DBG(fmt, ...) \
20 fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
21 #define MGMTD_FE_CLIENT_ERR(fmt, ...) \
22 fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
23 #else /* REDIRECT_DEBUG_TO_STDERR */
24 #define MGMTD_FE_CLIENT_DBG(fmt, ...) \
25 do { \
26 if (mgmt_debug_fe_client) \
27 zlog_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
28 } while (0)
29 #define MGMTD_FE_CLIENT_ERR(fmt, ...) \
30 zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
31 #endif /* REDIRECT_DEBUG_TO_STDERR */
32
33 struct mgmt_fe_client_ctx;
34
35 PREDECL_LIST(mgmt_sessions);
36
37 struct mgmt_fe_client_session {
38 uint64_t client_id;
39 uint64_t session_id;
40 struct mgmt_fe_client_ctx *client_ctx;
41 uintptr_t user_ctx;
42
43 struct mgmt_sessions_item list_linkage;
44 };
45
46 DECLARE_LIST(mgmt_sessions, struct mgmt_fe_client_session, list_linkage);
47
48 DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_SESSION, "MGMTD Frontend session");
49
50 struct mgmt_fe_client_ctx {
51 int conn_fd;
52 struct event_loop *tm;
53 struct event *conn_retry_tmr;
54 struct event *conn_read_ev;
55 struct event *conn_write_ev;
56 struct event *conn_writes_on;
57 struct event *msg_proc_ev;
58 uint32_t flags;
59
60 struct mgmt_msg_state mstate;
61
62 struct mgmt_fe_client_params client_params;
63
64 struct mgmt_sessions_head client_sessions;
65 };
66
67 #define MGMTD_FE_CLIENT_FLAGS_WRITES_OFF (1U << 0)
68
69 #define FOREACH_SESSION_IN_LIST(client_ctx, session) \
70 frr_each_safe (mgmt_sessions, &(client_ctx)->client_sessions, (session))
71
72 static bool mgmt_debug_fe_client;
73
74 static struct mgmt_fe_client_ctx mgmt_fe_client_ctx = {
75 .conn_fd = -1,
76 };
77
78 /* Forward declarations */
79 static void
80 mgmt_fe_client_register_event(struct mgmt_fe_client_ctx *client_ctx,
81 enum mgmt_fe_event event);
82 static void mgmt_fe_client_schedule_conn_retry(
83 struct mgmt_fe_client_ctx *client_ctx, unsigned long intvl_secs);
84
85 static struct mgmt_fe_client_session *
86 mgmt_fe_find_session_by_client_id(struct mgmt_fe_client_ctx *client_ctx,
87 uint64_t client_id)
88 {
89 struct mgmt_fe_client_session *session;
90
91 FOREACH_SESSION_IN_LIST (client_ctx, session) {
92 if (session->client_id == client_id) {
93 MGMTD_FE_CLIENT_DBG(
94 "Found session %p for client-id %llu.", session,
95 (unsigned long long)client_id);
96 return session;
97 }
98 }
99
100 return NULL;
101 }
102
103 static struct mgmt_fe_client_session *
104 mgmt_fe_find_session_by_session_id(struct mgmt_fe_client_ctx *client_ctx,
105 uint64_t session_id)
106 {
107 struct mgmt_fe_client_session *session;
108
109 FOREACH_SESSION_IN_LIST (client_ctx, session) {
110 if (session->session_id == session_id) {
111 MGMTD_FE_CLIENT_DBG(
112 "Found session %p for session-id %llu.",
113 session, (unsigned long long)session_id);
114 return session;
115 }
116 }
117
118 return NULL;
119 }
120
121 static void
122 mgmt_fe_server_disconnect(struct mgmt_fe_client_ctx *client_ctx,
123 bool reconnect)
124 {
125 if (client_ctx->conn_fd != -1) {
126 close(client_ctx->conn_fd);
127 client_ctx->conn_fd = -1;
128 }
129
130 if (reconnect)
131 mgmt_fe_client_schedule_conn_retry(
132 client_ctx,
133 client_ctx->client_params.conn_retry_intvl_sec);
134 }
135
136 static inline void
137 mgmt_fe_client_sched_msg_write(struct mgmt_fe_client_ctx *client_ctx)
138 {
139 if (!CHECK_FLAG(client_ctx->flags, MGMTD_FE_CLIENT_FLAGS_WRITES_OFF))
140 mgmt_fe_client_register_event(client_ctx,
141 MGMTD_FE_CONN_WRITE);
142 }
143
144 static inline void
145 mgmt_fe_client_writes_on(struct mgmt_fe_client_ctx *client_ctx)
146 {
147 MGMTD_FE_CLIENT_DBG("Resume writing msgs");
148 UNSET_FLAG(client_ctx->flags, MGMTD_FE_CLIENT_FLAGS_WRITES_OFF);
149 mgmt_fe_client_sched_msg_write(client_ctx);
150 }
151
152 static inline void
153 mgmt_fe_client_writes_off(struct mgmt_fe_client_ctx *client_ctx)
154 {
155 SET_FLAG(client_ctx->flags, MGMTD_FE_CLIENT_FLAGS_WRITES_OFF);
156 MGMTD_FE_CLIENT_DBG("Paused writing msgs");
157 }
158
159 static int mgmt_fe_client_send_msg(struct mgmt_fe_client_ctx *client_ctx,
160 Mgmtd__FeMessage *fe_msg)
161 {
162 /* users current expect this to fail here */
163 if (client_ctx->conn_fd == -1) {
164 MGMTD_FE_CLIENT_DBG("can't send message on closed connection");
165 return -1;
166 }
167
168 int rv = mgmt_msg_send_msg(
169 &client_ctx->mstate, fe_msg,
170 mgmtd__fe_message__get_packed_size(fe_msg),
171 (size_t(*)(void *, void *))mgmtd__fe_message__pack,
172 mgmt_debug_fe_client);
173 mgmt_fe_client_sched_msg_write(client_ctx);
174 return rv;
175 }
176
177 static void mgmt_fe_client_write(struct event *thread)
178 {
179 struct mgmt_fe_client_ctx *client_ctx;
180 enum mgmt_msg_wsched rv;
181
182 client_ctx = (struct mgmt_fe_client_ctx *)EVENT_ARG(thread);
183 rv = mgmt_msg_write(&client_ctx->mstate, client_ctx->conn_fd,
184 mgmt_debug_fe_client);
185 if (rv == MSW_SCHED_STREAM)
186 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_CONN_WRITE);
187 else if (rv == MSW_DISCONNECT)
188 mgmt_fe_server_disconnect(client_ctx, true);
189 else if (rv == MSW_SCHED_WRITES_OFF) {
190 mgmt_fe_client_writes_off(client_ctx);
191 mgmt_fe_client_register_event(client_ctx,
192 MGMTD_FE_CONN_WRITES_ON);
193 } else
194 assert(rv == MSW_SCHED_NONE);
195 }
196
197 static void mgmt_fe_client_resume_writes(struct event *thread)
198 {
199 struct mgmt_fe_client_ctx *client_ctx;
200
201 client_ctx = (struct mgmt_fe_client_ctx *)EVENT_ARG(thread);
202 assert(client_ctx && client_ctx->conn_fd != -1);
203
204 mgmt_fe_client_writes_on(client_ctx);
205 }
206
207 static int
208 mgmt_fe_send_register_req(struct mgmt_fe_client_ctx *client_ctx)
209 {
210 Mgmtd__FeMessage fe_msg;
211 Mgmtd__FeRegisterReq rgstr_req;
212
213 mgmtd__fe_register_req__init(&rgstr_req);
214 rgstr_req.client_name = client_ctx->client_params.name;
215
216 mgmtd__fe_message__init(&fe_msg);
217 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ;
218 fe_msg.register_req = &rgstr_req;
219
220 MGMTD_FE_CLIENT_DBG(
221 "Sending REGISTER_REQ message to MGMTD Frontend server");
222
223 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
224 }
225
226 static int
227 mgmt_fe_send_session_req(struct mgmt_fe_client_ctx *client_ctx,
228 struct mgmt_fe_client_session *session,
229 bool create)
230 {
231 Mgmtd__FeMessage fe_msg;
232 Mgmtd__FeSessionReq sess_req;
233
234 mgmtd__fe_session_req__init(&sess_req);
235 sess_req.create = create;
236 if (create) {
237 sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID;
238 sess_req.client_conn_id = session->client_id;
239 } else {
240 sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_SESSION_ID;
241 sess_req.session_id = session->session_id;
242 }
243
244 mgmtd__fe_message__init(&fe_msg);
245 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ;
246 fe_msg.session_req = &sess_req;
247
248 MGMTD_FE_CLIENT_DBG(
249 "Sending SESSION_REQ message for %s session %llu to MGMTD Frontend server",
250 create ? "creating" : "destroying",
251 (unsigned long long)session->client_id);
252
253 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
254 }
255
256 static int
257 mgmt_fe_send_lockds_req(struct mgmt_fe_client_ctx *client_ctx,
258 struct mgmt_fe_client_session *session, bool lock,
259 uint64_t req_id, Mgmtd__DatastoreId ds_id)
260 {
261 (void)req_id;
262 Mgmtd__FeMessage fe_msg;
263 Mgmtd__FeLockDsReq lockds_req;
264
265 mgmtd__fe_lock_ds_req__init(&lockds_req);
266 lockds_req.session_id = session->session_id;
267 lockds_req.req_id = req_id;
268 lockds_req.ds_id = ds_id;
269 lockds_req.lock = lock;
270
271 mgmtd__fe_message__init(&fe_msg);
272 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ;
273 fe_msg.lockds_req = &lockds_req;
274
275 MGMTD_FE_CLIENT_DBG(
276 "Sending %sLOCK_REQ message for Ds:%d session %llu to MGMTD Frontend server",
277 lock ? "" : "UN", ds_id,
278 (unsigned long long)session->client_id);
279
280 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
281 }
282
283 static int
284 mgmt_fe_send_setcfg_req(struct mgmt_fe_client_ctx *client_ctx,
285 struct mgmt_fe_client_session *session,
286 uint64_t req_id, Mgmtd__DatastoreId ds_id,
287 Mgmtd__YangCfgDataReq **data_req, int num_data_reqs,
288 bool implicit_commit, Mgmtd__DatastoreId dst_ds_id)
289 {
290 (void)req_id;
291 Mgmtd__FeMessage fe_msg;
292 Mgmtd__FeSetConfigReq setcfg_req;
293
294 mgmtd__fe_set_config_req__init(&setcfg_req);
295 setcfg_req.session_id = session->session_id;
296 setcfg_req.ds_id = ds_id;
297 setcfg_req.req_id = req_id;
298 setcfg_req.data = data_req;
299 setcfg_req.n_data = (size_t)num_data_reqs;
300 setcfg_req.implicit_commit = implicit_commit;
301 setcfg_req.commit_ds_id = dst_ds_id;
302
303 mgmtd__fe_message__init(&fe_msg);
304 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ;
305 fe_msg.setcfg_req = &setcfg_req;
306
307 MGMTD_FE_CLIENT_DBG(
308 "Sending SET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
309 ds_id, (unsigned long long)session->client_id, num_data_reqs);
310
311 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
312 }
313
314 static int mgmt_fe_send_commitcfg_req(struct mgmt_fe_client_ctx *client_ctx,
315 struct mgmt_fe_client_session *session,
316 uint64_t req_id,
317 Mgmtd__DatastoreId src_ds_id,
318 Mgmtd__DatastoreId dest_ds_id,
319 bool validate_only, bool abort)
320 {
321 (void)req_id;
322 Mgmtd__FeMessage fe_msg;
323 Mgmtd__FeCommitConfigReq commitcfg_req;
324
325 mgmtd__fe_commit_config_req__init(&commitcfg_req);
326 commitcfg_req.session_id = session->session_id;
327 commitcfg_req.src_ds_id = src_ds_id;
328 commitcfg_req.dst_ds_id = dest_ds_id;
329 commitcfg_req.req_id = req_id;
330 commitcfg_req.validate_only = validate_only;
331 commitcfg_req.abort = abort;
332
333 mgmtd__fe_message__init(&fe_msg);
334 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ;
335 fe_msg.commcfg_req = &commitcfg_req;
336
337 MGMTD_FE_CLIENT_DBG(
338 "Sending COMMIT_CONFIG_REQ message for Src-Ds:%d, Dst-Ds:%d session %llu to MGMTD Frontend server",
339 src_ds_id, dest_ds_id, (unsigned long long)session->client_id);
340
341 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
342 }
343
344 static int
345 mgmt_fe_send_getcfg_req(struct mgmt_fe_client_ctx *client_ctx,
346 struct mgmt_fe_client_session *session,
347 uint64_t req_id, Mgmtd__DatastoreId ds_id,
348 Mgmtd__YangGetDataReq * data_req[],
349 int num_data_reqs)
350 {
351 (void)req_id;
352 Mgmtd__FeMessage fe_msg;
353 Mgmtd__FeGetConfigReq getcfg_req;
354
355 mgmtd__fe_get_config_req__init(&getcfg_req);
356 getcfg_req.session_id = session->session_id;
357 getcfg_req.ds_id = ds_id;
358 getcfg_req.req_id = req_id;
359 getcfg_req.data = data_req;
360 getcfg_req.n_data = (size_t)num_data_reqs;
361
362 mgmtd__fe_message__init(&fe_msg);
363 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REQ;
364 fe_msg.getcfg_req = &getcfg_req;
365
366 MGMTD_FE_CLIENT_DBG(
367 "Sending GET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
368 ds_id, (unsigned long long)session->client_id, num_data_reqs);
369
370 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
371 }
372
373 static int
374 mgmt_fe_send_getdata_req(struct mgmt_fe_client_ctx *client_ctx,
375 struct mgmt_fe_client_session *session,
376 uint64_t req_id, Mgmtd__DatastoreId ds_id,
377 Mgmtd__YangGetDataReq * data_req[],
378 int num_data_reqs)
379 {
380 (void)req_id;
381 Mgmtd__FeMessage fe_msg;
382 Mgmtd__FeGetDataReq getdata_req;
383
384 mgmtd__fe_get_data_req__init(&getdata_req);
385 getdata_req.session_id = session->session_id;
386 getdata_req.ds_id = ds_id;
387 getdata_req.req_id = req_id;
388 getdata_req.data = data_req;
389 getdata_req.n_data = (size_t)num_data_reqs;
390
391 mgmtd__fe_message__init(&fe_msg);
392 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REQ;
393 fe_msg.getdata_req = &getdata_req;
394
395 MGMTD_FE_CLIENT_DBG(
396 "Sending GET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
397 ds_id, (unsigned long long)session->client_id, num_data_reqs);
398
399 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
400 }
401
402 static int mgmt_fe_send_regnotify_req(
403 struct mgmt_fe_client_ctx *client_ctx,
404 struct mgmt_fe_client_session *session, uint64_t req_id,
405 Mgmtd__DatastoreId ds_id, bool register_req,
406 Mgmtd__YangDataXPath * data_req[], int num_data_reqs)
407 {
408 (void)req_id;
409 Mgmtd__FeMessage fe_msg;
410 Mgmtd__FeRegisterNotifyReq regntfy_req;
411
412 mgmtd__fe_register_notify_req__init(&regntfy_req);
413 regntfy_req.session_id = session->session_id;
414 regntfy_req.ds_id = ds_id;
415 regntfy_req.register_req = register_req;
416 regntfy_req.data_xpath = data_req;
417 regntfy_req.n_data_xpath = (size_t)num_data_reqs;
418
419 mgmtd__fe_message__init(&fe_msg);
420 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ;
421 fe_msg.regnotify_req = &regntfy_req;
422
423 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
424 }
425
426 static int
427 mgmt_fe_client_handle_msg(struct mgmt_fe_client_ctx *client_ctx,
428 Mgmtd__FeMessage *fe_msg)
429 {
430 struct mgmt_fe_client_session *session = NULL;
431
432 /*
433 * protobuf-c adds a max size enum with an internal, and changing by
434 * version, name; cast to an int to avoid unhandled enum warnings
435 */
436 switch ((int)fe_msg->message_case) {
437 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY:
438 if (fe_msg->session_reply->create
439 && fe_msg->session_reply->has_client_conn_id) {
440 MGMTD_FE_CLIENT_DBG(
441 "Got Session Create Reply Msg for client-id %llu with session-id: %llu.",
442 (unsigned long long)
443 fe_msg->session_reply->client_conn_id,
444 (unsigned long long)
445 fe_msg->session_reply->session_id);
446
447 session = mgmt_fe_find_session_by_client_id(
448 client_ctx,
449 fe_msg->session_reply->client_conn_id);
450
451 if (session && fe_msg->session_reply->success) {
452 MGMTD_FE_CLIENT_DBG(
453 "Session Create for client-id %llu successful.",
454 (unsigned long long)
455 fe_msg->session_reply
456 ->client_conn_id);
457 session->session_id =
458 fe_msg->session_reply->session_id;
459 } else {
460 MGMTD_FE_CLIENT_ERR(
461 "Session Create for client-id %llu failed.",
462 (unsigned long long)
463 fe_msg->session_reply
464 ->client_conn_id);
465 }
466 } else if (!fe_msg->session_reply->create) {
467 MGMTD_FE_CLIENT_DBG(
468 "Got Session Destroy Reply Msg for session-id %llu",
469 (unsigned long long)
470 fe_msg->session_reply->session_id);
471
472 session = mgmt_fe_find_session_by_session_id(
473 client_ctx, fe_msg->session_req->session_id);
474 }
475
476 if (session && session->client_ctx
477 && session->client_ctx->client_params
478 .client_session_notify)
479 (*session->client_ctx->client_params
480 .client_session_notify)(
481 (uintptr_t)client_ctx,
482 client_ctx->client_params.user_data,
483 session->client_id,
484 fe_msg->session_reply->create,
485 fe_msg->session_reply->success,
486 (uintptr_t)session, session->user_ctx);
487 break;
488 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY:
489 MGMTD_FE_CLIENT_DBG(
490 "Got LockDs Reply Msg for session-id %llu",
491 (unsigned long long)
492 fe_msg->lockds_reply->session_id);
493 session = mgmt_fe_find_session_by_session_id(
494 client_ctx, fe_msg->lockds_reply->session_id);
495
496 if (session && session->client_ctx
497 && session->client_ctx->client_params
498 .lock_ds_notify)
499 (*session->client_ctx->client_params
500 .lock_ds_notify)(
501 (uintptr_t)client_ctx,
502 client_ctx->client_params.user_data,
503 session->client_id, (uintptr_t)session,
504 session->user_ctx,
505 fe_msg->lockds_reply->req_id,
506 fe_msg->lockds_reply->lock,
507 fe_msg->lockds_reply->success,
508 fe_msg->lockds_reply->ds_id,
509 fe_msg->lockds_reply->error_if_any);
510 break;
511 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY:
512 MGMTD_FE_CLIENT_DBG(
513 "Got Set Config Reply Msg for session-id %llu",
514 (unsigned long long)
515 fe_msg->setcfg_reply->session_id);
516
517 session = mgmt_fe_find_session_by_session_id(
518 client_ctx, fe_msg->setcfg_reply->session_id);
519
520 if (session && session->client_ctx
521 && session->client_ctx->client_params
522 .set_config_notify)
523 (*session->client_ctx->client_params
524 .set_config_notify)(
525 (uintptr_t)client_ctx,
526 client_ctx->client_params.user_data,
527 session->client_id, (uintptr_t)session,
528 session->user_ctx,
529 fe_msg->setcfg_reply->req_id,
530 fe_msg->setcfg_reply->success,
531 fe_msg->setcfg_reply->ds_id,
532 fe_msg->setcfg_reply->error_if_any);
533 break;
534 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY:
535 MGMTD_FE_CLIENT_DBG(
536 "Got Commit Config Reply Msg for session-id %llu",
537 (unsigned long long)
538 fe_msg->commcfg_reply->session_id);
539
540 session = mgmt_fe_find_session_by_session_id(
541 client_ctx, fe_msg->commcfg_reply->session_id);
542
543 if (session && session->client_ctx
544 && session->client_ctx->client_params
545 .commit_config_notify)
546 (*session->client_ctx->client_params
547 .commit_config_notify)(
548 (uintptr_t)client_ctx,
549 client_ctx->client_params.user_data,
550 session->client_id, (uintptr_t)session,
551 session->user_ctx,
552 fe_msg->commcfg_reply->req_id,
553 fe_msg->commcfg_reply->success,
554 fe_msg->commcfg_reply->src_ds_id,
555 fe_msg->commcfg_reply->dst_ds_id,
556 fe_msg->commcfg_reply->validate_only,
557 fe_msg->commcfg_reply->error_if_any);
558 break;
559 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REPLY:
560 MGMTD_FE_CLIENT_DBG(
561 "Got Get Config Reply Msg for session-id %llu",
562 (unsigned long long)
563 fe_msg->getcfg_reply->session_id);
564
565 session = mgmt_fe_find_session_by_session_id(
566 client_ctx, fe_msg->getcfg_reply->session_id);
567
568 if (session && session->client_ctx
569 && session->client_ctx->client_params
570 .get_data_notify)
571 (*session->client_ctx->client_params
572 .get_data_notify)(
573 (uintptr_t)client_ctx,
574 client_ctx->client_params.user_data,
575 session->client_id, (uintptr_t)session,
576 session->user_ctx,
577 fe_msg->getcfg_reply->req_id,
578 fe_msg->getcfg_reply->success,
579 fe_msg->getcfg_reply->ds_id,
580 fe_msg->getcfg_reply->data
581 ? fe_msg->getcfg_reply->data->data
582 : NULL,
583 fe_msg->getcfg_reply->data
584 ? fe_msg->getcfg_reply->data->n_data
585 : 0,
586 fe_msg->getcfg_reply->data
587 ? fe_msg->getcfg_reply->data
588 ->next_indx
589 : 0,
590 fe_msg->getcfg_reply->error_if_any);
591 break;
592 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REPLY:
593 MGMTD_FE_CLIENT_DBG(
594 "Got Get Data Reply Msg for session-id %llu",
595 (unsigned long long)
596 fe_msg->getdata_reply->session_id);
597
598 session = mgmt_fe_find_session_by_session_id(
599 client_ctx, fe_msg->getdata_reply->session_id);
600
601 if (session && session->client_ctx
602 && session->client_ctx->client_params
603 .get_data_notify)
604 (*session->client_ctx->client_params
605 .get_data_notify)(
606 (uintptr_t)client_ctx,
607 client_ctx->client_params.user_data,
608 session->client_id, (uintptr_t)session,
609 session->user_ctx,
610 fe_msg->getdata_reply->req_id,
611 fe_msg->getdata_reply->success,
612 fe_msg->getdata_reply->ds_id,
613 fe_msg->getdata_reply->data
614 ? fe_msg->getdata_reply->data->data
615 : NULL,
616 fe_msg->getdata_reply->data
617 ? fe_msg->getdata_reply->data
618 ->n_data
619 : 0,
620 fe_msg->getdata_reply->data
621 ? fe_msg->getdata_reply->data
622 ->next_indx
623 : 0,
624 fe_msg->getdata_reply->error_if_any);
625 break;
626 case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
627 case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ:
628 /*
629 * TODO: Add handling code in future.
630 */
631 break;
632 /*
633 * NOTE: The following messages are always sent from Frontend
634 * clients to MGMTd only and/or need not be handled here.
635 */
636 case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ:
637 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ:
638 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ:
639 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ:
640 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ:
641 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REQ:
642 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REQ:
643 case MGMTD__FE_MESSAGE__MESSAGE__NOT_SET:
644 default:
645 /*
646 * A 'default' case is being added contrary to the
647 * FRR code guidelines to take care of build
648 * failures on certain build systems (courtesy of
649 * the proto-c package).
650 */
651 break;
652 }
653
654 return 0;
655 }
656
657 static void mgmt_fe_client_process_msg(void *user_ctx, uint8_t *data,
658 size_t len)
659 {
660 struct mgmt_fe_client_ctx *client_ctx = user_ctx;
661 Mgmtd__FeMessage *fe_msg;
662
663 fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
664 if (!fe_msg) {
665 MGMTD_FE_CLIENT_DBG("Failed to decode %zu bytes from server.",
666 len);
667 return;
668 }
669 MGMTD_FE_CLIENT_DBG(
670 "Decoded %zu bytes of message(msg: %u/%u) from server", len,
671 fe_msg->message_case, fe_msg->message_case);
672 (void)mgmt_fe_client_handle_msg(client_ctx, fe_msg);
673 mgmtd__fe_message__free_unpacked(fe_msg, NULL);
674 }
675
676 static void mgmt_fe_client_proc_msgbufs(struct event *thread)
677 {
678 struct mgmt_fe_client_ctx *client_ctx;
679
680 client_ctx = (struct mgmt_fe_client_ctx *)EVENT_ARG(thread);
681 if (mgmt_msg_procbufs(&client_ctx->mstate, mgmt_fe_client_process_msg,
682 client_ctx, mgmt_debug_fe_client))
683 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_PROC_MSG);
684 }
685
686 static void mgmt_fe_client_read(struct event *thread)
687 {
688 struct mgmt_fe_client_ctx *client_ctx;
689 enum mgmt_msg_rsched rv;
690
691 client_ctx = (struct mgmt_fe_client_ctx *)EVENT_ARG(thread);
692
693 rv = mgmt_msg_read(&client_ctx->mstate, client_ctx->conn_fd,
694 mgmt_debug_fe_client);
695 if (rv == MSR_DISCONNECT) {
696 mgmt_fe_server_disconnect(client_ctx, true);
697 return;
698 }
699 if (rv == MSR_SCHED_BOTH)
700 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_PROC_MSG);
701 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_CONN_READ);
702 }
703
704 static void mgmt_fe_server_connect(struct mgmt_fe_client_ctx *client_ctx)
705 {
706 const char *dbgtag = mgmt_debug_fe_client ? "FE-client" : NULL;
707
708 assert(client_ctx->conn_fd == -1);
709 client_ctx->conn_fd = mgmt_msg_connect(
710 MGMTD_FE_SERVER_PATH, MGMTD_SOCKET_FE_SEND_BUF_SIZE,
711 MGMTD_SOCKET_FE_RECV_BUF_SIZE, dbgtag);
712
713 /* Send REGISTER_REQ message */
714 if (client_ctx->conn_fd == -1 ||
715 mgmt_fe_send_register_req(client_ctx) != 0) {
716 mgmt_fe_server_disconnect(client_ctx, true);
717 return;
718 }
719
720 /* Start reading from the socket */
721 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_CONN_READ);
722
723 /* Notify client through registered callback (if any) */
724 if (client_ctx->client_params.client_connect_notify)
725 (void)(*client_ctx->client_params.client_connect_notify)(
726 (uintptr_t)client_ctx,
727 client_ctx->client_params.user_data, true);
728 }
729
730
731 static void mgmt_fe_client_conn_timeout(struct event *thread)
732 {
733 mgmt_fe_server_connect(EVENT_ARG(thread));
734 }
735
736 static void
737 mgmt_fe_client_register_event(struct mgmt_fe_client_ctx *client_ctx,
738 enum mgmt_fe_event event)
739 {
740 struct timeval tv = {0};
741
742 switch (event) {
743 case MGMTD_FE_CONN_READ:
744 event_add_read(client_ctx->tm, mgmt_fe_client_read,
745 client_ctx, client_ctx->conn_fd,
746 &client_ctx->conn_read_ev);
747 break;
748 case MGMTD_FE_CONN_WRITE:
749 event_add_write(client_ctx->tm, mgmt_fe_client_write,
750 client_ctx, client_ctx->conn_fd,
751 &client_ctx->conn_write_ev);
752 break;
753 case MGMTD_FE_PROC_MSG:
754 tv.tv_usec = MGMTD_FE_MSG_PROC_DELAY_USEC;
755 event_add_timer_tv(client_ctx->tm,
756 mgmt_fe_client_proc_msgbufs, client_ctx,
757 &tv, &client_ctx->msg_proc_ev);
758 break;
759 case MGMTD_FE_CONN_WRITES_ON:
760 event_add_timer_msec(
761 client_ctx->tm, mgmt_fe_client_resume_writes,
762 client_ctx, MGMTD_FE_MSG_WRITE_DELAY_MSEC,
763 &client_ctx->conn_writes_on);
764 break;
765 case MGMTD_FE_SERVER:
766 assert(!"mgmt_fe_client_ctx_post_event called incorrectly");
767 break;
768 }
769 }
770
771 static void mgmt_fe_client_schedule_conn_retry(
772 struct mgmt_fe_client_ctx *client_ctx, unsigned long intvl_secs)
773 {
774 MGMTD_FE_CLIENT_DBG(
775 "Scheduling MGMTD Frontend server connection retry after %lu seconds",
776 intvl_secs);
777 event_add_timer(client_ctx->tm, mgmt_fe_client_conn_timeout,
778 (void *)client_ctx, intvl_secs,
779 &client_ctx->conn_retry_tmr);
780 }
781
782 /*
783 * Initialize library and try connecting with MGMTD.
784 */
785 uintptr_t mgmt_fe_client_lib_init(struct mgmt_fe_client_params *params,
786 struct event_loop *master_thread)
787 {
788 assert(master_thread && params && strlen(params->name)
789 && !mgmt_fe_client_ctx.tm);
790
791 mgmt_fe_client_ctx.tm = master_thread;
792 memcpy(&mgmt_fe_client_ctx.client_params, params,
793 sizeof(mgmt_fe_client_ctx.client_params));
794 if (!mgmt_fe_client_ctx.client_params.conn_retry_intvl_sec)
795 mgmt_fe_client_ctx.client_params.conn_retry_intvl_sec =
796 MGMTD_FE_DEFAULT_CONN_RETRY_INTVL_SEC;
797
798 mgmt_msg_init(&mgmt_fe_client_ctx.mstate, MGMTD_FE_MAX_NUM_MSG_PROC,
799 MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN,
800 "FE-client");
801
802 mgmt_sessions_init(&mgmt_fe_client_ctx.client_sessions);
803
804 /* Start trying to connect to MGMTD frontend server immediately */
805 mgmt_fe_client_schedule_conn_retry(&mgmt_fe_client_ctx, 1);
806
807 MGMTD_FE_CLIENT_DBG("Initialized client '%s'", params->name);
808
809 return (uintptr_t)&mgmt_fe_client_ctx;
810 }
811
812 /*
813 * Create a new Session for a Frontend Client connection.
814 */
815 enum mgmt_result mgmt_fe_create_client_session(uintptr_t lib_hndl,
816 uint64_t client_id,
817 uintptr_t user_ctx)
818 {
819 struct mgmt_fe_client_ctx *client_ctx;
820 struct mgmt_fe_client_session *session;
821
822 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
823 if (!client_ctx)
824 return MGMTD_INVALID_PARAM;
825
826 session = XCALLOC(MTYPE_MGMTD_FE_SESSION,
827 sizeof(struct mgmt_fe_client_session));
828 assert(session);
829 session->user_ctx = user_ctx;
830 session->client_id = client_id;
831 session->client_ctx = client_ctx;
832 session->session_id = 0;
833
834 if (mgmt_fe_send_session_req(client_ctx, session, true) != 0) {
835 XFREE(MTYPE_MGMTD_FE_SESSION, session);
836 return MGMTD_INTERNAL_ERROR;
837 }
838 mgmt_sessions_add_tail(&client_ctx->client_sessions, session);
839
840 return MGMTD_SUCCESS;
841 }
842
843 /*
844 * Delete an existing Session for a Frontend Client connection.
845 */
846 enum mgmt_result mgmt_fe_destroy_client_session(uintptr_t lib_hndl,
847 uint64_t client_id)
848 {
849 struct mgmt_fe_client_ctx *client_ctx;
850 struct mgmt_fe_client_session *session;
851
852 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
853 if (!client_ctx)
854 return MGMTD_INVALID_PARAM;
855
856 session = mgmt_fe_find_session_by_client_id(client_ctx, client_id);
857 if (!session || session->client_ctx != client_ctx)
858 return MGMTD_INVALID_PARAM;
859
860 if (session->session_id &&
861 mgmt_fe_send_session_req(client_ctx, session, false) != 0)
862 MGMTD_FE_CLIENT_ERR(
863 "Failed to send session destroy request for the session-id %lu",
864 (unsigned long)session->session_id);
865
866 mgmt_sessions_del(&client_ctx->client_sessions, session);
867 XFREE(MTYPE_MGMTD_FE_SESSION, session);
868
869 return MGMTD_SUCCESS;
870 }
871
872 static void mgmt_fe_destroy_client_sessions(uintptr_t lib_hndl)
873 {
874 struct mgmt_fe_client_ctx *client_ctx;
875 struct mgmt_fe_client_session *session;
876
877 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
878 if (!client_ctx)
879 return;
880
881 FOREACH_SESSION_IN_LIST (client_ctx, session)
882 mgmt_fe_destroy_client_session(lib_hndl, session->client_id);
883 }
884
885 /*
886 * Send UN/LOCK_DS_REQ to MGMTD for a specific Datastore DS.
887 */
888 enum mgmt_result mgmt_fe_lock_ds(uintptr_t lib_hndl, uintptr_t session_id,
889 uint64_t req_id, Mgmtd__DatastoreId ds_id,
890 bool lock_ds)
891 {
892 struct mgmt_fe_client_ctx *client_ctx;
893 struct mgmt_fe_client_session *session;
894
895 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
896 if (!client_ctx)
897 return MGMTD_INVALID_PARAM;
898
899 session = (struct mgmt_fe_client_session *)session_id;
900 if (!session || session->client_ctx != client_ctx)
901 return MGMTD_INVALID_PARAM;
902
903 if (mgmt_fe_send_lockds_req(client_ctx, session, lock_ds, req_id,
904 ds_id)
905 != 0)
906 return MGMTD_INTERNAL_ERROR;
907
908 return MGMTD_SUCCESS;
909 }
910
911 /*
912 * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
913 */
914 enum mgmt_result
915 mgmt_fe_set_config_data(uintptr_t lib_hndl, uintptr_t session_id,
916 uint64_t req_id, Mgmtd__DatastoreId ds_id,
917 Mgmtd__YangCfgDataReq **config_req, int num_reqs,
918 bool implicit_commit, Mgmtd__DatastoreId dst_ds_id)
919 {
920 struct mgmt_fe_client_ctx *client_ctx;
921 struct mgmt_fe_client_session *session;
922
923 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
924 if (!client_ctx)
925 return MGMTD_INVALID_PARAM;
926
927 session = (struct mgmt_fe_client_session *)session_id;
928 if (!session || session->client_ctx != client_ctx)
929 return MGMTD_INVALID_PARAM;
930
931 if (mgmt_fe_send_setcfg_req(client_ctx, session, req_id, ds_id,
932 config_req, num_reqs, implicit_commit,
933 dst_ds_id)
934 != 0)
935 return MGMTD_INTERNAL_ERROR;
936
937 return MGMTD_SUCCESS;
938 }
939
940 /*
941 * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
942 */
943 enum mgmt_result mgmt_fe_commit_config_data(uintptr_t lib_hndl,
944 uintptr_t session_id,
945 uint64_t req_id,
946 Mgmtd__DatastoreId src_ds_id,
947 Mgmtd__DatastoreId dst_ds_id,
948 bool validate_only, bool abort)
949 {
950 struct mgmt_fe_client_ctx *client_ctx;
951 struct mgmt_fe_client_session *session;
952
953 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
954 if (!client_ctx)
955 return MGMTD_INVALID_PARAM;
956
957 session = (struct mgmt_fe_client_session *)session_id;
958 if (!session || session->client_ctx != client_ctx)
959 return MGMTD_INVALID_PARAM;
960
961 if (mgmt_fe_send_commitcfg_req(client_ctx, session, req_id, src_ds_id,
962 dst_ds_id, validate_only, abort)
963 != 0)
964 return MGMTD_INTERNAL_ERROR;
965
966 return MGMTD_SUCCESS;
967 }
968
969 /*
970 * Send GET_CONFIG_REQ to MGMTD for one or more config data item(s).
971 */
972 enum mgmt_result
973 mgmt_fe_get_config_data(uintptr_t lib_hndl, uintptr_t session_id,
974 uint64_t req_id, Mgmtd__DatastoreId ds_id,
975 Mgmtd__YangGetDataReq * data_req[], int num_reqs)
976 {
977 struct mgmt_fe_client_ctx *client_ctx;
978 struct mgmt_fe_client_session *session;
979
980 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
981 if (!client_ctx)
982 return MGMTD_INVALID_PARAM;
983
984 session = (struct mgmt_fe_client_session *)session_id;
985 if (!session || session->client_ctx != client_ctx)
986 return MGMTD_INVALID_PARAM;
987
988 if (mgmt_fe_send_getcfg_req(client_ctx, session, req_id, ds_id,
989 data_req, num_reqs)
990 != 0)
991 return MGMTD_INTERNAL_ERROR;
992
993 return MGMTD_SUCCESS;
994 }
995
996 /*
997 * Send GET_DATA_REQ to MGMTD for one or more config data item(s).
998 */
999 enum mgmt_result mgmt_fe_get_data(uintptr_t lib_hndl, uintptr_t session_id,
1000 uint64_t req_id, Mgmtd__DatastoreId ds_id,
1001 Mgmtd__YangGetDataReq * data_req[],
1002 int num_reqs)
1003 {
1004 struct mgmt_fe_client_ctx *client_ctx;
1005 struct mgmt_fe_client_session *session;
1006
1007 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
1008 if (!client_ctx)
1009 return MGMTD_INVALID_PARAM;
1010
1011 session = (struct mgmt_fe_client_session *)session_id;
1012 if (!session || session->client_ctx != client_ctx)
1013 return MGMTD_INVALID_PARAM;
1014
1015 if (mgmt_fe_send_getdata_req(client_ctx, session, req_id, ds_id,
1016 data_req, num_reqs)
1017 != 0)
1018 return MGMTD_INTERNAL_ERROR;
1019
1020 return MGMTD_SUCCESS;
1021 }
1022
1023 /*
1024 * Send NOTIFY_REGISTER_REQ to MGMTD daemon.
1025 */
1026 enum mgmt_result
1027 mgmt_fe_register_yang_notify(uintptr_t lib_hndl, uintptr_t session_id,
1028 uint64_t req_id, Mgmtd__DatastoreId ds_id,
1029 bool register_req,
1030 Mgmtd__YangDataXPath * data_req[],
1031 int num_reqs)
1032 {
1033 struct mgmt_fe_client_ctx *client_ctx;
1034 struct mgmt_fe_client_session *session;
1035
1036 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
1037 if (!client_ctx)
1038 return MGMTD_INVALID_PARAM;
1039
1040 session = (struct mgmt_fe_client_session *)session_id;
1041 if (!session || session->client_ctx != client_ctx)
1042 return MGMTD_INVALID_PARAM;
1043
1044 if (mgmt_fe_send_regnotify_req(client_ctx, session, req_id, ds_id,
1045 register_req, data_req, num_reqs)
1046 != 0)
1047 return MGMTD_INTERNAL_ERROR;
1048
1049 return MGMTD_SUCCESS;
1050 }
1051
1052 /*
1053 * Destroy library and cleanup everything.
1054 */
1055 void mgmt_fe_client_lib_destroy(uintptr_t lib_hndl)
1056 {
1057 struct mgmt_fe_client_ctx *client_ctx;
1058
1059 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
1060 assert(client_ctx);
1061
1062 MGMTD_FE_CLIENT_DBG("Destroying MGMTD Frontend Client '%s'",
1063 client_ctx->client_params.name);
1064
1065 mgmt_fe_server_disconnect(client_ctx, false);
1066
1067 mgmt_fe_destroy_client_sessions(lib_hndl);
1068
1069 EVENT_OFF(client_ctx->conn_retry_tmr);
1070 EVENT_OFF(client_ctx->conn_read_ev);
1071 EVENT_OFF(client_ctx->conn_write_ev);
1072 EVENT_OFF(client_ctx->conn_writes_on);
1073 EVENT_OFF(client_ctx->msg_proc_ev);
1074 mgmt_msg_destroy(&client_ctx->mstate);
1075 }