Coverage Report

Created: 2025-08-03 06:36

/src/frr/lib/mgmt_fe_client.c
Line
Count
Source (jump to first uncovered line)
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 "compiler.h"
10
#include "debug.h"
11
#include "memory.h"
12
#include "libfrr.h"
13
#include "mgmt_fe_client.h"
14
#include "mgmt_msg.h"
15
#include "mgmt_pb.h"
16
#include "network.h"
17
#include "stream.h"
18
#include "sockopt.h"
19
20
#include "lib/mgmt_fe_client_clippy.c"
21
22
PREDECL_LIST(mgmt_sessions);
23
24
struct mgmt_fe_client_session {
25
  uint64_t client_id;  /* FE client identifies itself with this ID */
26
  uint64_t session_id; /* FE adapter identified session with this ID */
27
  struct mgmt_fe_client *client;
28
  uintptr_t user_ctx;
29
30
  struct mgmt_sessions_item list_linkage;
31
};
32
33
DECLARE_LIST(mgmt_sessions, struct mgmt_fe_client_session, list_linkage);
34
35
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_CLIENT, "frontend client");
36
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_CLIENT_NAME, "frontend client name");
37
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_SESSION, "frontend session");
38
39
struct mgmt_fe_client {
40
  struct msg_client client;
41
  char *name;
42
  struct mgmt_fe_client_cbs cbs;
43
  uintptr_t user_data;
44
  struct mgmt_sessions_head sessions;
45
};
46
47
#define FOREACH_SESSION_IN_LIST(client, session)                               \
48
0
  frr_each_safe (mgmt_sessions, &(client)->sessions, (session))
49
50
struct debug mgmt_dbg_fe_client = {0, "Management frontend client operations"};
51
52
53
static inline const char *dsid2name(Mgmtd__DatastoreId id)
54
0
{
55
0
  switch ((int)id) {
56
0
  case MGMTD_DS_NONE:
57
0
    return "none";
58
0
  case MGMTD_DS_RUNNING:
59
0
    return "running";
60
0
  case MGMTD_DS_CANDIDATE:
61
0
    return "candidate";
62
0
  case MGMTD_DS_OPERATIONAL:
63
0
    return "operational";
64
0
  default:
65
0
    return "unknown-datastore-id";
66
0
  }
67
0
}
68
69
static struct mgmt_fe_client_session *
70
mgmt_fe_find_session_by_client_id(struct mgmt_fe_client *client,
71
          uint64_t client_id)
72
0
{
73
0
  struct mgmt_fe_client_session *session;
74
75
0
  FOREACH_SESSION_IN_LIST (client, session) {
76
0
    if (session->client_id == client_id) {
77
0
      MGMTD_FE_CLIENT_DBG("Found session-id %" PRIu64
78
0
              " using client-id %" PRIu64,
79
0
              session->session_id, client_id);
80
0
      return session;
81
0
    }
82
0
  }
83
0
  MGMTD_FE_CLIENT_DBG("Session not found using client-id %" PRIu64,
84
0
          client_id);
85
0
  return NULL;
86
0
}
87
88
static struct mgmt_fe_client_session *
89
mgmt_fe_find_session_by_session_id(struct mgmt_fe_client *client,
90
           uint64_t session_id)
91
0
{
92
0
  struct mgmt_fe_client_session *session;
93
94
0
  FOREACH_SESSION_IN_LIST (client, session) {
95
0
    if (session->session_id == session_id) {
96
0
      MGMTD_FE_CLIENT_DBG(
97
0
        "Found session of client-id %" PRIu64
98
0
        " using session-id %" PRIu64,
99
0
        session->client_id, session_id);
100
0
      return session;
101
0
    }
102
0
  }
103
0
  MGMTD_FE_CLIENT_DBG("Session not found using session-id %" PRIu64,
104
0
          session_id);
105
0
  return NULL;
106
0
}
107
108
static int mgmt_fe_client_send_msg(struct mgmt_fe_client *client,
109
           Mgmtd__FeMessage *fe_msg,
110
           bool short_circuit_ok)
111
0
{
112
0
  return msg_conn_send_msg(
113
0
    &client->client.conn, MGMT_MSG_VERSION_PROTOBUF, fe_msg,
114
0
    mgmtd__fe_message__get_packed_size(fe_msg),
115
0
    (size_t(*)(void *, void *))mgmtd__fe_message__pack,
116
0
    short_circuit_ok);
117
0
}
118
119
static int mgmt_fe_send_register_req(struct mgmt_fe_client *client)
120
0
{
121
0
  Mgmtd__FeMessage fe_msg;
122
0
  Mgmtd__FeRegisterReq rgstr_req;
123
124
0
  mgmtd__fe_register_req__init(&rgstr_req);
125
0
  rgstr_req.client_name = client->name;
126
127
0
  mgmtd__fe_message__init(&fe_msg);
128
0
  fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ;
129
0
  fe_msg.register_req = &rgstr_req;
130
131
0
  MGMTD_FE_CLIENT_DBG(
132
0
    "Sending REGISTER_REQ message to MGMTD Frontend server");
133
134
0
  return mgmt_fe_client_send_msg(client, &fe_msg, true);
135
0
}
136
137
static int mgmt_fe_send_session_req(struct mgmt_fe_client *client,
138
            struct mgmt_fe_client_session *session,
139
            bool create)
140
0
{
141
0
  Mgmtd__FeMessage fe_msg;
142
0
  Mgmtd__FeSessionReq sess_req;
143
144
0
  mgmtd__fe_session_req__init(&sess_req);
145
0
  sess_req.create = create;
146
0
  if (create) {
147
0
    sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID;
148
0
    sess_req.client_conn_id = session->client_id;
149
0
  } else {
150
0
    sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_SESSION_ID;
151
0
    sess_req.session_id = session->session_id;
152
0
  }
153
154
0
  mgmtd__fe_message__init(&fe_msg);
155
0
  fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ;
156
0
  fe_msg.session_req = &sess_req;
157
158
0
  MGMTD_FE_CLIENT_DBG(
159
0
    "Sending SESSION_REQ %s message for client-id %" PRIu64,
160
0
    create ? "create" : "destroy", session->client_id);
161
162
0
  return mgmt_fe_client_send_msg(client, &fe_msg, true);
163
0
}
164
165
int mgmt_fe_send_lockds_req(struct mgmt_fe_client *client, uint64_t session_id,
166
          uint64_t req_id, Mgmtd__DatastoreId ds_id,
167
          bool lock, bool scok)
168
0
{
169
0
  (void)req_id;
170
0
  Mgmtd__FeMessage fe_msg;
171
0
  Mgmtd__FeLockDsReq lockds_req;
172
173
0
  mgmtd__fe_lock_ds_req__init(&lockds_req);
174
0
  lockds_req.session_id = session_id;
175
0
  lockds_req.req_id = req_id;
176
0
  lockds_req.ds_id = ds_id;
177
0
  lockds_req.lock = lock;
178
179
0
  mgmtd__fe_message__init(&fe_msg);
180
0
  fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ;
181
0
  fe_msg.lockds_req = &lockds_req;
182
183
0
  MGMTD_FE_CLIENT_DBG(
184
0
    "Sending LOCKDS_REQ (%sLOCK) message for DS:%s session-id %" PRIu64,
185
0
    lock ? "" : "UN", dsid2name(ds_id), session_id);
186
187
188
0
  return mgmt_fe_client_send_msg(client, &fe_msg, scok);
189
0
}
190
191
int mgmt_fe_send_setcfg_req(struct mgmt_fe_client *client, uint64_t session_id,
192
          uint64_t req_id, Mgmtd__DatastoreId ds_id,
193
          Mgmtd__YangCfgDataReq **data_req, int num_data_reqs,
194
          bool implicit_commit, Mgmtd__DatastoreId dst_ds_id)
195
0
{
196
0
  (void)req_id;
197
0
  Mgmtd__FeMessage fe_msg;
198
0
  Mgmtd__FeSetConfigReq setcfg_req;
199
200
0
  mgmtd__fe_set_config_req__init(&setcfg_req);
201
0
  setcfg_req.session_id = session_id;
202
0
  setcfg_req.ds_id = ds_id;
203
0
  setcfg_req.req_id = req_id;
204
0
  setcfg_req.data = data_req;
205
0
  setcfg_req.n_data = (size_t)num_data_reqs;
206
0
  setcfg_req.implicit_commit = implicit_commit;
207
0
  setcfg_req.commit_ds_id = dst_ds_id;
208
209
0
  mgmtd__fe_message__init(&fe_msg);
210
0
  fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ;
211
0
  fe_msg.setcfg_req = &setcfg_req;
212
213
0
  MGMTD_FE_CLIENT_DBG(
214
0
    "Sending SET_CONFIG_REQ message for DS:%s session-id %" PRIu64
215
0
    " (#xpaths:%d)",
216
0
    dsid2name(ds_id), session_id, num_data_reqs);
217
218
0
  return mgmt_fe_client_send_msg(client, &fe_msg, false);
219
0
}
220
221
int mgmt_fe_send_commitcfg_req(struct mgmt_fe_client *client,
222
             uint64_t session_id, uint64_t req_id,
223
             Mgmtd__DatastoreId src_ds_id,
224
             Mgmtd__DatastoreId dest_ds_id,
225
             bool validate_only, bool abort)
226
0
{
227
0
  (void)req_id;
228
0
  Mgmtd__FeMessage fe_msg;
229
0
  Mgmtd__FeCommitConfigReq commitcfg_req;
230
231
0
  mgmtd__fe_commit_config_req__init(&commitcfg_req);
232
0
  commitcfg_req.session_id = session_id;
233
0
  commitcfg_req.src_ds_id = src_ds_id;
234
0
  commitcfg_req.dst_ds_id = dest_ds_id;
235
0
  commitcfg_req.req_id = req_id;
236
0
  commitcfg_req.validate_only = validate_only;
237
0
  commitcfg_req.abort = abort;
238
239
0
  mgmtd__fe_message__init(&fe_msg);
240
0
  fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ;
241
0
  fe_msg.commcfg_req = &commitcfg_req;
242
243
0
  MGMTD_FE_CLIENT_DBG(
244
0
    "Sending COMMIT_CONFIG_REQ message for Src-DS:%s, Dst-DS:%s session-id %" PRIu64,
245
0
    dsid2name(src_ds_id), dsid2name(dest_ds_id), session_id);
246
247
0
  return mgmt_fe_client_send_msg(client, &fe_msg, false);
248
0
}
249
250
int mgmt_fe_send_get_req(struct mgmt_fe_client *client, uint64_t session_id,
251
       uint64_t req_id, bool is_config,
252
       Mgmtd__DatastoreId ds_id,
253
       Mgmtd__YangGetDataReq *data_req[], int num_data_reqs)
254
0
{
255
0
  (void)req_id;
256
0
  Mgmtd__FeMessage fe_msg;
257
0
  Mgmtd__FeGetReq getcfg_req;
258
259
0
  mgmtd__fe_get_req__init(&getcfg_req);
260
0
  getcfg_req.session_id = session_id;
261
0
  getcfg_req.config = is_config;
262
0
  getcfg_req.ds_id = ds_id;
263
0
  getcfg_req.req_id = req_id;
264
0
  getcfg_req.data = data_req;
265
0
  getcfg_req.n_data = (size_t)num_data_reqs;
266
267
0
  mgmtd__fe_message__init(&fe_msg);
268
0
  fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GET_REQ;
269
0
  fe_msg.get_req = &getcfg_req;
270
271
0
  MGMTD_FE_CLIENT_DBG("Sending GET_REQ (iscfg %d) message for DS:%s session-id %" PRIu64
272
0
          " (#xpaths:%d)",
273
0
          is_config, dsid2name(ds_id), session_id,
274
0
          num_data_reqs);
275
276
0
  return mgmt_fe_client_send_msg(client, &fe_msg, false);
277
0
}
278
279
int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client,
280
             uint64_t session_id, uint64_t req_id,
281
             Mgmtd__DatastoreId ds_id, bool register_req,
282
             Mgmtd__YangDataXPath *data_req[],
283
             int num_data_reqs)
284
0
{
285
0
  (void)req_id;
286
0
  Mgmtd__FeMessage fe_msg;
287
0
  Mgmtd__FeRegisterNotifyReq regntfy_req;
288
289
0
  mgmtd__fe_register_notify_req__init(&regntfy_req);
290
0
  regntfy_req.session_id = session_id;
291
0
  regntfy_req.ds_id = ds_id;
292
0
  regntfy_req.register_req = register_req;
293
0
  regntfy_req.data_xpath = data_req;
294
0
  regntfy_req.n_data_xpath = (size_t)num_data_reqs;
295
296
0
  mgmtd__fe_message__init(&fe_msg);
297
0
  fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ;
298
0
  fe_msg.regnotify_req = &regntfy_req;
299
300
0
  return mgmt_fe_client_send_msg(client, &fe_msg, false);
301
0
}
302
303
static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
304
             Mgmtd__FeMessage *fe_msg)
305
0
{
306
0
  struct mgmt_fe_client_session *session = NULL;
307
308
  /*
309
   * protobuf-c adds a max size enum with an internal, and changing by
310
   * version, name; cast to an int to avoid unhandled enum warnings
311
   */
312
0
  switch ((int)fe_msg->message_case) {
313
0
  case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY:
314
0
    if (fe_msg->session_reply->create &&
315
0
        fe_msg->session_reply->has_client_conn_id) {
316
0
      MGMTD_FE_CLIENT_DBG(
317
0
        "Got SESSION_REPLY (create) for client-id %" PRIu64
318
0
        " with session-id: %" PRIu64,
319
0
        fe_msg->session_reply->client_conn_id,
320
0
        fe_msg->session_reply->session_id);
321
322
0
      session = mgmt_fe_find_session_by_client_id(
323
0
        client, fe_msg->session_reply->client_conn_id);
324
325
0
      if (session && fe_msg->session_reply->success) {
326
0
        MGMTD_FE_CLIENT_DBG(
327
0
          "Session Created for client-id %" PRIu64,
328
0
          fe_msg->session_reply->client_conn_id);
329
0
        session->session_id =
330
0
          fe_msg->session_reply->session_id;
331
0
      } else {
332
0
        MGMTD_FE_CLIENT_ERR(
333
0
          "Session Create failed for client-id %" PRIu64,
334
0
          fe_msg->session_reply->client_conn_id);
335
0
      }
336
0
    } else if (!fe_msg->session_reply->create) {
337
0
      MGMTD_FE_CLIENT_DBG(
338
0
        "Got SESSION_REPLY (destroy) for session-id %" PRIu64,
339
0
        fe_msg->session_reply->session_id);
340
341
0
      session = mgmt_fe_find_session_by_session_id(
342
0
        client, fe_msg->session_req->session_id);
343
0
    }
344
345
    /* The session state may be deleted by the callback */
346
0
    if (session && session->client &&
347
0
        session->client->cbs.client_session_notify)
348
0
      (*session->client->cbs.client_session_notify)(
349
0
        client, client->user_data, session->client_id,
350
0
        fe_msg->session_reply->create,
351
0
        fe_msg->session_reply->success,
352
0
        fe_msg->session_reply->session_id,
353
0
        session->user_ctx);
354
0
    break;
355
0
  case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY:
356
0
    MGMTD_FE_CLIENT_DBG("Got LOCKDS_REPLY for session-id %" PRIu64,
357
0
            fe_msg->lockds_reply->session_id);
358
0
    session = mgmt_fe_find_session_by_session_id(
359
0
      client, fe_msg->lockds_reply->session_id);
360
361
0
    if (session && session->client &&
362
0
        session->client->cbs.lock_ds_notify)
363
0
      (*session->client->cbs.lock_ds_notify)(
364
0
        client, client->user_data, session->client_id,
365
0
        fe_msg->lockds_reply->session_id,
366
0
        session->user_ctx, fe_msg->lockds_reply->req_id,
367
0
        fe_msg->lockds_reply->lock,
368
0
        fe_msg->lockds_reply->success,
369
0
        fe_msg->lockds_reply->ds_id,
370
0
        fe_msg->lockds_reply->error_if_any);
371
0
    break;
372
0
  case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY:
373
0
    MGMTD_FE_CLIENT_DBG("Got SETCFG_REPLY for session-id %" PRIu64,
374
0
            fe_msg->setcfg_reply->session_id);
375
376
0
    session = mgmt_fe_find_session_by_session_id(
377
0
      client, fe_msg->setcfg_reply->session_id);
378
379
0
    if (session && session->client &&
380
0
        session->client->cbs.set_config_notify)
381
0
      (*session->client->cbs.set_config_notify)(
382
0
        client, client->user_data, session->client_id,
383
0
        fe_msg->setcfg_reply->session_id,
384
0
        session->user_ctx, fe_msg->setcfg_reply->req_id,
385
0
        fe_msg->setcfg_reply->success,
386
0
        fe_msg->setcfg_reply->ds_id,
387
0
        fe_msg->setcfg_reply->implicit_commit,
388
0
        fe_msg->setcfg_reply->error_if_any);
389
0
    break;
390
0
  case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY:
391
0
    MGMTD_FE_CLIENT_DBG("Got COMMCFG_REPLY for session-id %" PRIu64,
392
0
            fe_msg->commcfg_reply->session_id);
393
394
0
    session = mgmt_fe_find_session_by_session_id(
395
0
      client, fe_msg->commcfg_reply->session_id);
396
397
0
    if (session && session->client &&
398
0
        session->client->cbs.commit_config_notify)
399
0
      (*session->client->cbs.commit_config_notify)(
400
0
        client, client->user_data, session->client_id,
401
0
        fe_msg->commcfg_reply->session_id,
402
0
        session->user_ctx,
403
0
        fe_msg->commcfg_reply->req_id,
404
0
        fe_msg->commcfg_reply->success,
405
0
        fe_msg->commcfg_reply->src_ds_id,
406
0
        fe_msg->commcfg_reply->dst_ds_id,
407
0
        fe_msg->commcfg_reply->validate_only,
408
0
        fe_msg->commcfg_reply->error_if_any);
409
0
    break;
410
0
  case MGMTD__FE_MESSAGE__MESSAGE_GET_REPLY:
411
0
    MGMTD_FE_CLIENT_DBG("Got GET_REPLY for session-id %" PRIu64,
412
0
            fe_msg->get_reply->session_id);
413
414
0
    session =
415
0
      mgmt_fe_find_session_by_session_id(client,
416
0
                 fe_msg->get_reply
417
0
                   ->session_id);
418
419
0
    if (session && session->client &&
420
0
        session->client->cbs.get_data_notify)
421
0
      (*session->client->cbs.get_data_notify)(
422
0
        client, client->user_data, session->client_id,
423
0
        fe_msg->get_reply->session_id,
424
0
        session->user_ctx, fe_msg->get_reply->req_id,
425
0
        fe_msg->get_reply->success,
426
0
        fe_msg->get_reply->ds_id,
427
0
        fe_msg->get_reply->data
428
0
          ? fe_msg->get_reply->data->data
429
0
          : NULL,
430
0
        fe_msg->get_reply->data
431
0
          ? fe_msg->get_reply->data->n_data
432
0
          : 0,
433
0
        fe_msg->get_reply->data
434
0
          ? fe_msg->get_reply->data->next_indx
435
0
          : 0,
436
0
        fe_msg->get_reply->error_if_any);
437
0
    break;
438
0
  case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
439
0
  case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ:
440
    /*
441
     * TODO: Add handling code in future.
442
     */
443
0
    break;
444
  /*
445
   * NOTE: The following messages are always sent from Frontend
446
   * clients to MGMTd only and/or need not be handled here.
447
   */
448
0
  case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ:
449
0
  case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ:
450
0
  case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ:
451
0
  case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ:
452
0
  case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ:
453
0
  case MGMTD__FE_MESSAGE__MESSAGE_GET_REQ:
454
0
  case MGMTD__FE_MESSAGE__MESSAGE__NOT_SET:
455
0
  default:
456
    /*
457
     * A 'default' case is being added contrary to the
458
     * FRR code guidelines to take care of build
459
     * failures on certain build systems (courtesy of
460
     * the proto-c package).
461
     */
462
0
    break;
463
0
  }
464
465
0
  return 0;
466
0
}
467
468
static void mgmt_fe_client_process_msg(uint8_t version, uint8_t *data,
469
               size_t len, struct msg_conn *conn)
470
0
{
471
0
  struct mgmt_fe_client *client;
472
0
  struct msg_client *msg_client;
473
0
  Mgmtd__FeMessage *fe_msg;
474
475
0
  msg_client = container_of(conn, struct msg_client, conn);
476
0
  client = container_of(msg_client, struct mgmt_fe_client, client);
477
478
0
  fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
479
0
  if (!fe_msg) {
480
0
    MGMTD_FE_CLIENT_DBG("Failed to decode %zu bytes from server.",
481
0
            len);
482
0
    return;
483
0
  }
484
0
  MGMTD_FE_CLIENT_DBG(
485
0
    "Decoded %zu bytes of message(msg: %u/%u) from server", len,
486
0
    fe_msg->message_case, fe_msg->message_case);
487
0
  (void)mgmt_fe_client_handle_msg(client, fe_msg);
488
0
  mgmtd__fe_message__free_unpacked(fe_msg, NULL);
489
0
}
490
491
static int _notify_connect_disconnect(struct msg_client *msg_client,
492
              bool connected)
493
0
{
494
0
  struct mgmt_fe_client *client =
495
0
    container_of(msg_client, struct mgmt_fe_client, client);
496
0
  struct mgmt_fe_client_session *session;
497
0
  int ret;
498
499
  /* Send REGISTER_REQ message */
500
0
  if (connected) {
501
0
    if ((ret = mgmt_fe_send_register_req(client)) != 0)
502
0
      return ret;
503
0
  }
504
505
  /* Walk list of sessions for this FE client deleting them */
506
0
  if (!connected && mgmt_sessions_count(&client->sessions)) {
507
0
    MGMTD_FE_CLIENT_DBG("Cleaning up existing sessions");
508
509
0
    FOREACH_SESSION_IN_LIST (client, session) {
510
0
      assert(session->client);
511
512
      /* unlink from list first this avoids double free */
513
0
      mgmt_sessions_del(&client->sessions, session);
514
515
      /* notify FE client the session is being deleted */
516
0
      if (session->client->cbs.client_session_notify) {
517
0
        (*session->client->cbs.client_session_notify)(
518
0
          client, client->user_data,
519
0
          session->client_id, false, true,
520
0
          session->session_id, session->user_ctx);
521
0
      }
522
523
0
      XFREE(MTYPE_MGMTD_FE_SESSION, session);
524
0
    }
525
0
  }
526
527
  /* Notify FE client through registered callback (if any). */
528
0
  if (client->cbs.client_connect_notify)
529
0
    (void)(*client->cbs.client_connect_notify)(
530
0
      client, client->user_data, connected);
531
0
  return 0;
532
0
}
533
534
static int mgmt_fe_client_notify_connect(struct msg_client *client)
535
0
{
536
0
  return _notify_connect_disconnect(client, true);
537
0
}
538
539
static int mgmt_fe_client_notify_disconnect(struct msg_conn *conn)
540
0
{
541
0
  struct msg_client *client = container_of(conn, struct msg_client, conn);
542
543
0
  return _notify_connect_disconnect(client, false);
544
0
}
545
546
547
DEFPY(debug_mgmt_client_fe, debug_mgmt_client_fe_cmd,
548
      "[no] debug mgmt client frontend",
549
      NO_STR DEBUG_STR MGMTD_STR
550
      "client\n"
551
      "frontend\n")
552
0
{
553
0
  uint32_t mode = DEBUG_NODE2MODE(vty->node);
554
555
0
  DEBUG_MODE_SET(&mgmt_dbg_fe_client, mode, !no);
556
557
0
  return CMD_SUCCESS;
558
0
}
559
560
static void mgmt_debug_client_fe_set_all(uint32_t flags, bool set)
561
0
{
562
0
  DEBUG_FLAGS_SET(&mgmt_dbg_fe_client, flags, set);
563
0
}
564
565
static int mgmt_debug_fe_client_config_write(struct vty *vty)
566
0
{
567
0
  if (DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_CONF))
568
0
    vty_out(vty, "debug mgmt client frontend\n");
569
570
0
  return CMD_SUCCESS;
571
0
}
572
573
void mgmt_debug_fe_client_show_debug(struct vty *vty)
574
0
{
575
0
  if (MGMTD_DBG_FE_CLIENT_CHECK())
576
0
    vty_out(vty, "debug mgmt client frontend\n");
577
0
}
578
579
static struct debug_callbacks mgmt_dbg_fe_client_cbs = {
580
  .debug_set_all = mgmt_debug_client_fe_set_all};
581
582
static struct cmd_node mgmt_dbg_node = {
583
  .name = "mgmt client frontend",
584
  .node = DEBUG_NODE,
585
  .prompt = "",
586
  .config_write = mgmt_debug_fe_client_config_write,
587
};
588
589
/*
590
 * Initialize library and try connecting with MGMTD.
591
 */
592
struct mgmt_fe_client *mgmt_fe_client_create(const char *client_name,
593
               struct mgmt_fe_client_cbs *cbs,
594
               uintptr_t user_data,
595
               struct event_loop *event_loop)
596
0
{
597
0
  struct mgmt_fe_client *client =
598
0
    XCALLOC(MTYPE_MGMTD_FE_CLIENT, sizeof(*client));
599
600
0
  client->name = XSTRDUP(MTYPE_MGMTD_FE_CLIENT_NAME, client_name);
601
0
  client->user_data = user_data;
602
0
  if (cbs)
603
0
    client->cbs = *cbs;
604
605
0
  mgmt_sessions_init(&client->sessions);
606
607
0
  msg_client_init(&client->client, event_loop, MGMTD_FE_SERVER_PATH,
608
0
      mgmt_fe_client_notify_connect,
609
0
      mgmt_fe_client_notify_disconnect,
610
0
      mgmt_fe_client_process_msg, MGMTD_FE_MAX_NUM_MSG_PROC,
611
0
      MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN, true,
612
0
      "FE-client", MGMTD_DBG_FE_CLIENT_CHECK());
613
614
0
  MGMTD_FE_CLIENT_DBG("Initialized client '%s'", client_name);
615
616
0
  return client;
617
0
}
618
619
void mgmt_fe_client_lib_vty_init(void)
620
0
{
621
0
  debug_init(&mgmt_dbg_fe_client_cbs);
622
0
  install_node(&mgmt_dbg_node);
623
0
  install_element(ENABLE_NODE, &debug_mgmt_client_fe_cmd);
624
0
  install_element(CONFIG_NODE, &debug_mgmt_client_fe_cmd);
625
0
}
626
627
uint mgmt_fe_client_session_count(struct mgmt_fe_client *client)
628
0
{
629
0
  return mgmt_sessions_count(&client->sessions);
630
0
}
631
632
bool mgmt_fe_client_current_msg_short_circuit(struct mgmt_fe_client *client)
633
0
{
634
0
  return client->client.conn.is_short_circuit;
635
0
}
636
637
/*
638
 * Create a new Session for a Frontend Client connection.
639
 */
640
enum mgmt_result mgmt_fe_create_client_session(struct mgmt_fe_client *client,
641
                 uint64_t client_id,
642
                 uintptr_t user_ctx)
643
0
{
644
0
  struct mgmt_fe_client_session *session;
645
646
0
  session = XCALLOC(MTYPE_MGMTD_FE_SESSION,
647
0
        sizeof(struct mgmt_fe_client_session));
648
0
  assert(session);
649
0
  session->user_ctx = user_ctx;
650
0
  session->client_id = client_id;
651
0
  session->client = client;
652
0
  session->session_id = 0;
653
654
0
  mgmt_sessions_add_tail(&client->sessions, session);
655
656
0
  if (mgmt_fe_send_session_req(client, session, true) != 0) {
657
0
    XFREE(MTYPE_MGMTD_FE_SESSION, session);
658
0
    return MGMTD_INTERNAL_ERROR;
659
0
  }
660
661
0
  return MGMTD_SUCCESS;
662
0
}
663
664
/*
665
 * Delete an existing Session for a Frontend Client connection.
666
 */
667
enum mgmt_result mgmt_fe_destroy_client_session(struct mgmt_fe_client *client,
668
            uint64_t client_id)
669
0
{
670
0
  struct mgmt_fe_client_session *session;
671
672
0
  session = mgmt_fe_find_session_by_client_id(client, client_id);
673
0
  if (!session || session->client != client)
674
0
    return MGMTD_INVALID_PARAM;
675
676
0
  if (session->session_id &&
677
0
      mgmt_fe_send_session_req(client, session, false) != 0)
678
0
    MGMTD_FE_CLIENT_ERR(
679
0
      "Failed to send session destroy request for the session-id %" PRIu64,
680
0
      session->session_id);
681
682
0
  mgmt_sessions_del(&client->sessions, session);
683
0
  XFREE(MTYPE_MGMTD_FE_SESSION, session);
684
685
0
  return MGMTD_SUCCESS;
686
0
}
687
688
/*
689
 * Destroy library and cleanup everything.
690
 */
691
void mgmt_fe_client_destroy(struct mgmt_fe_client *client)
692
0
{
693
0
  struct mgmt_fe_client_session *session;
694
695
0
  MGMTD_FE_CLIENT_DBG("Destroying MGMTD Frontend Client '%s'",
696
0
          client->name);
697
698
0
  FOREACH_SESSION_IN_LIST (client, session)
699
0
    mgmt_fe_destroy_client_session(client, session->client_id);
700
701
0
  msg_client_cleanup(&client->client);
702
703
0
  XFREE(MTYPE_MGMTD_FE_CLIENT_NAME, client->name);
704
0
  XFREE(MTYPE_MGMTD_FE_CLIENT, client);
705
0
}