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