]> git.proxmox.com Git - mirror_frr.git/blob - lib/mgmt_fe_client.c
*: Convert struct thread_master to struct event_master and it's ilk
[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_master *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.", session,
113 (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 *)THREAD_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 *)THREAD_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, (unsigned long long)session->client_id);
278
279 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
280 }
281
282 static int
283 mgmt_fe_send_setcfg_req(struct mgmt_fe_client_ctx *client_ctx,
284 struct mgmt_fe_client_session *session,
285 uint64_t req_id, Mgmtd__DatastoreId ds_id,
286 Mgmtd__YangCfgDataReq **data_req, int num_data_reqs,
287 bool implicit_commit, Mgmtd__DatastoreId dst_ds_id)
288 {
289 (void)req_id;
290 Mgmtd__FeMessage fe_msg;
291 Mgmtd__FeSetConfigReq setcfg_req;
292
293 mgmtd__fe_set_config_req__init(&setcfg_req);
294 setcfg_req.session_id = session->session_id;
295 setcfg_req.ds_id = ds_id;
296 setcfg_req.req_id = req_id;
297 setcfg_req.data = data_req;
298 setcfg_req.n_data = (size_t)num_data_reqs;
299 setcfg_req.implicit_commit = implicit_commit;
300 setcfg_req.commit_ds_id = dst_ds_id;
301
302 mgmtd__fe_message__init(&fe_msg);
303 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ;
304 fe_msg.setcfg_req = &setcfg_req;
305
306 MGMTD_FE_CLIENT_DBG(
307 "Sending SET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
308 ds_id, (unsigned long long)session->client_id, num_data_reqs);
309
310 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
311 }
312
313 static int
314 mgmt_fe_send_commitcfg_req(struct mgmt_fe_client_ctx *client_ctx,
315 struct mgmt_fe_client_session *session,
316 uint64_t req_id, Mgmtd__DatastoreId src_ds_id,
317 Mgmtd__DatastoreId dest_ds_id, bool validate_only,
318 bool abort)
319 {
320 (void)req_id;
321 Mgmtd__FeMessage fe_msg;
322 Mgmtd__FeCommitConfigReq commitcfg_req;
323
324 mgmtd__fe_commit_config_req__init(&commitcfg_req);
325 commitcfg_req.session_id = session->session_id;
326 commitcfg_req.src_ds_id = src_ds_id;
327 commitcfg_req.dst_ds_id = dest_ds_id;
328 commitcfg_req.req_id = req_id;
329 commitcfg_req.validate_only = validate_only;
330 commitcfg_req.abort = abort;
331
332 mgmtd__fe_message__init(&fe_msg);
333 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ;
334 fe_msg.commcfg_req = &commitcfg_req;
335
336 MGMTD_FE_CLIENT_DBG(
337 "Sending COMMIT_CONFIG_REQ message for Src-Ds:%d, Dst-Ds:%d session %llu to MGMTD Frontend server",
338 src_ds_id, dest_ds_id, (unsigned long long)session->client_id);
339
340 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
341 }
342
343 static int
344 mgmt_fe_send_getcfg_req(struct mgmt_fe_client_ctx *client_ctx,
345 struct mgmt_fe_client_session *session,
346 uint64_t req_id, Mgmtd__DatastoreId ds_id,
347 Mgmtd__YangGetDataReq * data_req[],
348 int num_data_reqs)
349 {
350 (void)req_id;
351 Mgmtd__FeMessage fe_msg;
352 Mgmtd__FeGetConfigReq getcfg_req;
353
354 mgmtd__fe_get_config_req__init(&getcfg_req);
355 getcfg_req.session_id = session->session_id;
356 getcfg_req.ds_id = ds_id;
357 getcfg_req.req_id = req_id;
358 getcfg_req.data = data_req;
359 getcfg_req.n_data = (size_t)num_data_reqs;
360
361 mgmtd__fe_message__init(&fe_msg);
362 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REQ;
363 fe_msg.getcfg_req = &getcfg_req;
364
365 MGMTD_FE_CLIENT_DBG(
366 "Sending GET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
367 ds_id, (unsigned long long)session->client_id, num_data_reqs);
368
369 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
370 }
371
372 static int
373 mgmt_fe_send_getdata_req(struct mgmt_fe_client_ctx *client_ctx,
374 struct mgmt_fe_client_session *session,
375 uint64_t req_id, Mgmtd__DatastoreId ds_id,
376 Mgmtd__YangGetDataReq * data_req[],
377 int num_data_reqs)
378 {
379 (void)req_id;
380 Mgmtd__FeMessage fe_msg;
381 Mgmtd__FeGetDataReq getdata_req;
382
383 mgmtd__fe_get_data_req__init(&getdata_req);
384 getdata_req.session_id = session->session_id;
385 getdata_req.ds_id = ds_id;
386 getdata_req.req_id = req_id;
387 getdata_req.data = data_req;
388 getdata_req.n_data = (size_t)num_data_reqs;
389
390 mgmtd__fe_message__init(&fe_msg);
391 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REQ;
392 fe_msg.getdata_req = &getdata_req;
393
394 MGMTD_FE_CLIENT_DBG(
395 "Sending GET_CONFIG_REQ message for Ds:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
396 ds_id, (unsigned long long)session->client_id, num_data_reqs);
397
398 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
399 }
400
401 static int mgmt_fe_send_regnotify_req(
402 struct mgmt_fe_client_ctx *client_ctx,
403 struct mgmt_fe_client_session *session, uint64_t req_id,
404 Mgmtd__DatastoreId ds_id, bool register_req,
405 Mgmtd__YangDataXPath * data_req[], int num_data_reqs)
406 {
407 (void)req_id;
408 Mgmtd__FeMessage fe_msg;
409 Mgmtd__FeRegisterNotifyReq regntfy_req;
410
411 mgmtd__fe_register_notify_req__init(&regntfy_req);
412 regntfy_req.session_id = session->session_id;
413 regntfy_req.ds_id = ds_id;
414 regntfy_req.register_req = register_req;
415 regntfy_req.data_xpath = data_req;
416 regntfy_req.n_data_xpath = (size_t)num_data_reqs;
417
418 mgmtd__fe_message__init(&fe_msg);
419 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ;
420 fe_msg.regnotify_req = &regntfy_req;
421
422 return mgmt_fe_client_send_msg(client_ctx, &fe_msg);
423 }
424
425 static int
426 mgmt_fe_client_handle_msg(struct mgmt_fe_client_ctx *client_ctx,
427 Mgmtd__FeMessage *fe_msg)
428 {
429 struct mgmt_fe_client_session *session = NULL;
430
431 /*
432 * protobuf-c adds a max size enum with an internal, and changing by
433 * version, name; cast to an int to avoid unhandled enum warnings
434 */
435 switch ((int)fe_msg->message_case) {
436 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY:
437 if (fe_msg->session_reply->create
438 && fe_msg->session_reply->has_client_conn_id) {
439 MGMTD_FE_CLIENT_DBG(
440 "Got Session Create Reply Msg for client-id %llu with session-id: %llu.",
441 (unsigned long long)
442 fe_msg->session_reply->client_conn_id,
443 (unsigned long long)
444 fe_msg->session_reply->session_id);
445
446 session = mgmt_fe_find_session_by_client_id(
447 client_ctx,
448 fe_msg->session_reply->client_conn_id);
449
450 if (session && fe_msg->session_reply->success) {
451 MGMTD_FE_CLIENT_DBG(
452 "Session Create for client-id %llu successful.",
453 (unsigned long long)fe_msg
454 ->session_reply->client_conn_id);
455 session->session_id =
456 fe_msg->session_reply->session_id;
457 } else {
458 MGMTD_FE_CLIENT_ERR(
459 "Session Create for client-id %llu failed.",
460 (unsigned long long)fe_msg
461 ->session_reply->client_conn_id);
462 }
463 } else if (!fe_msg->session_reply->create) {
464 MGMTD_FE_CLIENT_DBG(
465 "Got Session Destroy Reply Msg for session-id %llu",
466 (unsigned long long)
467 fe_msg->session_reply->session_id);
468
469 session = mgmt_fe_find_session_by_session_id(
470 client_ctx, fe_msg->session_req->session_id);
471 }
472
473 if (session && session->client_ctx
474 && session->client_ctx->client_params
475 .client_session_notify)
476 (*session->client_ctx->client_params
477 .client_session_notify)(
478 (uintptr_t)client_ctx,
479 client_ctx->client_params.user_data,
480 session->client_id,
481 fe_msg->session_reply->create,
482 fe_msg->session_reply->success,
483 (uintptr_t)session, session->user_ctx);
484 break;
485 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY:
486 MGMTD_FE_CLIENT_DBG(
487 "Got LockDs Reply Msg for session-id %llu",
488 (unsigned long long)
489 fe_msg->lockds_reply->session_id);
490 session = mgmt_fe_find_session_by_session_id(
491 client_ctx, fe_msg->lockds_reply->session_id);
492
493 if (session && session->client_ctx
494 && session->client_ctx->client_params
495 .lock_ds_notify)
496 (*session->client_ctx->client_params
497 .lock_ds_notify)(
498 (uintptr_t)client_ctx,
499 client_ctx->client_params.user_data,
500 session->client_id, (uintptr_t)session,
501 session->user_ctx,
502 fe_msg->lockds_reply->req_id,
503 fe_msg->lockds_reply->lock,
504 fe_msg->lockds_reply->success,
505 fe_msg->lockds_reply->ds_id,
506 fe_msg->lockds_reply->error_if_any);
507 break;
508 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY:
509 MGMTD_FE_CLIENT_DBG(
510 "Got Set Config Reply Msg for session-id %llu",
511 (unsigned long long)
512 fe_msg->setcfg_reply->session_id);
513
514 session = mgmt_fe_find_session_by_session_id(
515 client_ctx, fe_msg->setcfg_reply->session_id);
516
517 if (session && session->client_ctx
518 && session->client_ctx->client_params
519 .set_config_notify)
520 (*session->client_ctx->client_params
521 .set_config_notify)(
522 (uintptr_t)client_ctx,
523 client_ctx->client_params.user_data,
524 session->client_id, (uintptr_t)session,
525 session->user_ctx,
526 fe_msg->setcfg_reply->req_id,
527 fe_msg->setcfg_reply->success,
528 fe_msg->setcfg_reply->ds_id,
529 fe_msg->setcfg_reply->error_if_any);
530 break;
531 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY:
532 MGMTD_FE_CLIENT_DBG(
533 "Got Commit Config Reply Msg for session-id %llu",
534 (unsigned long long)
535 fe_msg->commcfg_reply->session_id);
536
537 session = mgmt_fe_find_session_by_session_id(
538 client_ctx, fe_msg->commcfg_reply->session_id);
539
540 if (session && session->client_ctx
541 && session->client_ctx->client_params
542 .commit_config_notify)
543 (*session->client_ctx->client_params
544 .commit_config_notify)(
545 (uintptr_t)client_ctx,
546 client_ctx->client_params.user_data,
547 session->client_id, (uintptr_t)session,
548 session->user_ctx,
549 fe_msg->commcfg_reply->req_id,
550 fe_msg->commcfg_reply->success,
551 fe_msg->commcfg_reply->src_ds_id,
552 fe_msg->commcfg_reply->dst_ds_id,
553 fe_msg->commcfg_reply->validate_only,
554 fe_msg->commcfg_reply->error_if_any);
555 break;
556 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REPLY:
557 MGMTD_FE_CLIENT_DBG(
558 "Got Get Config Reply Msg for session-id %llu",
559 (unsigned long long)
560 fe_msg->getcfg_reply->session_id);
561
562 session = mgmt_fe_find_session_by_session_id(
563 client_ctx, fe_msg->getcfg_reply->session_id);
564
565 if (session && session->client_ctx
566 && session->client_ctx->client_params
567 .get_data_notify)
568 (*session->client_ctx->client_params
569 .get_data_notify)(
570 (uintptr_t)client_ctx,
571 client_ctx->client_params.user_data,
572 session->client_id, (uintptr_t)session,
573 session->user_ctx,
574 fe_msg->getcfg_reply->req_id,
575 fe_msg->getcfg_reply->success,
576 fe_msg->getcfg_reply->ds_id,
577 fe_msg->getcfg_reply->data
578 ? fe_msg->getcfg_reply->data->data
579 : NULL,
580 fe_msg->getcfg_reply->data
581 ? fe_msg->getcfg_reply->data->n_data
582 : 0,
583 fe_msg->getcfg_reply->data
584 ? fe_msg->getcfg_reply->data
585 ->next_indx
586 : 0,
587 fe_msg->getcfg_reply->error_if_any);
588 break;
589 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REPLY:
590 MGMTD_FE_CLIENT_DBG(
591 "Got Get Data Reply Msg for session-id %llu",
592 (unsigned long long)
593 fe_msg->getdata_reply->session_id);
594
595 session = mgmt_fe_find_session_by_session_id(
596 client_ctx, fe_msg->getdata_reply->session_id);
597
598 if (session && session->client_ctx
599 && session->client_ctx->client_params
600 .get_data_notify)
601 (*session->client_ctx->client_params
602 .get_data_notify)(
603 (uintptr_t)client_ctx,
604 client_ctx->client_params.user_data,
605 session->client_id, (uintptr_t)session,
606 session->user_ctx,
607 fe_msg->getdata_reply->req_id,
608 fe_msg->getdata_reply->success,
609 fe_msg->getdata_reply->ds_id,
610 fe_msg->getdata_reply->data
611 ? fe_msg->getdata_reply->data->data
612 : NULL,
613 fe_msg->getdata_reply->data
614 ? fe_msg->getdata_reply->data
615 ->n_data
616 : 0,
617 fe_msg->getdata_reply->data
618 ? fe_msg->getdata_reply->data
619 ->next_indx
620 : 0,
621 fe_msg->getdata_reply->error_if_any);
622 break;
623 case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
624 case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ:
625 /*
626 * TODO: Add handling code in future.
627 */
628 break;
629 /*
630 * NOTE: The following messages are always sent from Frontend
631 * clients to MGMTd only and/or need not be handled here.
632 */
633 case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ:
634 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ:
635 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ:
636 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ:
637 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ:
638 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REQ:
639 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REQ:
640 case MGMTD__FE_MESSAGE__MESSAGE__NOT_SET:
641 default:
642 /*
643 * A 'default' case is being added contrary to the
644 * FRR code guidelines to take care of build
645 * failures on certain build systems (courtesy of
646 * the proto-c package).
647 */
648 break;
649 }
650
651 return 0;
652 }
653
654 static void mgmt_fe_client_process_msg(void *user_ctx, uint8_t *data,
655 size_t len)
656 {
657 struct mgmt_fe_client_ctx *client_ctx = user_ctx;
658 Mgmtd__FeMessage *fe_msg;
659
660 fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
661 if (!fe_msg) {
662 MGMTD_FE_CLIENT_DBG("Failed to decode %zu bytes from server.",
663 len);
664 return;
665 }
666 MGMTD_FE_CLIENT_DBG(
667 "Decoded %zu bytes of message(msg: %u/%u) from server", len,
668 fe_msg->message_case, fe_msg->message_case);
669 (void)mgmt_fe_client_handle_msg(client_ctx, fe_msg);
670 mgmtd__fe_message__free_unpacked(fe_msg, NULL);
671 }
672
673 static void mgmt_fe_client_proc_msgbufs(struct event *thread)
674 {
675 struct mgmt_fe_client_ctx *client_ctx;
676
677 client_ctx = (struct mgmt_fe_client_ctx *)THREAD_ARG(thread);
678 if (mgmt_msg_procbufs(&client_ctx->mstate, mgmt_fe_client_process_msg,
679 client_ctx, mgmt_debug_fe_client))
680 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_PROC_MSG);
681 }
682
683 static void mgmt_fe_client_read(struct event *thread)
684 {
685 struct mgmt_fe_client_ctx *client_ctx;
686 enum mgmt_msg_rsched rv;
687
688 client_ctx = (struct mgmt_fe_client_ctx *)THREAD_ARG(thread);
689
690 rv = mgmt_msg_read(&client_ctx->mstate, client_ctx->conn_fd,
691 mgmt_debug_fe_client);
692 if (rv == MSR_DISCONNECT) {
693 mgmt_fe_server_disconnect(client_ctx, true);
694 return;
695 }
696 if (rv == MSR_SCHED_BOTH)
697 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_PROC_MSG);
698 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_CONN_READ);
699 }
700
701 static void mgmt_fe_server_connect(struct mgmt_fe_client_ctx *client_ctx)
702 {
703 const char *dbgtag = mgmt_debug_fe_client ? "FE-client" : NULL;
704
705 assert(client_ctx->conn_fd == -1);
706 client_ctx->conn_fd = mgmt_msg_connect(
707 MGMTD_FE_SERVER_PATH, MGMTD_SOCKET_FE_SEND_BUF_SIZE,
708 MGMTD_SOCKET_FE_RECV_BUF_SIZE, dbgtag);
709
710 /* Send REGISTER_REQ message */
711 if (client_ctx->conn_fd == -1 ||
712 mgmt_fe_send_register_req(client_ctx) != 0) {
713 mgmt_fe_server_disconnect(client_ctx, true);
714 return;
715 }
716
717 /* Start reading from the socket */
718 mgmt_fe_client_register_event(client_ctx, MGMTD_FE_CONN_READ);
719
720 /* Notify client through registered callback (if any) */
721 if (client_ctx->client_params.client_connect_notify)
722 (void)(*client_ctx->client_params.client_connect_notify)(
723 (uintptr_t)client_ctx,
724 client_ctx->client_params.user_data, true);
725 }
726
727
728 static void mgmt_fe_client_conn_timeout(struct event *thread)
729 {
730 mgmt_fe_server_connect(THREAD_ARG(thread));
731 }
732
733 static void
734 mgmt_fe_client_register_event(struct mgmt_fe_client_ctx *client_ctx,
735 enum mgmt_fe_event event)
736 {
737 struct timeval tv = {0};
738
739 switch (event) {
740 case MGMTD_FE_CONN_READ:
741 event_add_read(client_ctx->tm, mgmt_fe_client_read,
742 client_ctx, client_ctx->conn_fd,
743 &client_ctx->conn_read_ev);
744 assert(client_ctx->conn_read_ev);
745 break;
746 case MGMTD_FE_CONN_WRITE:
747 event_add_write(client_ctx->tm, mgmt_fe_client_write,
748 client_ctx, client_ctx->conn_fd,
749 &client_ctx->conn_write_ev);
750 assert(client_ctx->conn_write_ev);
751 break;
752 case MGMTD_FE_PROC_MSG:
753 tv.tv_usec = MGMTD_FE_MSG_PROC_DELAY_USEC;
754 event_add_timer_tv(client_ctx->tm,
755 mgmt_fe_client_proc_msgbufs, client_ctx,
756 &tv, &client_ctx->msg_proc_ev);
757 assert(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 assert(client_ctx->conn_writes_on);
765 break;
766 case MGMTD_FE_SERVER:
767 assert(!"mgmt_fe_client_ctx_post_event called incorrectly");
768 break;
769 }
770 }
771
772 static void mgmt_fe_client_schedule_conn_retry(
773 struct mgmt_fe_client_ctx *client_ctx, unsigned long intvl_secs)
774 {
775 MGMTD_FE_CLIENT_DBG(
776 "Scheduling MGMTD Frontend server connection retry after %lu seconds",
777 intvl_secs);
778 event_add_timer(client_ctx->tm, mgmt_fe_client_conn_timeout,
779 (void *)client_ctx, intvl_secs,
780 &client_ctx->conn_retry_tmr);
781 }
782
783 /*
784 * Initialize library and try connecting with MGMTD.
785 */
786 uintptr_t mgmt_fe_client_lib_init(struct mgmt_fe_client_params *params,
787 struct event_master *master_thread)
788 {
789 assert(master_thread && params && strlen(params->name)
790 && !mgmt_fe_client_ctx.tm);
791
792 mgmt_fe_client_ctx.tm = master_thread;
793 memcpy(&mgmt_fe_client_ctx.client_params, params,
794 sizeof(mgmt_fe_client_ctx.client_params));
795 if (!mgmt_fe_client_ctx.client_params.conn_retry_intvl_sec)
796 mgmt_fe_client_ctx.client_params.conn_retry_intvl_sec =
797 MGMTD_FE_DEFAULT_CONN_RETRY_INTVL_SEC;
798
799 mgmt_msg_init(&mgmt_fe_client_ctx.mstate, MGMTD_FE_MAX_NUM_MSG_PROC,
800 MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN,
801 "FE-client");
802
803 mgmt_sessions_init(&mgmt_fe_client_ctx.client_sessions);
804
805 /* Start trying to connect to MGMTD frontend server immediately */
806 mgmt_fe_client_schedule_conn_retry(&mgmt_fe_client_ctx, 1);
807
808 MGMTD_FE_CLIENT_DBG("Initialized client '%s'", params->name);
809
810 return (uintptr_t)&mgmt_fe_client_ctx;
811 }
812
813 /*
814 * Create a new Session for a Frontend Client connection.
815 */
816 enum mgmt_result mgmt_fe_create_client_session(uintptr_t lib_hndl,
817 uint64_t client_id,
818 uintptr_t user_ctx)
819 {
820 struct mgmt_fe_client_ctx *client_ctx;
821 struct mgmt_fe_client_session *session;
822
823 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
824 if (!client_ctx)
825 return MGMTD_INVALID_PARAM;
826
827 session = XCALLOC(MTYPE_MGMTD_FE_SESSION,
828 sizeof(struct mgmt_fe_client_session));
829 assert(session);
830 session->user_ctx = user_ctx;
831 session->client_id = client_id;
832 session->client_ctx = client_ctx;
833 session->session_id = 0;
834
835 if (mgmt_fe_send_session_req(client_ctx, session, true) != 0) {
836 XFREE(MTYPE_MGMTD_FE_SESSION, session);
837 return MGMTD_INTERNAL_ERROR;
838 }
839 mgmt_sessions_add_tail(&client_ctx->client_sessions, session);
840
841 return MGMTD_SUCCESS;
842 }
843
844 /*
845 * Delete an existing Session for a Frontend Client connection.
846 */
847 enum mgmt_result mgmt_fe_destroy_client_session(uintptr_t lib_hndl,
848 uint64_t client_id)
849 {
850 struct mgmt_fe_client_ctx *client_ctx;
851 struct mgmt_fe_client_session *session;
852
853 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
854 if (!client_ctx)
855 return MGMTD_INVALID_PARAM;
856
857 session = mgmt_fe_find_session_by_client_id(client_ctx, client_id);
858 if (!session || session->client_ctx != client_ctx)
859 return MGMTD_INVALID_PARAM;
860
861 if (session->session_id &&
862 mgmt_fe_send_session_req(client_ctx, session, false) != 0)
863 MGMTD_FE_CLIENT_ERR(
864 "Failed to send session destroy request for the session-id %lu",
865 (unsigned long)session->session_id);
866
867 mgmt_sessions_del(&client_ctx->client_sessions, session);
868 XFREE(MTYPE_MGMTD_FE_SESSION, session);
869
870 return MGMTD_SUCCESS;
871 }
872
873 static void mgmt_fe_destroy_client_sessions(uintptr_t lib_hndl)
874 {
875 struct mgmt_fe_client_ctx *client_ctx;
876 struct mgmt_fe_client_session *session;
877
878 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
879 if (!client_ctx)
880 return;
881
882 FOREACH_SESSION_IN_LIST (client_ctx, session)
883 mgmt_fe_destroy_client_session(lib_hndl, session->client_id);
884 }
885
886 /*
887 * Send UN/LOCK_DS_REQ to MGMTD for a specific Datastore DS.
888 */
889 enum mgmt_result mgmt_fe_lock_ds(uintptr_t lib_hndl, uintptr_t session_id,
890 uint64_t req_id, Mgmtd__DatastoreId ds_id,
891 bool lock_ds)
892 {
893 struct mgmt_fe_client_ctx *client_ctx;
894 struct mgmt_fe_client_session *session;
895
896 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
897 if (!client_ctx)
898 return MGMTD_INVALID_PARAM;
899
900 session = (struct mgmt_fe_client_session *)session_id;
901 if (!session || session->client_ctx != client_ctx)
902 return MGMTD_INVALID_PARAM;
903
904 if (mgmt_fe_send_lockds_req(client_ctx, session, lock_ds, req_id,
905 ds_id)
906 != 0)
907 return MGMTD_INTERNAL_ERROR;
908
909 return MGMTD_SUCCESS;
910 }
911
912 /*
913 * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
914 */
915 enum mgmt_result
916 mgmt_fe_set_config_data(uintptr_t lib_hndl, uintptr_t session_id,
917 uint64_t req_id, Mgmtd__DatastoreId ds_id,
918 Mgmtd__YangCfgDataReq **config_req, int num_reqs,
919 bool implicit_commit, Mgmtd__DatastoreId dst_ds_id)
920 {
921 struct mgmt_fe_client_ctx *client_ctx;
922 struct mgmt_fe_client_session *session;
923
924 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
925 if (!client_ctx)
926 return MGMTD_INVALID_PARAM;
927
928 session = (struct mgmt_fe_client_session *)session_id;
929 if (!session || session->client_ctx != client_ctx)
930 return MGMTD_INVALID_PARAM;
931
932 if (mgmt_fe_send_setcfg_req(client_ctx, session, req_id, ds_id,
933 config_req, num_reqs, implicit_commit,
934 dst_ds_id)
935 != 0)
936 return MGMTD_INTERNAL_ERROR;
937
938 return MGMTD_SUCCESS;
939 }
940
941 /*
942 * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
943 */
944 enum mgmt_result mgmt_fe_commit_config_data(uintptr_t lib_hndl,
945 uintptr_t session_id,
946 uint64_t req_id,
947 Mgmtd__DatastoreId src_ds_id,
948 Mgmtd__DatastoreId dst_ds_id,
949 bool validate_only, bool abort)
950 {
951 struct mgmt_fe_client_ctx *client_ctx;
952 struct mgmt_fe_client_session *session;
953
954 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
955 if (!client_ctx)
956 return MGMTD_INVALID_PARAM;
957
958 session = (struct mgmt_fe_client_session *)session_id;
959 if (!session || session->client_ctx != client_ctx)
960 return MGMTD_INVALID_PARAM;
961
962 if (mgmt_fe_send_commitcfg_req(client_ctx, session, req_id, src_ds_id,
963 dst_ds_id, validate_only, abort)
964 != 0)
965 return MGMTD_INTERNAL_ERROR;
966
967 return MGMTD_SUCCESS;
968 }
969
970 /*
971 * Send GET_CONFIG_REQ to MGMTD for one or more config data item(s).
972 */
973 enum mgmt_result
974 mgmt_fe_get_config_data(uintptr_t lib_hndl, uintptr_t session_id,
975 uint64_t req_id, Mgmtd__DatastoreId ds_id,
976 Mgmtd__YangGetDataReq * data_req[], int num_reqs)
977 {
978 struct mgmt_fe_client_ctx *client_ctx;
979 struct mgmt_fe_client_session *session;
980
981 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
982 if (!client_ctx)
983 return MGMTD_INVALID_PARAM;
984
985 session = (struct mgmt_fe_client_session *)session_id;
986 if (!session || session->client_ctx != client_ctx)
987 return MGMTD_INVALID_PARAM;
988
989 if (mgmt_fe_send_getcfg_req(client_ctx, session, req_id, ds_id,
990 data_req, num_reqs)
991 != 0)
992 return MGMTD_INTERNAL_ERROR;
993
994 return MGMTD_SUCCESS;
995 }
996
997 /*
998 * Send GET_DATA_REQ to MGMTD for one or more config data item(s).
999 */
1000 enum mgmt_result mgmt_fe_get_data(uintptr_t lib_hndl, uintptr_t session_id,
1001 uint64_t req_id, Mgmtd__DatastoreId ds_id,
1002 Mgmtd__YangGetDataReq * data_req[],
1003 int num_reqs)
1004 {
1005 struct mgmt_fe_client_ctx *client_ctx;
1006 struct mgmt_fe_client_session *session;
1007
1008 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
1009 if (!client_ctx)
1010 return MGMTD_INVALID_PARAM;
1011
1012 session = (struct mgmt_fe_client_session *)session_id;
1013 if (!session || session->client_ctx != client_ctx)
1014 return MGMTD_INVALID_PARAM;
1015
1016 if (mgmt_fe_send_getdata_req(client_ctx, session, req_id, ds_id,
1017 data_req, num_reqs)
1018 != 0)
1019 return MGMTD_INTERNAL_ERROR;
1020
1021 return MGMTD_SUCCESS;
1022 }
1023
1024 /*
1025 * Send NOTIFY_REGISTER_REQ to MGMTD daemon.
1026 */
1027 enum mgmt_result
1028 mgmt_fe_register_yang_notify(uintptr_t lib_hndl, uintptr_t session_id,
1029 uint64_t req_id, Mgmtd__DatastoreId ds_id,
1030 bool register_req,
1031 Mgmtd__YangDataXPath * data_req[],
1032 int num_reqs)
1033 {
1034 struct mgmt_fe_client_ctx *client_ctx;
1035 struct mgmt_fe_client_session *session;
1036
1037 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
1038 if (!client_ctx)
1039 return MGMTD_INVALID_PARAM;
1040
1041 session = (struct mgmt_fe_client_session *)session_id;
1042 if (!session || session->client_ctx != client_ctx)
1043 return MGMTD_INVALID_PARAM;
1044
1045 if (mgmt_fe_send_regnotify_req(client_ctx, session, req_id, ds_id,
1046 register_req, data_req, num_reqs)
1047 != 0)
1048 return MGMTD_INTERNAL_ERROR;
1049
1050 return MGMTD_SUCCESS;
1051 }
1052
1053 /*
1054 * Destroy library and cleanup everything.
1055 */
1056 void mgmt_fe_client_lib_destroy(uintptr_t lib_hndl)
1057 {
1058 struct mgmt_fe_client_ctx *client_ctx;
1059
1060 client_ctx = (struct mgmt_fe_client_ctx *)lib_hndl;
1061 assert(client_ctx);
1062
1063 MGMTD_FE_CLIENT_DBG("Destroying MGMTD Frontend Client '%s'",
1064 client_ctx->client_params.name);
1065
1066 mgmt_fe_server_disconnect(client_ctx, false);
1067
1068 mgmt_fe_destroy_client_sessions(lib_hndl);
1069
1070 THREAD_OFF(client_ctx->conn_retry_tmr);
1071 THREAD_OFF(client_ctx->conn_read_ev);
1072 THREAD_OFF(client_ctx->conn_write_ev);
1073 THREAD_OFF(client_ctx->conn_writes_on);
1074 THREAD_OFF(client_ctx->msg_proc_ev);
1075 mgmt_msg_destroy(&client_ctx->mstate);
1076 }