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