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