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