]> git.proxmox.com Git - mirror_frr.git/blob - mgmtd/mgmt_fe_adapter.c
Merge pull request #13060 from opensourcerouting/feature/allow_peering_with_127.0.0.1
[mirror_frr.git] / mgmtd / mgmt_fe_adapter.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * MGMTD Frontend Client Connection Adapter
4 *
5 * Copyright (C) 2021 Vmware, Inc.
6 * Pushpasis Sarkar <spushpasis@vmware.com>
7 */
8
9 #include <zebra.h>
10 #include "sockopt.h"
11 #include "network.h"
12 #include "libfrr.h"
13 #include "mgmt_fe_client.h"
14 #include "mgmt_msg.h"
15 #include "mgmt_pb.h"
16 #include "hash.h"
17 #include "jhash.h"
18 #include "mgmtd/mgmt.h"
19 #include "mgmtd/mgmt_memory.h"
20 #include "mgmtd/mgmt_fe_adapter.h"
21
22 #ifdef REDIRECT_DEBUG_TO_STDERR
23 #define MGMTD_FE_ADAPTER_DBG(fmt, ...) \
24 fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
25 #define MGMTD_FE_ADAPTER_ERR(fmt, ...) \
26 fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
27 #else /* REDIRECT_DEBUG_TO_STDERR */
28 #define MGMTD_FE_ADAPTER_DBG(fmt, ...) \
29 do { \
30 if (mgmt_debug_fe) \
31 zlog_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
32 } while (0)
33 #define MGMTD_FE_ADAPTER_ERR(fmt, ...) \
34 zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
35 #endif /* REDIRECT_DEBUG_TO_STDERR */
36
37 #define FOREACH_ADAPTER_IN_LIST(adapter) \
38 frr_each_safe (mgmt_fe_adapters, &mgmt_fe_adapters, (adapter))
39
40 enum mgmt_session_event {
41 MGMTD_FE_SESSION_CFG_TXN_CLNUP = 1,
42 MGMTD_FE_SESSION_SHOW_TXN_CLNUP,
43 };
44
45 struct mgmt_fe_session_ctx {
46 struct mgmt_fe_client_adapter *adapter;
47 uint64_t session_id;
48 uint64_t client_id;
49 uint64_t txn_id;
50 uint64_t cfg_txn_id;
51 uint8_t ds_write_locked[MGMTD_DS_MAX_ID];
52 uint8_t ds_read_locked[MGMTD_DS_MAX_ID];
53 uint8_t ds_locked_implict[MGMTD_DS_MAX_ID];
54 struct event *proc_cfg_txn_clnp;
55 struct event *proc_show_txn_clnp;
56
57 struct mgmt_fe_sessions_item list_linkage;
58 };
59
60 DECLARE_LIST(mgmt_fe_sessions, struct mgmt_fe_session_ctx, list_linkage);
61
62 #define FOREACH_SESSION_IN_LIST(adapter, session) \
63 frr_each_safe (mgmt_fe_sessions, &(adapter)->fe_sessions, (session))
64
65 static struct event_loop *mgmt_fe_adapter_tm;
66 static struct mgmt_master *mgmt_fe_adapter_mm;
67
68 static struct mgmt_fe_adapters_head mgmt_fe_adapters;
69
70 static struct hash *mgmt_fe_sessions;
71 static uint64_t mgmt_fe_next_session_id;
72
73 /* Forward declarations */
74 static void
75 mgmt_fe_adapter_register_event(struct mgmt_fe_client_adapter *adapter,
76 enum mgmt_fe_event event);
77 static void
78 mgmt_fe_adapter_disconnect(struct mgmt_fe_client_adapter *adapter);
79 static void
80 mgmt_fe_session_register_event(struct mgmt_fe_session_ctx *session,
81 enum mgmt_session_event event);
82
83 static int
84 mgmt_fe_session_write_lock_ds(Mgmtd__DatastoreId ds_id,
85 struct mgmt_ds_ctx *ds_ctx,
86 struct mgmt_fe_session_ctx *session)
87 {
88 if (!session->ds_write_locked[ds_id]) {
89 if (mgmt_ds_write_lock(ds_ctx) != 0) {
90 MGMTD_FE_ADAPTER_DBG(
91 "Failed to lock the DS %u for Sessn: %p from %s!",
92 ds_id, session, session->adapter->name);
93 return -1;
94 }
95
96 session->ds_write_locked[ds_id] = true;
97 MGMTD_FE_ADAPTER_DBG(
98 "Write-Locked the DS %u for Sessn: %p from %s!", ds_id,
99 session, session->adapter->name);
100 }
101
102 return 0;
103 }
104
105 static int
106 mgmt_fe_session_read_lock_ds(Mgmtd__DatastoreId ds_id,
107 struct mgmt_ds_ctx *ds_ctx,
108 struct mgmt_fe_session_ctx *session)
109 {
110 if (!session->ds_read_locked[ds_id]) {
111 if (mgmt_ds_read_lock(ds_ctx) != 0) {
112 MGMTD_FE_ADAPTER_DBG(
113 "Failed to lock the DS %u for Sessn: %p from %s!",
114 ds_id, session, session->adapter->name);
115 return -1;
116 }
117
118 session->ds_read_locked[ds_id] = true;
119 MGMTD_FE_ADAPTER_DBG(
120 "Read-Locked the DS %u for Sessn: %p from %s!", ds_id,
121 session, session->adapter->name);
122 }
123
124 return 0;
125 }
126
127 static int mgmt_fe_session_unlock_ds(Mgmtd__DatastoreId ds_id,
128 struct mgmt_ds_ctx *ds_ctx,
129 struct mgmt_fe_session_ctx *session,
130 bool unlock_write, bool unlock_read)
131 {
132 if (unlock_write && session->ds_write_locked[ds_id]) {
133 session->ds_write_locked[ds_id] = false;
134 session->ds_locked_implict[ds_id] = false;
135 if (mgmt_ds_unlock(ds_ctx) != 0) {
136 MGMTD_FE_ADAPTER_DBG(
137 "Failed to unlock the DS %u taken earlier by Sessn: %p from %s!",
138 ds_id, session, session->adapter->name);
139 return -1;
140 }
141
142 MGMTD_FE_ADAPTER_DBG(
143 "Unlocked DS %u write-locked earlier by Sessn: %p from %s",
144 ds_id, session, session->adapter->name);
145 } else if (unlock_read && session->ds_read_locked[ds_id]) {
146 session->ds_read_locked[ds_id] = false;
147 session->ds_locked_implict[ds_id] = false;
148 if (mgmt_ds_unlock(ds_ctx) != 0) {
149 MGMTD_FE_ADAPTER_DBG(
150 "Failed to unlock the DS %u taken earlier by Sessn: %p from %s!",
151 ds_id, session, session->adapter->name);
152 return -1;
153 }
154
155 MGMTD_FE_ADAPTER_DBG(
156 "Unlocked DS %u read-locked earlier by Sessn: %p from %s",
157 ds_id, session, session->adapter->name);
158 }
159
160 return 0;
161 }
162
163 static void
164 mgmt_fe_session_cfg_txn_cleanup(struct mgmt_fe_session_ctx *session)
165 {
166 Mgmtd__DatastoreId ds_id;
167 struct mgmt_ds_ctx *ds_ctx;
168
169 /*
170 * Ensure any uncommitted changes in Candidate DS
171 * is discarded.
172 */
173 mgmt_ds_copy_dss(mm->running_ds, mm->candidate_ds, false);
174
175 for (ds_id = 0; ds_id < MGMTD_DS_MAX_ID; ds_id++) {
176 ds_ctx = mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm, ds_id);
177 if (ds_ctx) {
178 if (session->ds_locked_implict[ds_id])
179 mgmt_fe_session_unlock_ds(
180 ds_id, ds_ctx, session, true, false);
181 }
182 }
183
184 /*
185 * Destroy the actual transaction created earlier.
186 */
187 if (session->cfg_txn_id != MGMTD_TXN_ID_NONE)
188 mgmt_destroy_txn(&session->cfg_txn_id);
189 }
190
191 static void
192 mgmt_fe_session_show_txn_cleanup(struct mgmt_fe_session_ctx *session)
193 {
194 Mgmtd__DatastoreId ds_id;
195 struct mgmt_ds_ctx *ds_ctx;
196
197 for (ds_id = 0; ds_id < MGMTD_DS_MAX_ID; ds_id++) {
198 ds_ctx = mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm, ds_id);
199 if (ds_ctx) {
200 mgmt_fe_session_unlock_ds(ds_id, ds_ctx, session,
201 false, true);
202 }
203 }
204
205 /*
206 * Destroy the transaction created recently.
207 */
208 if (session->txn_id != MGMTD_TXN_ID_NONE)
209 mgmt_destroy_txn(&session->txn_id);
210 }
211
212 static void
213 mgmt_fe_adapter_compute_set_cfg_timers(struct mgmt_setcfg_stats *setcfg_stats)
214 {
215 setcfg_stats->last_exec_tm = timeval_elapsed(setcfg_stats->last_end,
216 setcfg_stats->last_start);
217 if (setcfg_stats->last_exec_tm > setcfg_stats->max_tm)
218 setcfg_stats->max_tm = setcfg_stats->last_exec_tm;
219
220 if (setcfg_stats->last_exec_tm < setcfg_stats->min_tm)
221 setcfg_stats->min_tm = setcfg_stats->last_exec_tm;
222
223 setcfg_stats->avg_tm =
224 (((setcfg_stats->avg_tm * (setcfg_stats->set_cfg_count - 1))
225 + setcfg_stats->last_exec_tm)
226 / setcfg_stats->set_cfg_count);
227 }
228
229 static void
230 mgmt_fe_session_compute_commit_timers(struct mgmt_commit_stats *cmt_stats)
231 {
232 cmt_stats->last_exec_tm =
233 timeval_elapsed(cmt_stats->last_end, cmt_stats->last_start);
234 if (cmt_stats->last_exec_tm > cmt_stats->max_tm) {
235 cmt_stats->max_tm = cmt_stats->last_exec_tm;
236 cmt_stats->max_batch_cnt = cmt_stats->last_batch_cnt;
237 }
238
239 if (cmt_stats->last_exec_tm < cmt_stats->min_tm) {
240 cmt_stats->min_tm = cmt_stats->last_exec_tm;
241 cmt_stats->min_batch_cnt = cmt_stats->last_batch_cnt;
242 }
243 }
244
245 static void mgmt_fe_cleanup_session(struct mgmt_fe_session_ctx **session)
246 {
247 if ((*session)->adapter) {
248 mgmt_fe_session_cfg_txn_cleanup((*session));
249 mgmt_fe_session_show_txn_cleanup((*session));
250 mgmt_fe_session_unlock_ds(MGMTD_DS_CANDIDATE,
251 mgmt_fe_adapter_mm->candidate_ds,
252 *session, true, true);
253 mgmt_fe_session_unlock_ds(MGMTD_DS_RUNNING,
254 mgmt_fe_adapter_mm->running_ds,
255 *session, true, true);
256
257 mgmt_fe_sessions_del(&(*session)->adapter->fe_sessions,
258 *session);
259 mgmt_fe_adapter_unlock(&(*session)->adapter);
260 }
261
262 hash_release(mgmt_fe_sessions, *session);
263 XFREE(MTYPE_MGMTD_FE_SESSION, *session);
264 *session = NULL;
265 }
266
267 static struct mgmt_fe_session_ctx *
268 mgmt_fe_find_session_by_client_id(struct mgmt_fe_client_adapter *adapter,
269 uint64_t client_id)
270 {
271 struct mgmt_fe_session_ctx *session;
272
273 FOREACH_SESSION_IN_LIST (adapter, session) {
274 if (session->client_id == client_id)
275 return session;
276 }
277
278 return NULL;
279 }
280
281 static unsigned int mgmt_fe_session_hash_key(const void *data)
282 {
283 const struct mgmt_fe_session_ctx *session = data;
284
285 return jhash2((uint32_t *) &session->session_id,
286 sizeof(session->session_id) / sizeof(uint32_t), 0);
287 }
288
289 static bool mgmt_fe_session_hash_cmp(const void *d1, const void *d2)
290 {
291 const struct mgmt_fe_session_ctx *session1 = d1;
292 const struct mgmt_fe_session_ctx *session2 = d2;
293
294 return (session1->session_id == session2->session_id);
295 }
296
297 static void mgmt_fe_session_hash_free(void *data)
298 {
299 struct mgmt_fe_session_ctx *session = data;
300
301 mgmt_fe_cleanup_session(&session);
302 }
303
304 static void mgmt_fe_session_hash_destroy(void)
305 {
306 if (mgmt_fe_sessions == NULL)
307 return;
308
309 hash_clean(mgmt_fe_sessions,
310 mgmt_fe_session_hash_free);
311 hash_free(mgmt_fe_sessions);
312 mgmt_fe_sessions = NULL;
313 }
314
315 static inline struct mgmt_fe_session_ctx *
316 mgmt_session_id2ctx(uint64_t session_id)
317 {
318 struct mgmt_fe_session_ctx key = {0};
319 struct mgmt_fe_session_ctx *session;
320
321 if (!mgmt_fe_sessions)
322 return NULL;
323
324 key.session_id = session_id;
325 session = hash_lookup(mgmt_fe_sessions, &key);
326
327 return session;
328 }
329
330 static struct mgmt_fe_session_ctx *
331 mgmt_fe_create_session(struct mgmt_fe_client_adapter *adapter,
332 uint64_t client_id)
333 {
334 struct mgmt_fe_session_ctx *session;
335
336 session = mgmt_fe_find_session_by_client_id(adapter, client_id);
337 if (session)
338 mgmt_fe_cleanup_session(&session);
339
340 session = XCALLOC(MTYPE_MGMTD_FE_SESSION,
341 sizeof(struct mgmt_fe_session_ctx));
342 assert(session);
343 session->client_id = client_id;
344 session->adapter = adapter;
345 session->txn_id = MGMTD_TXN_ID_NONE;
346 session->cfg_txn_id = MGMTD_TXN_ID_NONE;
347 mgmt_fe_adapter_lock(adapter);
348 mgmt_fe_sessions_add_tail(&adapter->fe_sessions, session);
349 if (!mgmt_fe_next_session_id)
350 mgmt_fe_next_session_id++;
351 session->session_id = mgmt_fe_next_session_id++;
352 hash_get(mgmt_fe_sessions, session, hash_alloc_intern);
353
354 return session;
355 }
356
357 static void
358 mgmt_fe_cleanup_sessions(struct mgmt_fe_client_adapter *adapter)
359 {
360 struct mgmt_fe_session_ctx *session;
361
362 FOREACH_SESSION_IN_LIST (adapter, session)
363 mgmt_fe_cleanup_session(&session);
364 }
365
366 static inline void
367 mgmt_fe_adapter_sched_msg_write(struct mgmt_fe_client_adapter *adapter)
368 {
369 if (!CHECK_FLAG(adapter->flags, MGMTD_FE_ADAPTER_FLAGS_WRITES_OFF))
370 mgmt_fe_adapter_register_event(adapter,
371 MGMTD_FE_CONN_WRITE);
372 }
373
374 static inline void
375 mgmt_fe_adapter_writes_on(struct mgmt_fe_client_adapter *adapter)
376 {
377 MGMTD_FE_ADAPTER_DBG("Resume writing msgs for '%s'", adapter->name);
378 UNSET_FLAG(adapter->flags, MGMTD_FE_ADAPTER_FLAGS_WRITES_OFF);
379 mgmt_fe_adapter_sched_msg_write(adapter);
380 }
381
382 static inline void
383 mgmt_fe_adapter_writes_off(struct mgmt_fe_client_adapter *adapter)
384 {
385 SET_FLAG(adapter->flags, MGMTD_FE_ADAPTER_FLAGS_WRITES_OFF);
386 MGMTD_FE_ADAPTER_DBG("Paused writing msgs for '%s'", adapter->name);
387 }
388
389 static int
390 mgmt_fe_adapter_send_msg(struct mgmt_fe_client_adapter *adapter,
391 Mgmtd__FeMessage *fe_msg)
392 {
393 if (adapter->conn_fd == -1) {
394 MGMTD_FE_ADAPTER_DBG("can't send message on closed connection");
395 return -1;
396 }
397
398 int rv = mgmt_msg_send_msg(
399 &adapter->mstate, fe_msg,
400 mgmtd__fe_message__get_packed_size(fe_msg),
401 (size_t(*)(void *, void *))mgmtd__fe_message__pack,
402 mgmt_debug_fe);
403 mgmt_fe_adapter_sched_msg_write(adapter);
404 return rv;
405 }
406
407 static int
408 mgmt_fe_send_session_reply(struct mgmt_fe_client_adapter *adapter,
409 struct mgmt_fe_session_ctx *session,
410 bool create, bool success)
411 {
412 Mgmtd__FeMessage fe_msg;
413 Mgmtd__FeSessionReply session_reply;
414
415 mgmtd__fe_session_reply__init(&session_reply);
416 session_reply.create = create;
417 if (create) {
418 session_reply.has_client_conn_id = 1;
419 session_reply.client_conn_id = session->client_id;
420 }
421 session_reply.session_id = session->session_id;
422 session_reply.success = success;
423
424 mgmtd__fe_message__init(&fe_msg);
425 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY;
426 fe_msg.session_reply = &session_reply;
427
428 MGMTD_FE_ADAPTER_DBG(
429 "Sending SESSION_REPLY message to MGMTD Frontend client '%s'",
430 adapter->name);
431
432 return mgmt_fe_adapter_send_msg(adapter, &fe_msg);
433 }
434
435 static int mgmt_fe_send_lockds_reply(struct mgmt_fe_session_ctx *session,
436 Mgmtd__DatastoreId ds_id,
437 uint64_t req_id, bool lock_ds,
438 bool success, const char *error_if_any)
439 {
440 Mgmtd__FeMessage fe_msg;
441 Mgmtd__FeLockDsReply lockds_reply;
442
443 assert(session->adapter);
444
445 mgmtd__fe_lock_ds_reply__init(&lockds_reply);
446 lockds_reply.session_id = session->session_id;
447 lockds_reply.ds_id = ds_id;
448 lockds_reply.req_id = req_id;
449 lockds_reply.lock = lock_ds;
450 lockds_reply.success = success;
451 if (error_if_any)
452 lockds_reply.error_if_any = (char *)error_if_any;
453
454 mgmtd__fe_message__init(&fe_msg);
455 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY;
456 fe_msg.lockds_reply = &lockds_reply;
457
458 MGMTD_FE_ADAPTER_DBG(
459 "Sending LOCK_DS_REPLY message to MGMTD Frontend client '%s'",
460 session->adapter->name);
461
462 return mgmt_fe_adapter_send_msg(session->adapter, &fe_msg);
463 }
464
465 static int mgmt_fe_send_setcfg_reply(struct mgmt_fe_session_ctx *session,
466 Mgmtd__DatastoreId ds_id,
467 uint64_t req_id, bool success,
468 const char *error_if_any,
469 bool implicit_commit)
470 {
471 Mgmtd__FeMessage fe_msg;
472 Mgmtd__FeSetConfigReply setcfg_reply;
473
474 assert(session->adapter);
475
476 if (implicit_commit && session->cfg_txn_id)
477 mgmt_fe_session_register_event(
478 session, MGMTD_FE_SESSION_CFG_TXN_CLNUP);
479
480 mgmtd__fe_set_config_reply__init(&setcfg_reply);
481 setcfg_reply.session_id = session->session_id;
482 setcfg_reply.ds_id = ds_id;
483 setcfg_reply.req_id = req_id;
484 setcfg_reply.success = success;
485 if (error_if_any)
486 setcfg_reply.error_if_any = (char *)error_if_any;
487
488 mgmtd__fe_message__init(&fe_msg);
489 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY;
490 fe_msg.setcfg_reply = &setcfg_reply;
491
492 MGMTD_FE_ADAPTER_DBG(
493 "Sending SET_CONFIG_REPLY message to MGMTD Frontend client '%s'",
494 session->adapter->name);
495
496 if (implicit_commit) {
497 if (mm->perf_stats_en)
498 gettimeofday(&session->adapter->cmt_stats.last_end, NULL);
499 mgmt_fe_session_compute_commit_timers(
500 &session->adapter->cmt_stats);
501 }
502
503 if (mm->perf_stats_en)
504 gettimeofday(&session->adapter->setcfg_stats.last_end, NULL);
505 mgmt_fe_adapter_compute_set_cfg_timers(&session->adapter->setcfg_stats);
506
507 return mgmt_fe_adapter_send_msg(session->adapter, &fe_msg);
508 }
509
510 static int mgmt_fe_send_commitcfg_reply(
511 struct mgmt_fe_session_ctx *session, Mgmtd__DatastoreId src_ds_id,
512 Mgmtd__DatastoreId dst_ds_id, uint64_t req_id, enum mgmt_result result,
513 bool validate_only, const char *error_if_any)
514 {
515 Mgmtd__FeMessage fe_msg;
516 Mgmtd__FeCommitConfigReply commcfg_reply;
517
518 assert(session->adapter);
519
520 mgmtd__fe_commit_config_reply__init(&commcfg_reply);
521 commcfg_reply.session_id = session->session_id;
522 commcfg_reply.src_ds_id = src_ds_id;
523 commcfg_reply.dst_ds_id = dst_ds_id;
524 commcfg_reply.req_id = req_id;
525 commcfg_reply.success =
526 (result == MGMTD_SUCCESS || result == MGMTD_NO_CFG_CHANGES)
527 ? true
528 : false;
529 commcfg_reply.validate_only = validate_only;
530 if (error_if_any)
531 commcfg_reply.error_if_any = (char *)error_if_any;
532
533 mgmtd__fe_message__init(&fe_msg);
534 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY;
535 fe_msg.commcfg_reply = &commcfg_reply;
536
537 MGMTD_FE_ADAPTER_DBG(
538 "Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'",
539 session->adapter->name);
540
541 /*
542 * Cleanup the CONFIG transaction associated with this session.
543 */
544 if (session->cfg_txn_id
545 && ((result == MGMTD_SUCCESS && !validate_only)
546 || (result == MGMTD_NO_CFG_CHANGES)))
547 mgmt_fe_session_register_event(
548 session, MGMTD_FE_SESSION_CFG_TXN_CLNUP);
549
550 if (mm->perf_stats_en)
551 gettimeofday(&session->adapter->cmt_stats.last_end, NULL);
552 mgmt_fe_session_compute_commit_timers(&session->adapter->cmt_stats);
553 return mgmt_fe_adapter_send_msg(session->adapter, &fe_msg);
554 }
555
556 static int mgmt_fe_send_getcfg_reply(struct mgmt_fe_session_ctx *session,
557 Mgmtd__DatastoreId ds_id,
558 uint64_t req_id, bool success,
559 Mgmtd__YangDataReply *data,
560 const char *error_if_any)
561 {
562 Mgmtd__FeMessage fe_msg;
563 Mgmtd__FeGetConfigReply getcfg_reply;
564
565 assert(session->adapter);
566
567 mgmtd__fe_get_config_reply__init(&getcfg_reply);
568 getcfg_reply.session_id = session->session_id;
569 getcfg_reply.ds_id = ds_id;
570 getcfg_reply.req_id = req_id;
571 getcfg_reply.success = success;
572 getcfg_reply.data = data;
573 if (error_if_any)
574 getcfg_reply.error_if_any = (char *)error_if_any;
575
576 mgmtd__fe_message__init(&fe_msg);
577 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REPLY;
578 fe_msg.getcfg_reply = &getcfg_reply;
579
580 MGMTD_FE_ADAPTER_DBG(
581 "Sending GET_CONFIG_REPLY message to MGMTD Frontend client '%s'",
582 session->adapter->name);
583
584 /*
585 * Cleanup the SHOW transaction associated with this session.
586 */
587 if (session->txn_id && (!success || (data && data->next_indx < 0)))
588 mgmt_fe_session_register_event(
589 session, MGMTD_FE_SESSION_SHOW_TXN_CLNUP);
590
591 return mgmt_fe_adapter_send_msg(session->adapter, &fe_msg);
592 }
593
594 static int mgmt_fe_send_getdata_reply(struct mgmt_fe_session_ctx *session,
595 Mgmtd__DatastoreId ds_id,
596 uint64_t req_id, bool success,
597 Mgmtd__YangDataReply *data,
598 const char *error_if_any)
599 {
600 Mgmtd__FeMessage fe_msg;
601 Mgmtd__FeGetDataReply getdata_reply;
602
603 assert(session->adapter);
604
605 mgmtd__fe_get_data_reply__init(&getdata_reply);
606 getdata_reply.session_id = session->session_id;
607 getdata_reply.ds_id = ds_id;
608 getdata_reply.req_id = req_id;
609 getdata_reply.success = success;
610 getdata_reply.data = data;
611 if (error_if_any)
612 getdata_reply.error_if_any = (char *)error_if_any;
613
614 mgmtd__fe_message__init(&fe_msg);
615 fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REPLY;
616 fe_msg.getdata_reply = &getdata_reply;
617
618 MGMTD_FE_ADAPTER_DBG(
619 "Sending GET_DATA_REPLY message to MGMTD Frontend client '%s'",
620 session->adapter->name);
621
622 /*
623 * Cleanup the SHOW transaction associated with this session.
624 */
625 if (session->txn_id && (!success || (data && data->next_indx < 0)))
626 mgmt_fe_session_register_event(
627 session, MGMTD_FE_SESSION_SHOW_TXN_CLNUP);
628
629 return mgmt_fe_adapter_send_msg(session->adapter, &fe_msg);
630 }
631
632 static void mgmt_fe_session_cfg_txn_clnup(struct event *thread)
633 {
634 struct mgmt_fe_session_ctx *session;
635
636 session = (struct mgmt_fe_session_ctx *)EVENT_ARG(thread);
637
638 mgmt_fe_session_cfg_txn_cleanup(session);
639 }
640
641 static void mgmt_fe_session_show_txn_clnup(struct event *thread)
642 {
643 struct mgmt_fe_session_ctx *session;
644
645 session = (struct mgmt_fe_session_ctx *)EVENT_ARG(thread);
646
647 mgmt_fe_session_show_txn_cleanup(session);
648 }
649
650 static void
651 mgmt_fe_session_register_event(struct mgmt_fe_session_ctx *session,
652 enum mgmt_session_event event)
653 {
654 struct timeval tv = {.tv_sec = 0,
655 .tv_usec = MGMTD_FE_MSG_PROC_DELAY_USEC};
656
657 switch (event) {
658 case MGMTD_FE_SESSION_CFG_TXN_CLNUP:
659 event_add_timer_tv(mgmt_fe_adapter_tm,
660 mgmt_fe_session_cfg_txn_clnup, session,
661 &tv, &session->proc_cfg_txn_clnp);
662 break;
663 case MGMTD_FE_SESSION_SHOW_TXN_CLNUP:
664 event_add_timer_tv(mgmt_fe_adapter_tm,
665 mgmt_fe_session_show_txn_clnup, session,
666 &tv, &session->proc_show_txn_clnp);
667 break;
668 }
669 }
670
671 static struct mgmt_fe_client_adapter *
672 mgmt_fe_find_adapter_by_fd(int conn_fd)
673 {
674 struct mgmt_fe_client_adapter *adapter;
675
676 FOREACH_ADAPTER_IN_LIST (adapter) {
677 if (adapter->conn_fd == conn_fd)
678 return adapter;
679 }
680
681 return NULL;
682 }
683
684 static struct mgmt_fe_client_adapter *
685 mgmt_fe_find_adapter_by_name(const char *name)
686 {
687 struct mgmt_fe_client_adapter *adapter;
688
689 FOREACH_ADAPTER_IN_LIST (adapter) {
690 if (!strncmp(adapter->name, name, sizeof(adapter->name)))
691 return adapter;
692 }
693
694 return NULL;
695 }
696
697 static void mgmt_fe_adapter_disconnect(struct mgmt_fe_client_adapter *adapter)
698 {
699 if (adapter->conn_fd >= 0) {
700 close(adapter->conn_fd);
701 adapter->conn_fd = -1;
702 }
703
704 /* TODO: notify about client disconnect for appropriate cleanup */
705 mgmt_fe_cleanup_sessions(adapter);
706 mgmt_fe_sessions_fini(&adapter->fe_sessions);
707 mgmt_fe_adapters_del(&mgmt_fe_adapters, adapter);
708
709 mgmt_fe_adapter_unlock(&adapter);
710 }
711
712 static void
713 mgmt_fe_adapter_cleanup_old_conn(struct mgmt_fe_client_adapter *adapter)
714 {
715 struct mgmt_fe_client_adapter *old;
716
717 FOREACH_ADAPTER_IN_LIST (old) {
718 if (old != adapter
719 && !strncmp(adapter->name, old->name, sizeof(adapter->name))) {
720 /*
721 * We have a Zombie lingering around
722 */
723 MGMTD_FE_ADAPTER_DBG(
724 "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!",
725 adapter->name, adapter->conn_fd, old->conn_fd);
726 mgmt_fe_adapter_disconnect(old);
727 }
728 }
729 }
730
731 static void
732 mgmt_fe_cleanup_adapters(void)
733 {
734 struct mgmt_fe_client_adapter *adapter;
735
736 FOREACH_ADAPTER_IN_LIST (adapter) {
737 mgmt_fe_cleanup_sessions(adapter);
738 mgmt_fe_adapter_unlock(&adapter);
739 }
740 }
741
742 static int
743 mgmt_fe_session_handle_lockds_req_msg(struct mgmt_fe_session_ctx *session,
744 Mgmtd__FeLockDsReq *lockds_req)
745 {
746 struct mgmt_ds_ctx *ds_ctx;
747
748 /*
749 * Next check first if the SET_CONFIG_REQ is for Candidate DS
750 * or not. Report failure if its not. MGMTD currently only
751 * supports editing the Candidate DS.
752 */
753 if (lockds_req->ds_id != MGMTD_DS_CANDIDATE) {
754 mgmt_fe_send_lockds_reply(
755 session, lockds_req->ds_id, lockds_req->req_id,
756 lockds_req->lock, false,
757 "Lock/Unlock on datastores other than Candidate DS not permitted!");
758 return -1;
759 }
760
761 ds_ctx =
762 mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm, lockds_req->ds_id);
763 if (!ds_ctx) {
764 mgmt_fe_send_lockds_reply(
765 session, lockds_req->ds_id, lockds_req->req_id,
766 lockds_req->lock, false,
767 "Failed to retrieve handle for DS!");
768 return -1;
769 }
770
771 if (lockds_req->lock) {
772 if (mgmt_fe_session_write_lock_ds(lockds_req->ds_id,
773 ds_ctx, session)
774 != 0) {
775 mgmt_fe_send_lockds_reply(
776 session, lockds_req->ds_id, lockds_req->req_id,
777 lockds_req->lock, false,
778 "Lock already taken on DS by another session!");
779 return -1;
780 }
781
782 session->ds_locked_implict[lockds_req->ds_id] = false;
783 } else {
784 if (!session->ds_write_locked[lockds_req->ds_id]) {
785 mgmt_fe_send_lockds_reply(
786 session, lockds_req->ds_id, lockds_req->req_id,
787 lockds_req->lock, false,
788 "Lock on DS was not taken by this session!");
789 return 0;
790 }
791
792 (void)mgmt_fe_session_unlock_ds(lockds_req->ds_id, ds_ctx,
793 session, true, false);
794 }
795
796 if (mgmt_fe_send_lockds_reply(session, lockds_req->ds_id,
797 lockds_req->req_id, lockds_req->lock,
798 true, NULL)
799 != 0) {
800 MGMTD_FE_ADAPTER_DBG(
801 "Failed to send LOCK_DS_REPLY for DS %u Sessn: %p from %s",
802 lockds_req->ds_id, session, session->adapter->name);
803 }
804
805 return 0;
806 }
807
808 static int
809 mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session,
810 Mgmtd__FeSetConfigReq *setcfg_req)
811 {
812 uint64_t cfg_session_id;
813 struct mgmt_ds_ctx *ds_ctx, *dst_ds_ctx;
814
815 if (mm->perf_stats_en)
816 gettimeofday(&session->adapter->setcfg_stats.last_start, NULL);
817
818 /*
819 * Next check first if the SET_CONFIG_REQ is for Candidate DS
820 * or not. Report failure if its not. MGMTD currently only
821 * supports editing the Candidate DS.
822 */
823 if (setcfg_req->ds_id != MGMTD_DS_CANDIDATE) {
824 mgmt_fe_send_setcfg_reply(
825 session, setcfg_req->ds_id, setcfg_req->req_id, false,
826 "Set-Config on datastores other than Candidate DS not permitted!",
827 setcfg_req->implicit_commit);
828 return 0;
829 }
830
831 /*
832 * Get the DS handle.
833 */
834 ds_ctx =
835 mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm, setcfg_req->ds_id);
836 if (!ds_ctx) {
837 mgmt_fe_send_setcfg_reply(
838 session, setcfg_req->ds_id, setcfg_req->req_id, false,
839 "No such DS exists!", setcfg_req->implicit_commit);
840 return 0;
841 }
842
843 if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) {
844 /*
845 * Check first if the current session can run a CONFIG
846 * transaction or not. Report failure if a CONFIG transaction
847 * from another session is already in progress.
848 */
849 cfg_session_id = mgmt_config_txn_in_progress();
850 if (cfg_session_id != MGMTD_SESSION_ID_NONE
851 && cfg_session_id != session->session_id) {
852 mgmt_fe_send_setcfg_reply(
853 session, setcfg_req->ds_id, setcfg_req->req_id,
854 false,
855 "Configuration already in-progress through a different user session!",
856 setcfg_req->implicit_commit);
857 goto mgmt_fe_sess_handle_setcfg_req_failed;
858 }
859
860
861 /*
862 * Try taking write-lock on the requested DS (if not already).
863 */
864 if (!session->ds_write_locked[setcfg_req->ds_id]) {
865 if (mgmt_fe_session_write_lock_ds(setcfg_req->ds_id,
866 ds_ctx, session)
867 != 0) {
868 mgmt_fe_send_setcfg_reply(
869 session, setcfg_req->ds_id,
870 setcfg_req->req_id, false,
871 "Failed to lock the DS!",
872 setcfg_req->implicit_commit);
873 goto mgmt_fe_sess_handle_setcfg_req_failed;
874 }
875
876 session->ds_locked_implict[setcfg_req->ds_id] = true;
877 }
878
879 /*
880 * Start a CONFIG Transaction (if not started already)
881 */
882 session->cfg_txn_id = mgmt_create_txn(session->session_id,
883 MGMTD_TXN_TYPE_CONFIG);
884 if (session->cfg_txn_id == MGMTD_SESSION_ID_NONE) {
885 mgmt_fe_send_setcfg_reply(
886 session, setcfg_req->ds_id, setcfg_req->req_id,
887 false,
888 "Failed to create a Configuration session!",
889 setcfg_req->implicit_commit);
890 goto mgmt_fe_sess_handle_setcfg_req_failed;
891 }
892
893 MGMTD_FE_ADAPTER_DBG(
894 "Created new Config Txn 0x%llx for session %p",
895 (unsigned long long)session->cfg_txn_id, session);
896 } else {
897 MGMTD_FE_ADAPTER_DBG(
898 "Config Txn 0x%llx for session %p already created",
899 (unsigned long long)session->cfg_txn_id, session);
900
901 if (setcfg_req->implicit_commit) {
902 /*
903 * In this scenario need to skip cleanup of the txn,
904 * so setting implicit commit to false.
905 */
906 mgmt_fe_send_setcfg_reply(
907 session, setcfg_req->ds_id, setcfg_req->req_id,
908 false,
909 "A Configuration transaction is already in progress!",
910 false);
911 return 0;
912 }
913 }
914
915 dst_ds_ctx = 0;
916 if (setcfg_req->implicit_commit) {
917 dst_ds_ctx = mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm,
918 setcfg_req->commit_ds_id);
919 if (!dst_ds_ctx) {
920 mgmt_fe_send_setcfg_reply(
921 session, setcfg_req->ds_id, setcfg_req->req_id,
922 false, "No such commit DS exists!",
923 setcfg_req->implicit_commit);
924 return 0;
925 }
926 }
927
928 /*
929 * Create the SETConfig request under the transaction.
930 */
931 if (mgmt_txn_send_set_config_req(
932 session->cfg_txn_id, setcfg_req->req_id, setcfg_req->ds_id,
933 ds_ctx, setcfg_req->data, setcfg_req->n_data,
934 setcfg_req->implicit_commit, setcfg_req->commit_ds_id,
935 dst_ds_ctx)
936 != 0) {
937 mgmt_fe_send_setcfg_reply(
938 session, setcfg_req->ds_id, setcfg_req->req_id, false,
939 "Request processing for SET-CONFIG failed!",
940 setcfg_req->implicit_commit);
941 goto mgmt_fe_sess_handle_setcfg_req_failed;
942 }
943
944 return 0;
945
946 mgmt_fe_sess_handle_setcfg_req_failed:
947
948 /*
949 * Delete transaction created recently.
950 */
951 if (session->cfg_txn_id != MGMTD_TXN_ID_NONE)
952 mgmt_destroy_txn(&session->cfg_txn_id);
953 if (ds_ctx && session->ds_write_locked[setcfg_req->ds_id])
954 mgmt_fe_session_unlock_ds(setcfg_req->ds_id, ds_ctx, session,
955 true, false);
956
957 return 0;
958 }
959
960 static int
961 mgmt_fe_session_handle_getcfg_req_msg(struct mgmt_fe_session_ctx *session,
962 Mgmtd__FeGetConfigReq *getcfg_req)
963 {
964 struct mgmt_ds_ctx *ds_ctx;
965
966 /*
967 * Get the DS handle.
968 */
969 ds_ctx =
970 mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm, getcfg_req->ds_id);
971 if (!ds_ctx) {
972 mgmt_fe_send_getcfg_reply(session, getcfg_req->ds_id,
973 getcfg_req->req_id, false, NULL,
974 "No such DS exists!");
975 return 0;
976 }
977
978 /*
979 * Next check first if the SET_CONFIG_REQ is for Candidate DS
980 * or not. Report failure if its not. MGMTD currently only
981 * supports editing the Candidate DS.
982 */
983 if (getcfg_req->ds_id != MGMTD_DS_CANDIDATE
984 && getcfg_req->ds_id != MGMTD_DS_RUNNING) {
985 mgmt_fe_send_getcfg_reply(
986 session, getcfg_req->ds_id, getcfg_req->req_id, false,
987 NULL,
988 "Get-Config on datastores other than Candidate or Running DS not permitted!");
989 return 0;
990 }
991
992 if (session->txn_id == MGMTD_TXN_ID_NONE) {
993 /*
994 * Try taking read-lock on the requested DS (if not already
995 * locked). If the DS has already been write-locked by a ongoing
996 * CONFIG transaction we may allow reading the contents of the
997 * same DS.
998 */
999 if (!session->ds_read_locked[getcfg_req->ds_id]
1000 && !session->ds_write_locked[getcfg_req->ds_id]) {
1001 if (mgmt_fe_session_read_lock_ds(getcfg_req->ds_id,
1002 ds_ctx, session)
1003 != 0) {
1004 mgmt_fe_send_getcfg_reply(
1005 session, getcfg_req->ds_id,
1006 getcfg_req->req_id, false, NULL,
1007 "Failed to lock the DS! Another session might have locked it!");
1008 goto mgmt_fe_sess_handle_getcfg_req_failed;
1009 }
1010
1011 session->ds_locked_implict[getcfg_req->ds_id] = true;
1012 }
1013
1014 /*
1015 * Start a SHOW Transaction (if not started already)
1016 */
1017 session->txn_id = mgmt_create_txn(session->session_id,
1018 MGMTD_TXN_TYPE_SHOW);
1019 if (session->txn_id == MGMTD_SESSION_ID_NONE) {
1020 mgmt_fe_send_getcfg_reply(
1021 session, getcfg_req->ds_id, getcfg_req->req_id,
1022 false, NULL,
1023 "Failed to create a Show transaction!");
1024 goto mgmt_fe_sess_handle_getcfg_req_failed;
1025 }
1026
1027 MGMTD_FE_ADAPTER_DBG(
1028 "Created new Show Txn 0x%llx for session %p",
1029 (unsigned long long)session->txn_id, session);
1030 } else {
1031 MGMTD_FE_ADAPTER_DBG(
1032 "Show Txn 0x%llx for session %p already created",
1033 (unsigned long long)session->txn_id, session);
1034 }
1035
1036 /*
1037 * Create a GETConfig request under the transaction.
1038 */
1039 if (mgmt_txn_send_get_config_req(session->txn_id, getcfg_req->req_id,
1040 getcfg_req->ds_id, ds_ctx,
1041 getcfg_req->data, getcfg_req->n_data)
1042 != 0) {
1043 mgmt_fe_send_getcfg_reply(
1044 session, getcfg_req->ds_id, getcfg_req->req_id, false,
1045 NULL, "Request processing for GET-CONFIG failed!");
1046 goto mgmt_fe_sess_handle_getcfg_req_failed;
1047 }
1048
1049 return 0;
1050
1051 mgmt_fe_sess_handle_getcfg_req_failed:
1052
1053 /*
1054 * Destroy the transaction created recently.
1055 */
1056 if (session->txn_id != MGMTD_TXN_ID_NONE)
1057 mgmt_destroy_txn(&session->txn_id);
1058 if (ds_ctx && session->ds_read_locked[getcfg_req->ds_id])
1059 mgmt_fe_session_unlock_ds(getcfg_req->ds_id, ds_ctx, session,
1060 false, true);
1061
1062 return -1;
1063 }
1064
1065 static int
1066 mgmt_fe_session_handle_getdata_req_msg(struct mgmt_fe_session_ctx *session,
1067 Mgmtd__FeGetDataReq *getdata_req)
1068 {
1069 struct mgmt_ds_ctx *ds_ctx;
1070
1071 /*
1072 * Get the DS handle.
1073 */
1074 ds_ctx = mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm,
1075 getdata_req->ds_id);
1076 if (!ds_ctx) {
1077 mgmt_fe_send_getdata_reply(session, getdata_req->ds_id,
1078 getdata_req->req_id, false, NULL,
1079 "No such DS exists!");
1080 return 0;
1081 }
1082
1083 if (session->txn_id == MGMTD_TXN_ID_NONE) {
1084 /*
1085 * Try taking read-lock on the requested DS (if not already
1086 * locked). If the DS has already been write-locked by a ongoing
1087 * CONFIG transaction we may allow reading the contents of the
1088 * same DS.
1089 */
1090 if (!session->ds_read_locked[getdata_req->ds_id]
1091 && !session->ds_write_locked[getdata_req->ds_id]) {
1092 if (mgmt_fe_session_read_lock_ds(getdata_req->ds_id,
1093 ds_ctx, session)
1094 != 0) {
1095 mgmt_fe_send_getdata_reply(
1096 session, getdata_req->ds_id,
1097 getdata_req->req_id, false, NULL,
1098 "Failed to lock the DS! Another session might have locked it!");
1099 goto mgmt_fe_sess_handle_getdata_req_failed;
1100 }
1101
1102 session->ds_locked_implict[getdata_req->ds_id] = true;
1103 }
1104
1105 /*
1106 * Start a SHOW Transaction (if not started already)
1107 */
1108 session->txn_id = mgmt_create_txn(session->session_id,
1109 MGMTD_TXN_TYPE_SHOW);
1110 if (session->txn_id == MGMTD_SESSION_ID_NONE) {
1111 mgmt_fe_send_getdata_reply(
1112 session, getdata_req->ds_id, getdata_req->req_id,
1113 false, NULL,
1114 "Failed to create a Show transaction!");
1115 goto mgmt_fe_sess_handle_getdata_req_failed;
1116 }
1117
1118 MGMTD_FE_ADAPTER_DBG(
1119 "Created new Show Txn 0x%llx for session %p",
1120 (unsigned long long)session->txn_id, session);
1121 } else {
1122 MGMTD_FE_ADAPTER_DBG(
1123 "Show Txn 0x%llx for session %p already created",
1124 (unsigned long long)session->txn_id, session);
1125 }
1126
1127 /*
1128 * Create a GETData request under the transaction.
1129 */
1130 if (mgmt_txn_send_get_data_req(session->txn_id, getdata_req->req_id,
1131 getdata_req->ds_id, ds_ctx,
1132 getdata_req->data, getdata_req->n_data)
1133 != 0) {
1134 mgmt_fe_send_getdata_reply(
1135 session, getdata_req->ds_id, getdata_req->req_id, false,
1136 NULL, "Request processing for GET-CONFIG failed!");
1137 goto mgmt_fe_sess_handle_getdata_req_failed;
1138 }
1139
1140 return 0;
1141
1142 mgmt_fe_sess_handle_getdata_req_failed:
1143
1144 /*
1145 * Destroy the transaction created recently.
1146 */
1147 if (session->txn_id != MGMTD_TXN_ID_NONE)
1148 mgmt_destroy_txn(&session->txn_id);
1149
1150 if (ds_ctx && session->ds_read_locked[getdata_req->ds_id])
1151 mgmt_fe_session_unlock_ds(getdata_req->ds_id, ds_ctx,
1152 session, false, true);
1153
1154 return -1;
1155 }
1156
1157 static int mgmt_fe_session_handle_commit_config_req_msg(
1158 struct mgmt_fe_session_ctx *session,
1159 Mgmtd__FeCommitConfigReq *commcfg_req)
1160 {
1161 struct mgmt_ds_ctx *src_ds_ctx, *dst_ds_ctx;
1162
1163 if (mm->perf_stats_en)
1164 gettimeofday(&session->adapter->cmt_stats.last_start, NULL);
1165 session->adapter->cmt_stats.commit_cnt++;
1166 /*
1167 * Get the source DS handle.
1168 */
1169 src_ds_ctx = mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm,
1170 commcfg_req->src_ds_id);
1171 if (!src_ds_ctx) {
1172 mgmt_fe_send_commitcfg_reply(
1173 session, commcfg_req->src_ds_id, commcfg_req->dst_ds_id,
1174 commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
1175 commcfg_req->validate_only,
1176 "No such source DS exists!");
1177 return 0;
1178 }
1179
1180 /*
1181 * Get the destination DS handle.
1182 */
1183 dst_ds_ctx = mgmt_ds_get_ctx_by_id(mgmt_fe_adapter_mm,
1184 commcfg_req->dst_ds_id);
1185 if (!dst_ds_ctx) {
1186 mgmt_fe_send_commitcfg_reply(
1187 session, commcfg_req->src_ds_id, commcfg_req->dst_ds_id,
1188 commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
1189 commcfg_req->validate_only,
1190 "No such destination DS exists!");
1191 return 0;
1192 }
1193
1194 /*
1195 * Next check first if the SET_CONFIG_REQ is for Candidate DS
1196 * or not. Report failure if its not. MGMTD currently only
1197 * supports editing the Candidate DS.
1198 */
1199 if (commcfg_req->dst_ds_id != MGMTD_DS_RUNNING) {
1200 mgmt_fe_send_commitcfg_reply(
1201 session, commcfg_req->src_ds_id, commcfg_req->dst_ds_id,
1202 commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
1203 commcfg_req->validate_only,
1204 "Set-Config on datastores other than Running DS not permitted!");
1205 return 0;
1206 }
1207
1208 if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) {
1209 /*
1210 * Start a CONFIG Transaction (if not started already)
1211 */
1212 session->cfg_txn_id = mgmt_create_txn(session->session_id,
1213 MGMTD_TXN_TYPE_CONFIG);
1214 if (session->cfg_txn_id == MGMTD_SESSION_ID_NONE) {
1215 mgmt_fe_send_commitcfg_reply(
1216 session, commcfg_req->src_ds_id,
1217 commcfg_req->dst_ds_id, commcfg_req->req_id,
1218 MGMTD_INTERNAL_ERROR,
1219 commcfg_req->validate_only,
1220 "Failed to create a Configuration session!");
1221 return 0;
1222 }
1223 MGMTD_FE_ADAPTER_DBG("Created txn %" PRIu64
1224 " for session %" PRIu64
1225 " for COMMIT-CFG-REQ",
1226 session->cfg_txn_id, session->session_id);
1227 }
1228
1229
1230 /*
1231 * Try taking write-lock on the destination DS (if not already).
1232 */
1233 if (!session->ds_write_locked[commcfg_req->dst_ds_id]) {
1234 if (mgmt_fe_session_write_lock_ds(commcfg_req->dst_ds_id,
1235 dst_ds_ctx, session)
1236 != 0) {
1237 mgmt_fe_send_commitcfg_reply(
1238 session, commcfg_req->src_ds_id,
1239 commcfg_req->dst_ds_id, commcfg_req->req_id,
1240 MGMTD_DS_LOCK_FAILED,
1241 commcfg_req->validate_only,
1242 "Failed to lock the destination DS!");
1243 return 0;
1244 }
1245
1246 session->ds_locked_implict[commcfg_req->dst_ds_id] = true;
1247 }
1248
1249 /*
1250 * Create COMMITConfig request under the transaction
1251 */
1252 if (mgmt_txn_send_commit_config_req(
1253 session->cfg_txn_id, commcfg_req->req_id,
1254 commcfg_req->src_ds_id, src_ds_ctx, commcfg_req->dst_ds_id,
1255 dst_ds_ctx, commcfg_req->validate_only, commcfg_req->abort,
1256 false)
1257 != 0) {
1258 mgmt_fe_send_commitcfg_reply(
1259 session, commcfg_req->src_ds_id, commcfg_req->dst_ds_id,
1260 commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
1261 commcfg_req->validate_only,
1262 "Request processing for COMMIT-CONFIG failed!");
1263 return 0;
1264 }
1265
1266 return 0;
1267 }
1268
1269 static int
1270 mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
1271 Mgmtd__FeMessage *fe_msg)
1272 {
1273 struct mgmt_fe_session_ctx *session;
1274
1275 /*
1276 * protobuf-c adds a max size enum with an internal, and changing by
1277 * version, name; cast to an int to avoid unhandled enum warnings
1278 */
1279 switch ((int)fe_msg->message_case) {
1280 case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ:
1281 MGMTD_FE_ADAPTER_DBG("Got Register Req Msg from '%s'",
1282 fe_msg->register_req->client_name);
1283
1284 if (strlen(fe_msg->register_req->client_name)) {
1285 strlcpy(adapter->name,
1286 fe_msg->register_req->client_name,
1287 sizeof(adapter->name));
1288 mgmt_fe_adapter_cleanup_old_conn(adapter);
1289 }
1290 break;
1291 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ:
1292 if (fe_msg->session_req->create
1293 && fe_msg->session_req->id_case
1294 == MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID) {
1295 MGMTD_FE_ADAPTER_DBG(
1296 "Got Session Create Req Msg for client-id %llu from '%s'",
1297 (unsigned long long)
1298 fe_msg->session_req->client_conn_id,
1299 adapter->name);
1300
1301 session = mgmt_fe_create_session(
1302 adapter, fe_msg->session_req->client_conn_id);
1303 mgmt_fe_send_session_reply(adapter, session, true,
1304 session ? true : false);
1305 } else if (
1306 !fe_msg->session_req->create
1307 && fe_msg->session_req->id_case
1308 == MGMTD__FE_SESSION_REQ__ID_SESSION_ID) {
1309 MGMTD_FE_ADAPTER_DBG(
1310 "Got Session Destroy Req Msg for session-id %llu from '%s'",
1311 (unsigned long long)
1312 fe_msg->session_req->session_id,
1313 adapter->name);
1314
1315 session = mgmt_session_id2ctx(
1316 fe_msg->session_req->session_id);
1317 mgmt_fe_send_session_reply(adapter, session, false,
1318 true);
1319 mgmt_fe_cleanup_session(&session);
1320 }
1321 break;
1322 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ:
1323 session = mgmt_session_id2ctx(
1324 fe_msg->lockds_req->session_id);
1325 MGMTD_FE_ADAPTER_DBG(
1326 "Got %sockDS Req Msg for DS:%d for session-id %llx from '%s'",
1327 fe_msg->lockds_req->lock ? "L" : "Unl",
1328 fe_msg->lockds_req->ds_id,
1329 (unsigned long long)fe_msg->lockds_req->session_id,
1330 adapter->name);
1331 mgmt_fe_session_handle_lockds_req_msg(
1332 session, fe_msg->lockds_req);
1333 break;
1334 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ:
1335 session = mgmt_session_id2ctx(
1336 fe_msg->setcfg_req->session_id);
1337 session->adapter->setcfg_stats.set_cfg_count++;
1338 MGMTD_FE_ADAPTER_DBG(
1339 "Got Set Config Req Msg (%d Xpaths, Implicit:%c) on DS:%d for session-id %llu from '%s'",
1340 (int)fe_msg->setcfg_req->n_data,
1341 fe_msg->setcfg_req->implicit_commit ? 'T':'F',
1342 fe_msg->setcfg_req->ds_id,
1343 (unsigned long long)fe_msg->setcfg_req->session_id,
1344 adapter->name);
1345
1346 mgmt_fe_session_handle_setcfg_req_msg(
1347 session, fe_msg->setcfg_req);
1348 break;
1349 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ:
1350 session = mgmt_session_id2ctx(
1351 fe_msg->commcfg_req->session_id);
1352 MGMTD_FE_ADAPTER_DBG(
1353 "Got Commit Config Req Msg for src-DS:%d dst-DS:%d (Abort:%c) on session-id %llu from '%s'",
1354 fe_msg->commcfg_req->src_ds_id,
1355 fe_msg->commcfg_req->dst_ds_id,
1356 fe_msg->commcfg_req->abort ? 'T':'F',
1357 (unsigned long long)fe_msg->commcfg_req->session_id,
1358 adapter->name);
1359 mgmt_fe_session_handle_commit_config_req_msg(
1360 session, fe_msg->commcfg_req);
1361 break;
1362 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REQ:
1363 session = mgmt_session_id2ctx(
1364 fe_msg->getcfg_req->session_id);
1365 MGMTD_FE_ADAPTER_DBG(
1366 "Got Get-Config Req Msg for DS:%d (xpaths: %d) on session-id %llu from '%s'",
1367 fe_msg->getcfg_req->ds_id,
1368 (int)fe_msg->getcfg_req->n_data,
1369 (unsigned long long)fe_msg->getcfg_req->session_id,
1370 adapter->name);
1371 mgmt_fe_session_handle_getcfg_req_msg(
1372 session, fe_msg->getcfg_req);
1373 break;
1374 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REQ:
1375 session = mgmt_session_id2ctx(
1376 fe_msg->getdata_req->session_id);
1377 MGMTD_FE_ADAPTER_DBG(
1378 "Got Get-Data Req Msg for DS:%d (xpaths: %d) on session-id %llu from '%s'",
1379 fe_msg->getdata_req->ds_id,
1380 (int)fe_msg->getdata_req->n_data,
1381 (unsigned long long)fe_msg->getdata_req->session_id,
1382 adapter->name);
1383 mgmt_fe_session_handle_getdata_req_msg(
1384 session, fe_msg->getdata_req);
1385 break;
1386 case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
1387 case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ:
1388 /*
1389 * TODO: Add handling code in future.
1390 */
1391 break;
1392 /*
1393 * NOTE: The following messages are always sent from MGMTD to
1394 * Frontend clients only and/or need not be handled on MGMTd.
1395 */
1396 case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY:
1397 case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY:
1398 case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY:
1399 case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY:
1400 case MGMTD__FE_MESSAGE__MESSAGE_GETCFG_REPLY:
1401 case MGMTD__FE_MESSAGE__MESSAGE_GETDATA_REPLY:
1402 case MGMTD__FE_MESSAGE__MESSAGE__NOT_SET:
1403 default:
1404 /*
1405 * A 'default' case is being added contrary to the
1406 * FRR code guidelines to take care of build
1407 * failures on certain build systems (courtesy of
1408 * the proto-c package).
1409 */
1410 break;
1411 }
1412
1413 return 0;
1414 }
1415
1416 static void mgmt_fe_adapter_process_msg(void *user_ctx, uint8_t *data,
1417 size_t len)
1418 {
1419 struct mgmt_fe_client_adapter *adapter = user_ctx;
1420 Mgmtd__FeMessage *fe_msg;
1421
1422 fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
1423 if (!fe_msg) {
1424 MGMTD_FE_ADAPTER_DBG(
1425 "Failed to decode %zu bytes for adapter: %s", len,
1426 adapter->name);
1427 return;
1428 }
1429 MGMTD_FE_ADAPTER_DBG(
1430 "Decoded %zu bytes of message: %u from adapter: %s", len,
1431 fe_msg->message_case, adapter->name);
1432 (void)mgmt_fe_adapter_handle_msg(adapter, fe_msg);
1433 mgmtd__fe_message__free_unpacked(fe_msg, NULL);
1434 }
1435
1436 static void mgmt_fe_adapter_proc_msgbufs(struct event *thread)
1437 {
1438 struct mgmt_fe_client_adapter *adapter = EVENT_ARG(thread);
1439
1440 if (mgmt_msg_procbufs(&adapter->mstate, mgmt_fe_adapter_process_msg,
1441 adapter, mgmt_debug_fe))
1442 mgmt_fe_adapter_register_event(adapter, MGMTD_FE_PROC_MSG);
1443 }
1444
1445 static void mgmt_fe_adapter_read(struct event *thread)
1446 {
1447 struct mgmt_fe_client_adapter *adapter = EVENT_ARG(thread);
1448 enum mgmt_msg_rsched rv;
1449
1450 rv = mgmt_msg_read(&adapter->mstate, adapter->conn_fd, mgmt_debug_fe);
1451 if (rv == MSR_DISCONNECT) {
1452 mgmt_fe_adapter_disconnect(adapter);
1453 return;
1454 }
1455 if (rv == MSR_SCHED_BOTH)
1456 mgmt_fe_adapter_register_event(adapter, MGMTD_FE_PROC_MSG);
1457 mgmt_fe_adapter_register_event(adapter, MGMTD_FE_CONN_READ);
1458 }
1459
1460 static void mgmt_fe_adapter_write(struct event *thread)
1461 {
1462 struct mgmt_fe_client_adapter *adapter = EVENT_ARG(thread);
1463 enum mgmt_msg_wsched rv;
1464
1465 rv = mgmt_msg_write(&adapter->mstate, adapter->conn_fd, mgmt_debug_fe);
1466 if (rv == MSW_SCHED_STREAM)
1467 mgmt_fe_adapter_register_event(adapter, MGMTD_FE_CONN_WRITE);
1468 else if (rv == MSW_DISCONNECT)
1469 mgmt_fe_adapter_disconnect(adapter);
1470 else if (rv == MSW_SCHED_WRITES_OFF) {
1471 mgmt_fe_adapter_writes_off(adapter);
1472 mgmt_fe_adapter_register_event(adapter,
1473 MGMTD_FE_CONN_WRITES_ON);
1474 } else
1475 assert(rv == MSW_SCHED_NONE);
1476 }
1477
1478 static void mgmt_fe_adapter_resume_writes(struct event *thread)
1479 {
1480 struct mgmt_fe_client_adapter *adapter;
1481
1482 adapter = (struct mgmt_fe_client_adapter *)EVENT_ARG(thread);
1483 assert(adapter && adapter->conn_fd != -1);
1484
1485 mgmt_fe_adapter_writes_on(adapter);
1486 }
1487
1488 static void
1489 mgmt_fe_adapter_register_event(struct mgmt_fe_client_adapter *adapter,
1490 enum mgmt_fe_event event)
1491 {
1492 struct timeval tv = {0};
1493
1494 switch (event) {
1495 case MGMTD_FE_CONN_READ:
1496 event_add_read(mgmt_fe_adapter_tm, mgmt_fe_adapter_read,
1497 adapter, adapter->conn_fd, &adapter->conn_read_ev);
1498 break;
1499 case MGMTD_FE_CONN_WRITE:
1500 event_add_write(mgmt_fe_adapter_tm,
1501 mgmt_fe_adapter_write, adapter,
1502 adapter->conn_fd, &adapter->conn_write_ev);
1503 break;
1504 case MGMTD_FE_PROC_MSG:
1505 tv.tv_usec = MGMTD_FE_MSG_PROC_DELAY_USEC;
1506 event_add_timer_tv(mgmt_fe_adapter_tm,
1507 mgmt_fe_adapter_proc_msgbufs, adapter,
1508 &tv, &adapter->proc_msg_ev);
1509 break;
1510 case MGMTD_FE_CONN_WRITES_ON:
1511 event_add_timer_msec(mgmt_fe_adapter_tm,
1512 mgmt_fe_adapter_resume_writes, adapter,
1513 MGMTD_FE_MSG_WRITE_DELAY_MSEC,
1514 &adapter->conn_writes_on);
1515 break;
1516 case MGMTD_FE_SERVER:
1517 assert(!"mgmt_fe_adapter_post_event() called incorrectly");
1518 break;
1519 }
1520 }
1521
1522 void mgmt_fe_adapter_lock(struct mgmt_fe_client_adapter *adapter)
1523 {
1524 adapter->refcount++;
1525 }
1526
1527 extern void
1528 mgmt_fe_adapter_unlock(struct mgmt_fe_client_adapter **adapter)
1529 {
1530 assert(*adapter && (*adapter)->refcount);
1531
1532 (*adapter)->refcount--;
1533 if (!(*adapter)->refcount) {
1534 mgmt_fe_adapters_del(&mgmt_fe_adapters, *adapter);
1535 EVENT_OFF((*adapter)->conn_read_ev);
1536 EVENT_OFF((*adapter)->conn_write_ev);
1537 EVENT_OFF((*adapter)->proc_msg_ev);
1538 EVENT_OFF((*adapter)->conn_writes_on);
1539 mgmt_msg_destroy(&(*adapter)->mstate);
1540 XFREE(MTYPE_MGMTD_FE_ADPATER, *adapter);
1541 }
1542
1543 *adapter = NULL;
1544 }
1545
1546 int mgmt_fe_adapter_init(struct event_loop *tm, struct mgmt_master *mm)
1547 {
1548 if (!mgmt_fe_adapter_tm) {
1549 mgmt_fe_adapter_tm = tm;
1550 mgmt_fe_adapter_mm = mm;
1551 mgmt_fe_adapters_init(&mgmt_fe_adapters);
1552
1553 assert(!mgmt_fe_sessions);
1554 mgmt_fe_sessions = hash_create(mgmt_fe_session_hash_key,
1555 mgmt_fe_session_hash_cmp,
1556 "MGMT Frontend Sessions");
1557 }
1558
1559 return 0;
1560 }
1561
1562 void mgmt_fe_adapter_destroy(void)
1563 {
1564 mgmt_fe_cleanup_adapters();
1565 mgmt_fe_session_hash_destroy();
1566 }
1567
1568 struct mgmt_fe_client_adapter *
1569 mgmt_fe_create_adapter(int conn_fd, union sockunion *from)
1570 {
1571 struct mgmt_fe_client_adapter *adapter = NULL;
1572
1573 adapter = mgmt_fe_find_adapter_by_fd(conn_fd);
1574 if (!adapter) {
1575 adapter = XCALLOC(MTYPE_MGMTD_FE_ADPATER,
1576 sizeof(struct mgmt_fe_client_adapter));
1577 assert(adapter);
1578
1579 adapter->conn_fd = conn_fd;
1580 memcpy(&adapter->conn_su, from, sizeof(adapter->conn_su));
1581 snprintf(adapter->name, sizeof(adapter->name), "Unknown-FD-%d",
1582 adapter->conn_fd);
1583 mgmt_fe_sessions_init(&adapter->fe_sessions);
1584
1585 mgmt_msg_init(&adapter->mstate, MGMTD_FE_MAX_NUM_MSG_PROC,
1586 MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN,
1587 "FE-adapter");
1588 mgmt_fe_adapter_lock(adapter);
1589
1590 mgmt_fe_adapter_register_event(adapter, MGMTD_FE_CONN_READ);
1591 mgmt_fe_adapters_add_tail(&mgmt_fe_adapters, adapter);
1592
1593 adapter->setcfg_stats.min_tm = ULONG_MAX;
1594 adapter->cmt_stats.min_tm = ULONG_MAX;
1595 MGMTD_FE_ADAPTER_DBG("Added new MGMTD Frontend adapter '%s'",
1596 adapter->name);
1597 }
1598
1599 /* Make client socket non-blocking. */
1600 set_nonblocking(adapter->conn_fd);
1601 setsockopt_so_sendbuf(adapter->conn_fd,
1602 MGMTD_SOCKET_FE_SEND_BUF_SIZE);
1603 setsockopt_so_recvbuf(adapter->conn_fd,
1604 MGMTD_SOCKET_FE_RECV_BUF_SIZE);
1605 return adapter;
1606 }
1607
1608 struct mgmt_fe_client_adapter *mgmt_fe_get_adapter(const char *name)
1609 {
1610 return mgmt_fe_find_adapter_by_name(name);
1611 }
1612
1613 int mgmt_fe_send_set_cfg_reply(uint64_t session_id, uint64_t txn_id,
1614 Mgmtd__DatastoreId ds_id, uint64_t req_id,
1615 enum mgmt_result result,
1616 const char *error_if_any,
1617 bool implicit_commit)
1618 {
1619 struct mgmt_fe_session_ctx *session;
1620
1621 session = mgmt_session_id2ctx(session_id);
1622 if (!session || session->cfg_txn_id != txn_id) {
1623 if (session)
1624 MGMTD_FE_ADAPTER_ERR(
1625 "Txn_id doesnot match, session txn is 0x%llx, current txn 0x%llx",
1626 (unsigned long long)session->cfg_txn_id,
1627 (unsigned long long)txn_id);
1628 return -1;
1629 }
1630
1631 return mgmt_fe_send_setcfg_reply(
1632 session, ds_id, req_id, result == MGMTD_SUCCESS ? true : false,
1633 error_if_any, implicit_commit);
1634 }
1635
1636 int mgmt_fe_send_commit_cfg_reply(uint64_t session_id, uint64_t txn_id,
1637 Mgmtd__DatastoreId src_ds_id,
1638 Mgmtd__DatastoreId dst_ds_id,
1639 uint64_t req_id, bool validate_only,
1640 enum mgmt_result result,
1641 const char *error_if_any)
1642 {
1643 struct mgmt_fe_session_ctx *session;
1644
1645 session = mgmt_session_id2ctx(session_id);
1646 if (!session || session->cfg_txn_id != txn_id)
1647 return -1;
1648
1649 return mgmt_fe_send_commitcfg_reply(session, src_ds_id, dst_ds_id,
1650 req_id, result, validate_only,
1651 error_if_any);
1652 }
1653
1654 int mgmt_fe_send_get_cfg_reply(uint64_t session_id, uint64_t txn_id,
1655 Mgmtd__DatastoreId ds_id, uint64_t req_id,
1656 enum mgmt_result result,
1657 Mgmtd__YangDataReply *data_resp,
1658 const char *error_if_any)
1659 {
1660 struct mgmt_fe_session_ctx *session;
1661
1662 session = mgmt_session_id2ctx(session_id);
1663 if (!session || session->txn_id != txn_id)
1664 return -1;
1665
1666 return mgmt_fe_send_getcfg_reply(session, ds_id, req_id,
1667 result == MGMTD_SUCCESS, data_resp,
1668 error_if_any);
1669 }
1670
1671 int mgmt_fe_send_get_data_reply(uint64_t session_id, uint64_t txn_id,
1672 Mgmtd__DatastoreId ds_id, uint64_t req_id,
1673 enum mgmt_result result,
1674 Mgmtd__YangDataReply *data_resp,
1675 const char *error_if_any)
1676 {
1677 struct mgmt_fe_session_ctx *session;
1678
1679 session = mgmt_session_id2ctx(session_id);
1680 if (!session || session->txn_id != txn_id)
1681 return -1;
1682
1683 return mgmt_fe_send_getdata_reply(session, ds_id, req_id,
1684 result == MGMTD_SUCCESS,
1685 data_resp, error_if_any);
1686 }
1687
1688 int mgmt_fe_send_data_notify(Mgmtd__DatastoreId ds_id,
1689 Mgmtd__YangData * data_resp[], int num_data)
1690 {
1691 /* struct mgmt_fe_session_ctx *session; */
1692
1693 return 0;
1694 }
1695
1696 struct mgmt_setcfg_stats *
1697 mgmt_fe_get_session_setcfg_stats(uint64_t session_id)
1698 {
1699 struct mgmt_fe_session_ctx *session;
1700
1701 session = mgmt_session_id2ctx(session_id);
1702 if (!session || !session->adapter)
1703 return NULL;
1704
1705 return &session->adapter->setcfg_stats;
1706 }
1707
1708 struct mgmt_commit_stats *
1709 mgmt_fe_get_session_commit_stats(uint64_t session_id)
1710 {
1711 struct mgmt_fe_session_ctx *session;
1712
1713 session = mgmt_session_id2ctx(session_id);
1714 if (!session || !session->adapter)
1715 return NULL;
1716
1717 return &session->adapter->cmt_stats;
1718 }
1719
1720 static void
1721 mgmt_fe_adapter_cmt_stats_write(struct vty *vty,
1722 struct mgmt_fe_client_adapter *adapter)
1723 {
1724 char buf[100] = {0};
1725
1726 if (!mm->perf_stats_en)
1727 return;
1728
1729 vty_out(vty, " Num-Commits: \t\t\t%lu\n",
1730 adapter->cmt_stats.commit_cnt);
1731 if (adapter->cmt_stats.commit_cnt > 0) {
1732 if (mm->perf_stats_en)
1733 vty_out(vty, " Max-Commit-Duration: \t\t%lu uSecs\n",
1734 adapter->cmt_stats.max_tm);
1735 vty_out(vty, " Max-Commit-Batch-Size: \t\t%lu\n",
1736 adapter->cmt_stats.max_batch_cnt);
1737 if (mm->perf_stats_en)
1738 vty_out(vty, " Min-Commit-Duration: \t\t%lu uSecs\n",
1739 adapter->cmt_stats.min_tm);
1740 vty_out(vty, " Min-Commit-Batch-Size: \t\t%lu\n",
1741 adapter->cmt_stats.min_batch_cnt);
1742 if (mm->perf_stats_en)
1743 vty_out(vty,
1744 " Last-Commit-Duration: \t\t%lu uSecs\n",
1745 adapter->cmt_stats.last_exec_tm);
1746 vty_out(vty, " Last-Commit-Batch-Size: \t\t%lu\n",
1747 adapter->cmt_stats.last_batch_cnt);
1748 vty_out(vty, " Last-Commit-CfgData-Reqs: \t\t%lu\n",
1749 adapter->cmt_stats.last_num_cfgdata_reqs);
1750 vty_out(vty, " Last-Commit-CfgApply-Reqs: \t\t%lu\n",
1751 adapter->cmt_stats.last_num_apply_reqs);
1752 if (mm->perf_stats_en) {
1753 vty_out(vty, " Last-Commit-Details:\n");
1754 vty_out(vty, " Commit Start: \t\t\t%s\n",
1755 mgmt_realtime_to_string(
1756 &adapter->cmt_stats.last_start, buf,
1757 sizeof(buf)));
1758 #ifdef MGMTD_LOCAL_VALIDATIONS_ENABLED
1759 vty_out(vty, " Config-Validate Start: \t\t%s\n",
1760 mgmt_realtime_to_string(
1761 &adapter->cmt_stats.validate_start, buf,
1762 sizeof(buf)));
1763 #endif
1764 vty_out(vty, " Prep-Config Start: \t\t%s\n",
1765 mgmt_realtime_to_string(
1766 &adapter->cmt_stats.prep_cfg_start, buf,
1767 sizeof(buf)));
1768 vty_out(vty, " Txn-Create Start: \t\t%s\n",
1769 mgmt_realtime_to_string(
1770 &adapter->cmt_stats.txn_create_start,
1771 buf, sizeof(buf)));
1772 vty_out(vty,
1773 #ifdef MGMTD_LOCAL_VALIDATIONS_ENABLED
1774 " Send-Config Start: \t\t%s\n",
1775 #else
1776 " Send-Config-Validate Start: \t%s\n",
1777 #endif
1778 mgmt_realtime_to_string(
1779 &adapter->cmt_stats.send_cfg_start, buf,
1780 sizeof(buf)));
1781 vty_out(vty, " Apply-Config Start: \t\t%s\n",
1782 mgmt_realtime_to_string(
1783 &adapter->cmt_stats.apply_cfg_start, buf,
1784 sizeof(buf)));
1785 vty_out(vty, " Apply-Config End: \t\t%s\n",
1786 mgmt_realtime_to_string(
1787 &adapter->cmt_stats.apply_cfg_end, buf,
1788 sizeof(buf)));
1789 vty_out(vty, " Txn-Delete Start: \t\t%s\n",
1790 mgmt_realtime_to_string(
1791 &adapter->cmt_stats.txn_del_start, buf,
1792 sizeof(buf)));
1793 vty_out(vty, " Commit End: \t\t\t%s\n",
1794 mgmt_realtime_to_string(
1795 &adapter->cmt_stats.last_end, buf,
1796 sizeof(buf)));
1797 }
1798 }
1799 }
1800
1801 static void
1802 mgmt_fe_adapter_setcfg_stats_write(struct vty *vty,
1803 struct mgmt_fe_client_adapter *adapter)
1804 {
1805 char buf[100] = {0};
1806
1807 if (!mm->perf_stats_en)
1808 return;
1809
1810 vty_out(vty, " Num-Set-Cfg: \t\t\t%lu\n",
1811 adapter->setcfg_stats.set_cfg_count);
1812 if (mm->perf_stats_en && adapter->setcfg_stats.set_cfg_count > 0) {
1813 vty_out(vty, " Max-Set-Cfg-Duration: \t\t%lu uSec\n",
1814 adapter->setcfg_stats.max_tm);
1815 vty_out(vty, " Min-Set-Cfg-Duration: \t\t%lu uSec\n",
1816 adapter->setcfg_stats.min_tm);
1817 vty_out(vty, " Avg-Set-Cfg-Duration: \t\t%lu uSec\n",
1818 adapter->setcfg_stats.avg_tm);
1819 vty_out(vty, " Last-Set-Cfg-Details:\n");
1820 vty_out(vty, " Set-Cfg Start: \t\t\t%s\n",
1821 mgmt_realtime_to_string(&adapter->setcfg_stats.last_start,
1822 buf, sizeof(buf)));
1823 vty_out(vty, " Set-Cfg End: \t\t\t%s\n",
1824 mgmt_realtime_to_string(&adapter->setcfg_stats.last_end,
1825 buf, sizeof(buf)));
1826 }
1827 }
1828
1829 void mgmt_fe_adapter_status_write(struct vty *vty, bool detail)
1830 {
1831 struct mgmt_fe_client_adapter *adapter;
1832 struct mgmt_fe_session_ctx *session;
1833 Mgmtd__DatastoreId ds_id;
1834 bool locked = false;
1835
1836 vty_out(vty, "MGMTD Frontend Adpaters\n");
1837
1838 FOREACH_ADAPTER_IN_LIST (adapter) {
1839 vty_out(vty, " Client: \t\t\t\t%s\n", adapter->name);
1840 vty_out(vty, " Conn-FD: \t\t\t\t%d\n", adapter->conn_fd);
1841 if (detail) {
1842 mgmt_fe_adapter_setcfg_stats_write(vty, adapter);
1843 mgmt_fe_adapter_cmt_stats_write(vty, adapter);
1844 }
1845 vty_out(vty, " Sessions\n");
1846 FOREACH_SESSION_IN_LIST (adapter, session) {
1847 vty_out(vty, " Session: \t\t\t\t%p\n", session);
1848 vty_out(vty, " Client-Id: \t\t\t%llu\n",
1849 (unsigned long long)session->client_id);
1850 vty_out(vty, " Session-Id: \t\t\t%llx\n",
1851 (unsigned long long)session->session_id);
1852 vty_out(vty, " DS-Locks:\n");
1853 FOREACH_MGMTD_DS_ID (ds_id) {
1854 if (session->ds_write_locked[ds_id]
1855 || session->ds_read_locked[ds_id]) {
1856 locked = true;
1857 vty_out(vty,
1858 " %s\t\t\t%s, %s\n",
1859 mgmt_ds_id2name(ds_id),
1860 session->ds_write_locked[ds_id]
1861 ? "Write"
1862 : "Read",
1863 session->ds_locked_implict[ds_id]
1864 ? "Implicit"
1865 : "Explicit");
1866 }
1867 }
1868 if (!locked)
1869 vty_out(vty, " None\n");
1870 }
1871 vty_out(vty, " Total-Sessions: \t\t\t%d\n",
1872 (int)mgmt_fe_sessions_count(&adapter->fe_sessions));
1873 vty_out(vty, " Msg-Recvd: \t\t\t\t%" PRIu64 "\n",
1874 adapter->mstate.nrxm);
1875 vty_out(vty, " Bytes-Recvd: \t\t\t%" PRIu64 "\n",
1876 adapter->mstate.nrxb);
1877 vty_out(vty, " Msg-Sent: \t\t\t\t%" PRIu64 "\n",
1878 adapter->mstate.ntxm);
1879 vty_out(vty, " Bytes-Sent: \t\t\t%" PRIu64 "\n",
1880 adapter->mstate.ntxb);
1881 }
1882 vty_out(vty, " Total: %d\n",
1883 (int)mgmt_fe_adapters_count(&mgmt_fe_adapters));
1884 }
1885
1886 void mgmt_fe_adapter_perf_measurement(struct vty *vty, bool config)
1887 {
1888 mm->perf_stats_en = config;
1889 }
1890
1891 void mgmt_fe_adapter_reset_perf_stats(struct vty *vty)
1892 {
1893 struct mgmt_fe_client_adapter *adapter;
1894 struct mgmt_fe_session_ctx *session;
1895
1896 FOREACH_ADAPTER_IN_LIST (adapter) {
1897 memset(&adapter->setcfg_stats, 0, sizeof(adapter->setcfg_stats));
1898 FOREACH_SESSION_IN_LIST (adapter, session) {
1899 memset(&adapter->cmt_stats, 0, sizeof(adapter->cmt_stats));
1900 }
1901 }
1902 }