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