]>
Commit | Line | Data |
---|---|---|
7d65b7b7 CH |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * MGMTD Backend Client Connection Adapter | |
4 | * | |
5 | * Copyright (C) 2021 Vmware, Inc. | |
6 | * Pushpasis Sarkar <spushpasis@vmware.com> | |
99564edc | 7 | * Copyright (c) 2023, LabN Consulting, L.L.C. |
7d65b7b7 CH |
8 | */ |
9 | ||
10 | #include <zebra.h> | |
24a58196 | 11 | #include "frrevent.h" |
7d65b7b7 CH |
12 | #include "sockopt.h" |
13 | #include "network.h" | |
14 | #include "libfrr.h" | |
f82370b4 | 15 | #include "mgmt_msg.h" |
7d65b7b7 CH |
16 | #include "mgmt_pb.h" |
17 | #include "mgmtd/mgmt.h" | |
18 | #include "mgmtd/mgmt_memory.h" | |
19 | #include "mgmt_be_client.h" | |
20 | #include "mgmtd/mgmt_be_adapter.h" | |
21 | ||
cfa0facb | 22 | #define MGMTD_BE_ADAPTER_DBG(fmt, ...) \ |
08e8019c CH |
23 | DEBUGD(&mgmt_debug_be, "BE-ADAPTER: %s:" fmt, __func__, ##__VA_ARGS__) |
24 | #define MGMTD_BE_ADAPTER_ERR(fmt, ...) \ | |
25 | zlog_err("BE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__) | |
7d65b7b7 CH |
26 | |
27 | #define FOREACH_ADAPTER_IN_LIST(adapter) \ | |
28 | frr_each_safe (mgmt_be_adapters, &mgmt_be_adapters, (adapter)) | |
29 | ||
30 | /* | |
31 | * Static mapping of YANG XPath regular expressions and | |
32 | * the corresponding interested backend clients. | |
33 | * NOTE: Thiis is a static mapping defined by all MGMTD | |
34 | * backend client modules (for now, till we develop a | |
35 | * more dynamic way of creating and updating this map). | |
36 | * A running map is created by MGMTD in run-time to | |
37 | * handle real-time mapping of YANG xpaths to one or | |
38 | * more interested backend client adapters. | |
39 | * | |
40 | * Please see xpath_map_reg[] in lib/mgmt_be_client.c | |
41 | * for the actual map | |
42 | */ | |
0327be91 CH |
43 | struct mgmt_be_xpath_map_init { |
44 | const char *xpath_regexp; | |
45 | uint subscr_info[MGMTD_BE_CLIENT_ID_MAX]; | |
7d65b7b7 CH |
46 | }; |
47 | ||
0327be91 CH |
48 | struct mgmt_be_xpath_map { |
49 | char *xpath_regexp; | |
50 | uint subscr_info[MGMTD_BE_CLIENT_ID_MAX]; | |
51 | }; | |
52 | ||
53 | struct mgmt_be_client_xpath { | |
54 | const char *xpath; | |
55 | uint subscribed; | |
56 | }; | |
57 | ||
58 | struct mgmt_be_client_xpath_map { | |
59 | struct mgmt_be_client_xpath *xpaths; | |
60 | uint nxpaths; | |
7d65b7b7 CH |
61 | }; |
62 | ||
63 | struct mgmt_be_get_adapter_config_params { | |
64 | struct mgmt_be_client_adapter *adapter; | |
65 | struct nb_config_cbs *cfg_chgs; | |
66 | uint32_t seq; | |
67 | }; | |
68 | ||
69 | /* | |
70 | * Static mapping of YANG XPath regular expressions and | |
71 | * the corresponding interested backend clients. | |
72 | * NOTE: Thiis is a static mapping defined by all MGMTD | |
73 | * backend client modules (for now, till we develop a | |
74 | * more dynamic way of creating and updating this map). | |
75 | * A running map is created by MGMTD in run-time to | |
76 | * handle real-time mapping of YANG xpaths to one or | |
77 | * more interested backend client adapters. | |
78 | */ | |
0327be91 CH |
79 | static const struct mgmt_be_xpath_map_init mgmt_xpath_map_init[] = { |
80 | { | |
81 | .xpath_regexp = "/frr-vrf:lib/*", | |
82 | .subscr_info = | |
83 | { | |
84 | #if HAVE_STATICD | |
85 | [MGMTD_BE_CLIENT_ID_STATICD] = | |
86 | MGMT_SUBSCR_VALIDATE_CFG | | |
87 | MGMT_SUBSCR_NOTIFY_CFG, | |
88 | #endif | |
89 | }, | |
90 | }, | |
91 | { | |
92 | .xpath_regexp = "/frr-interface:lib/*", | |
93 | .subscr_info = | |
94 | { | |
7d65b7b7 | 95 | #if HAVE_STATICD |
0327be91 CH |
96 | [MGMTD_BE_CLIENT_ID_STATICD] = |
97 | MGMT_SUBSCR_VALIDATE_CFG | | |
98 | MGMT_SUBSCR_NOTIFY_CFG, | |
7d65b7b7 | 99 | #endif |
0327be91 CH |
100 | }, |
101 | }, | |
102 | ||
103 | { | |
104 | .xpath_regexp = | |
105 | "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/*", | |
106 | .subscr_info = | |
107 | { | |
7d65b7b7 | 108 | #if HAVE_STATICD |
0327be91 CH |
109 | [MGMTD_BE_CLIENT_ID_STATICD] = |
110 | MGMT_SUBSCR_VALIDATE_CFG | | |
111 | MGMT_SUBSCR_NOTIFY_CFG, | |
7d65b7b7 | 112 | #endif |
0327be91 CH |
113 | }, |
114 | }, | |
115 | }; | |
7d65b7b7 | 116 | |
0327be91 CH |
117 | |
118 | /* | |
119 | * Each client gets their own map, but also union all the strings into the | |
120 | * above map as well. | |
121 | */ | |
7d65b7b7 | 122 | #if HAVE_STATICD |
0327be91 CH |
123 | static struct mgmt_be_client_xpath staticd_xpaths[] = { |
124 | { | |
125 | .xpath = "/frr-vrf:lib/*", | |
126 | .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, | |
127 | }, | |
128 | { | |
129 | .xpath = "/frr-interface:lib/*", | |
130 | .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, | |
131 | }, | |
132 | { | |
133 | .xpath = | |
134 | "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/*", | |
135 | .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, | |
136 | }, | |
137 | }; | |
138 | #endif | |
139 | ||
140 | static struct mgmt_be_client_xpath_map | |
141 | mgmt_client_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { | |
142 | #ifdef HAVE_STATICD | |
143 | [MGMTD_BE_CLIENT_ID_STATICD] = {staticd_xpaths, | |
144 | array_size(staticd_xpaths)}, | |
7d65b7b7 | 145 | #endif |
7d65b7b7 CH |
146 | }; |
147 | ||
148 | #define MGMTD_BE_MAX_NUM_XPATH_MAP 256 | |
99564edc | 149 | |
0327be91 CH |
150 | /* We would like to have a better ADT than one with O(n) |
151 | comparisons */ | |
152 | static struct mgmt_be_xpath_map *mgmt_xpath_map; | |
153 | static uint mgmt_num_xpath_maps; | |
7d65b7b7 | 154 | |
99564edc CH |
155 | static struct event_loop *mgmt_loop; |
156 | static struct msg_server mgmt_be_server = {.fd = -1}; | |
7d65b7b7 CH |
157 | |
158 | static struct mgmt_be_adapters_head mgmt_be_adapters; | |
159 | ||
160 | static struct mgmt_be_client_adapter | |
161 | *mgmt_be_adapters_by_id[MGMTD_BE_CLIENT_ID_MAX]; | |
162 | ||
163 | /* Forward declarations */ | |
164 | static void | |
99564edc | 165 | mgmt_be_adapter_sched_init_event(struct mgmt_be_client_adapter *adapter); |
7d65b7b7 | 166 | |
0327be91 CH |
167 | static uint mgmt_be_get_subscr_for_xpath_and_client( |
168 | const char *xpath, enum mgmt_be_client_id client_id, uint subscr_mask); | |
169 | ||
7d65b7b7 CH |
170 | static struct mgmt_be_client_adapter * |
171 | mgmt_be_find_adapter_by_fd(int conn_fd) | |
172 | { | |
173 | struct mgmt_be_client_adapter *adapter; | |
174 | ||
175 | FOREACH_ADAPTER_IN_LIST (adapter) { | |
6dad9b53 | 176 | if (adapter->conn->fd == conn_fd) |
7d65b7b7 CH |
177 | return adapter; |
178 | } | |
179 | ||
180 | return NULL; | |
181 | } | |
182 | ||
183 | static struct mgmt_be_client_adapter * | |
184 | mgmt_be_find_adapter_by_name(const char *name) | |
185 | { | |
186 | struct mgmt_be_client_adapter *adapter; | |
187 | ||
188 | FOREACH_ADAPTER_IN_LIST (adapter) { | |
189 | if (!strncmp(adapter->name, name, sizeof(adapter->name))) | |
190 | return adapter; | |
191 | } | |
192 | ||
193 | return NULL; | |
194 | } | |
195 | ||
7d65b7b7 CH |
196 | static void mgmt_be_xpath_map_init(void) |
197 | { | |
0327be91 | 198 | uint i; |
7d65b7b7 CH |
199 | |
200 | MGMTD_BE_ADAPTER_DBG("Init XPath Maps"); | |
201 | ||
0327be91 CH |
202 | mgmt_num_xpath_maps = array_size(mgmt_xpath_map_init); |
203 | mgmt_xpath_map = | |
204 | calloc(1, sizeof(*mgmt_xpath_map) * mgmt_num_xpath_maps); | |
205 | for (i = 0; i < mgmt_num_xpath_maps; i++) { | |
7d65b7b7 | 206 | MGMTD_BE_ADAPTER_DBG(" - XPATH: '%s'", |
0327be91 CH |
207 | mgmt_xpath_map_init[i].xpath_regexp); |
208 | mgmt_xpath_map[i].xpath_regexp = XSTRDUP( | |
209 | MTYPE_MGMTD_XPATH, mgmt_xpath_map_init[i].xpath_regexp); | |
210 | memcpy(mgmt_xpath_map[i].subscr_info, | |
211 | mgmt_xpath_map_init[i].subscr_info, | |
212 | sizeof(mgmt_xpath_map_init[i].subscr_info)); | |
7d65b7b7 | 213 | } |
7d65b7b7 CH |
214 | MGMTD_BE_ADAPTER_DBG("Total XPath Maps: %u", mgmt_num_xpath_maps); |
215 | } | |
216 | ||
0327be91 CH |
217 | static void mgmt_be_xpath_map_cleanup(void) |
218 | { | |
219 | uint i; | |
220 | ||
221 | for (i = 0; i < mgmt_num_xpath_maps; i++) | |
222 | XFREE(MTYPE_MGMTD_XPATH, mgmt_xpath_map[i].xpath_regexp); | |
223 | free(mgmt_xpath_map); | |
224 | } | |
225 | ||
7d65b7b7 CH |
226 | static int mgmt_be_eval_regexp_match(const char *xpath_regexp, |
227 | const char *xpath) | |
228 | { | |
229 | int match_len = 0, re_indx = 0, xp_indx = 0; | |
230 | int rexp_len, xpath_len; | |
231 | bool match = true, re_wild = false, xp_wild = false; | |
232 | bool delim = false, enter_wild_match = false; | |
233 | char wild_delim = 0; | |
234 | ||
235 | rexp_len = strlen(xpath_regexp); | |
236 | xpath_len = strlen(xpath); | |
237 | ||
238 | /* | |
239 | * Remove the trailing wildcard from the regexp and Xpath. | |
240 | */ | |
241 | if (rexp_len && xpath_regexp[rexp_len-1] == '*') | |
242 | rexp_len--; | |
243 | if (xpath_len && xpath[xpath_len-1] == '*') | |
244 | xpath_len--; | |
245 | ||
246 | if (!rexp_len || !xpath_len) | |
247 | return 0; | |
248 | ||
249 | for (re_indx = 0, xp_indx = 0; | |
250 | match && re_indx < rexp_len && xp_indx < xpath_len;) { | |
251 | match = (xpath_regexp[re_indx] == xpath[xp_indx]); | |
252 | ||
253 | /* | |
254 | * Check if we need to enter wildcard matching. | |
255 | */ | |
256 | if (!enter_wild_match && !match && | |
257 | (xpath_regexp[re_indx] == '*' | |
258 | || xpath[xp_indx] == '*')) { | |
259 | /* | |
260 | * Found wildcard | |
261 | */ | |
262 | enter_wild_match = | |
263 | (xpath_regexp[re_indx-1] == '/' | |
264 | || xpath_regexp[re_indx-1] == '\'' | |
265 | || xpath[xp_indx-1] == '/' | |
266 | || xpath[xp_indx-1] == '\''); | |
267 | if (enter_wild_match) { | |
268 | if (xpath_regexp[re_indx] == '*') { | |
269 | /* | |
270 | * Begin RE wildcard match. | |
271 | */ | |
272 | re_wild = true; | |
273 | wild_delim = xpath_regexp[re_indx-1]; | |
274 | } else if (xpath[xp_indx] == '*') { | |
275 | /* | |
276 | * Begin XP wildcard match. | |
277 | */ | |
278 | xp_wild = true; | |
279 | wild_delim = xpath[xp_indx-1]; | |
280 | } | |
281 | } | |
282 | } | |
283 | ||
284 | /* | |
285 | * Check if we need to exit wildcard matching. | |
286 | */ | |
287 | if (enter_wild_match) { | |
288 | if (re_wild && xpath[xp_indx] == wild_delim) { | |
289 | /* | |
290 | * End RE wildcard matching. | |
291 | */ | |
292 | re_wild = false; | |
293 | if (re_indx < rexp_len-1) | |
294 | re_indx++; | |
295 | enter_wild_match = false; | |
296 | } else if (xp_wild | |
297 | && xpath_regexp[re_indx] == wild_delim) { | |
298 | /* | |
299 | * End XP wildcard matching. | |
300 | */ | |
301 | xp_wild = false; | |
302 | if (xp_indx < xpath_len-1) | |
303 | xp_indx++; | |
304 | enter_wild_match = false; | |
305 | } | |
306 | } | |
307 | ||
308 | match = (xp_wild || re_wild | |
309 | || xpath_regexp[re_indx] == xpath[xp_indx]); | |
310 | ||
311 | /* | |
312 | * Check if we found a delimiter in both the Xpaths | |
313 | */ | |
314 | if ((xpath_regexp[re_indx] == '/' | |
315 | && xpath[xp_indx] == '/') | |
316 | || (xpath_regexp[re_indx] == ']' | |
317 | && xpath[xp_indx] == ']') | |
318 | || (xpath_regexp[re_indx] == '[' | |
319 | && xpath[xp_indx] == '[')) { | |
320 | /* | |
321 | * Increment the match count if we have a | |
322 | * new delimiter. | |
323 | */ | |
324 | if (match && re_indx && xp_indx && !delim) | |
325 | match_len++; | |
326 | delim = true; | |
327 | } else { | |
328 | delim = false; | |
329 | } | |
330 | ||
331 | /* | |
332 | * Proceed to the next character in the RE/XP string as | |
333 | * necessary. | |
334 | */ | |
335 | if (!re_wild) | |
336 | re_indx++; | |
337 | if (!xp_wild) | |
338 | xp_indx++; | |
339 | } | |
340 | ||
341 | /* | |
342 | * If we finished matching and the last token was a full match | |
343 | * increment the match count appropriately. | |
344 | */ | |
345 | if (match && !delim && | |
346 | (xpath_regexp[re_indx] == '/' | |
347 | || xpath_regexp[re_indx] == ']')) | |
348 | match_len++; | |
349 | ||
350 | return match_len; | |
351 | } | |
352 | ||
e3cacd96 | 353 | static void mgmt_be_adapter_delete(struct mgmt_be_client_adapter *adapter) |
7d65b7b7 | 354 | { |
e3cacd96 | 355 | MGMTD_BE_ADAPTER_DBG("deleting client adapter '%s'", adapter->name); |
7d65b7b7 CH |
356 | |
357 | /* | |
99564edc | 358 | * Notify about disconnect for appropriate cleanup |
7d65b7b7 | 359 | */ |
74335ceb | 360 | mgmt_txn_notify_be_adapter_conn(adapter, false); |
7d65b7b7 CH |
361 | if (adapter->id < MGMTD_BE_CLIENT_ID_MAX) { |
362 | mgmt_be_adapters_by_id[adapter->id] = NULL; | |
363 | adapter->id = MGMTD_BE_CLIENT_ID_MAX; | |
364 | } | |
365 | ||
e3cacd96 | 366 | assert(adapter->refcount == 1); |
7d65b7b7 | 367 | mgmt_be_adapter_unlock(&adapter); |
e3cacd96 CH |
368 | } |
369 | ||
370 | static int mgmt_be_adapter_notify_disconnect(struct msg_conn *conn) | |
371 | { | |
372 | struct mgmt_be_client_adapter *adapter = conn->user; | |
373 | ||
374 | MGMTD_BE_ADAPTER_DBG("notify disconnect for client adapter '%s'", | |
375 | adapter->name); | |
376 | ||
377 | mgmt_be_adapter_delete(adapter); | |
99564edc CH |
378 | |
379 | return 0; | |
7d65b7b7 CH |
380 | } |
381 | ||
382 | static void | |
383 | mgmt_be_adapter_cleanup_old_conn(struct mgmt_be_client_adapter *adapter) | |
384 | { | |
385 | struct mgmt_be_client_adapter *old; | |
386 | ||
387 | FOREACH_ADAPTER_IN_LIST (old) { | |
83b78f43 | 388 | if (old != adapter && |
389 | !strncmp(adapter->name, old->name, sizeof(adapter->name))) { | |
7d65b7b7 CH |
390 | /* |
391 | * We have a Zombie lingering around | |
392 | */ | |
393 | MGMTD_BE_ADAPTER_DBG( | |
394 | "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!", | |
6dad9b53 CH |
395 | adapter->name, adapter->conn->fd, |
396 | old->conn->fd); | |
397 | /* this will/should delete old */ | |
398 | msg_conn_disconnect(old->conn, false); | |
7d65b7b7 CH |
399 | } |
400 | } | |
401 | } | |
402 | ||
9405278e CH |
403 | |
404 | static int mgmt_be_adapter_send_msg(struct mgmt_be_client_adapter *adapter, | |
405 | Mgmtd__BeMessage *be_msg) | |
406 | { | |
407 | return msg_conn_send_msg( | |
408 | adapter->conn, MGMT_MSG_VERSION_PROTOBUF, be_msg, | |
409 | mgmtd__be_message__get_packed_size(be_msg), | |
410 | (size_t(*)(void *, void *))mgmtd__be_message__pack, false); | |
411 | } | |
412 | ||
413 | static int mgmt_be_send_subscr_reply(struct mgmt_be_client_adapter *adapter, | |
414 | bool success) | |
415 | { | |
416 | Mgmtd__BeMessage be_msg; | |
417 | Mgmtd__BeSubscribeReply reply; | |
418 | ||
419 | mgmtd__be_subscribe_reply__init(&reply); | |
420 | reply.success = success; | |
421 | ||
422 | mgmtd__be_message__init(&be_msg); | |
423 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY; | |
424 | be_msg.subscr_reply = &reply; | |
425 | ||
426 | MGMTD_FE_CLIENT_DBG("Sending SUBSCR_REPLY client: %s sucess: %u", | |
427 | adapter->name, success); | |
428 | ||
429 | return mgmt_be_adapter_send_msg(adapter, &be_msg); | |
430 | } | |
431 | ||
7d65b7b7 CH |
432 | static int |
433 | mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter, | |
434 | Mgmtd__BeMessage *be_msg) | |
435 | { | |
0b645fd2 CH |
436 | /* |
437 | * protobuf-c adds a max size enum with an internal, and changing by | |
438 | * version, name; cast to an int to avoid unhandled enum warnings | |
439 | */ | |
440 | switch ((int)be_msg->message_case) { | |
7d65b7b7 CH |
441 | case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ: |
442 | MGMTD_BE_ADAPTER_DBG( | |
218625aa | 443 | "Got SUBSCR_REQ from '%s' to %sregister %zu xpaths", |
7d65b7b7 | 444 | be_msg->subscr_req->client_name, |
218625aa CH |
445 | !be_msg->subscr_req->subscribe_xpaths && |
446 | be_msg->subscr_req->n_xpath_reg | |
7d65b7b7 CH |
447 | ? "de" |
448 | : "", | |
218625aa | 449 | be_msg->subscr_req->n_xpath_reg); |
7d65b7b7 CH |
450 | |
451 | if (strlen(be_msg->subscr_req->client_name)) { | |
452 | strlcpy(adapter->name, be_msg->subscr_req->client_name, | |
453 | sizeof(adapter->name)); | |
454 | adapter->id = mgmt_be_client_name2id(adapter->name); | |
455 | if (adapter->id >= MGMTD_BE_CLIENT_ID_MAX) { | |
456 | MGMTD_BE_ADAPTER_ERR( | |
457 | "Unable to resolve adapter '%s' to a valid ID. Disconnecting!", | |
458 | adapter->name); | |
6dad9b53 CH |
459 | /* this will/should delete old */ |
460 | msg_conn_disconnect(adapter->conn, false); | |
99564edc CH |
461 | zlog_err("XXX different from original code"); |
462 | break; | |
7d65b7b7 CH |
463 | } |
464 | mgmt_be_adapters_by_id[adapter->id] = adapter; | |
465 | mgmt_be_adapter_cleanup_old_conn(adapter); | |
42f4bb2b CH |
466 | |
467 | /* schedule INIT sequence now that it is registered */ | |
468 | mgmt_be_adapter_sched_init_event(adapter); | |
7d65b7b7 | 469 | } |
9405278e CH |
470 | |
471 | if (be_msg->subscr_req->n_xpath_reg) | |
472 | /* we aren't handling dynamic xpaths yet */ | |
473 | mgmt_be_send_subscr_reply(adapter, false); | |
474 | else | |
475 | mgmt_be_send_subscr_reply(adapter, true); | |
7d65b7b7 CH |
476 | break; |
477 | case MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY: | |
478 | MGMTD_BE_ADAPTER_DBG( | |
218625aa CH |
479 | "Got %s TXN_REPLY from '%s' txn-id %" PRIx64 |
480 | " with '%s'", | |
7d65b7b7 | 481 | be_msg->txn_reply->create ? "Create" : "Delete", |
218625aa | 482 | adapter->name, be_msg->txn_reply->txn_id, |
7d65b7b7 CH |
483 | be_msg->txn_reply->success ? "success" : "failure"); |
484 | /* | |
74335ceb | 485 | * Forward the TXN_REPLY to txn module. |
7d65b7b7 | 486 | */ |
74335ceb YR |
487 | mgmt_txn_notify_be_txn_reply( |
488 | be_msg->txn_reply->txn_id, | |
489 | be_msg->txn_reply->create, | |
490 | be_msg->txn_reply->success, adapter); | |
7d65b7b7 CH |
491 | break; |
492 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY: | |
493 | MGMTD_BE_ADAPTER_DBG( | |
218625aa CH |
494 | "Got CFGDATA_REPLY from '%s' txn-id %" PRIx64 |
495 | " batch-id %" PRIu64 " err:'%s'", | |
496 | adapter->name, be_msg->cfg_data_reply->txn_id, | |
497 | be_msg->cfg_data_reply->batch_id, | |
7d65b7b7 CH |
498 | be_msg->cfg_data_reply->error_if_any |
499 | ? be_msg->cfg_data_reply->error_if_any | |
500 | : "None"); | |
501 | /* | |
74335ceb | 502 | * Forward the CGFData-create reply to txn module. |
7d65b7b7 | 503 | */ |
74335ceb YR |
504 | mgmt_txn_notify_be_cfgdata_reply( |
505 | be_msg->cfg_data_reply->txn_id, | |
506 | be_msg->cfg_data_reply->batch_id, | |
507 | be_msg->cfg_data_reply->success, | |
508 | be_msg->cfg_data_reply->error_if_any, adapter); | |
7d65b7b7 CH |
509 | break; |
510 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY: | |
511 | MGMTD_BE_ADAPTER_DBG( | |
218625aa CH |
512 | "Got %s CFG_APPLY_REPLY from '%s' txn-id %" PRIx64 |
513 | " for %zu batches id %" PRIu64 "-%" PRIu64 " err:'%s'", | |
7d65b7b7 | 514 | be_msg->cfg_apply_reply->success ? "successful" |
218625aa CH |
515 | : "failed", |
516 | adapter->name, be_msg->cfg_apply_reply->txn_id, | |
517 | be_msg->cfg_apply_reply->n_batch_ids, | |
518 | be_msg->cfg_apply_reply->batch_ids[0], | |
519 | be_msg->cfg_apply_reply->batch_ids | |
520 | [be_msg->cfg_apply_reply->n_batch_ids - 1], | |
7d65b7b7 CH |
521 | be_msg->cfg_apply_reply->error_if_any |
522 | ? be_msg->cfg_apply_reply->error_if_any | |
523 | : "None"); | |
74335ceb YR |
524 | /* |
525 | * Forward the CGFData-apply reply to txn module. | |
7d65b7b7 | 526 | */ |
74335ceb YR |
527 | mgmt_txn_notify_be_cfg_apply_reply( |
528 | be_msg->cfg_apply_reply->txn_id, | |
529 | be_msg->cfg_apply_reply->success, | |
530 | (uint64_t *)be_msg->cfg_apply_reply->batch_ids, | |
531 | be_msg->cfg_apply_reply->n_batch_ids, | |
532 | be_msg->cfg_apply_reply->error_if_any, adapter); | |
7d65b7b7 CH |
533 | break; |
534 | case MGMTD__BE_MESSAGE__MESSAGE_GET_REPLY: | |
535 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_CMD_REPLY: | |
536 | case MGMTD__BE_MESSAGE__MESSAGE_SHOW_CMD_REPLY: | |
537 | case MGMTD__BE_MESSAGE__MESSAGE_NOTIFY_DATA: | |
538 | /* | |
539 | * TODO: Add handling code in future. | |
540 | */ | |
541 | break; | |
542 | /* | |
543 | * NOTE: The following messages are always sent from MGMTD to | |
544 | * Backend clients only and/or need not be handled on MGMTd. | |
545 | */ | |
546 | case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY: | |
547 | case MGMTD__BE_MESSAGE__MESSAGE_GET_REQ: | |
548 | case MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ: | |
549 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ: | |
550 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ: | |
551 | case MGMTD__BE_MESSAGE__MESSAGE_CFG_CMD_REQ: | |
552 | case MGMTD__BE_MESSAGE__MESSAGE_SHOW_CMD_REQ: | |
553 | case MGMTD__BE_MESSAGE__MESSAGE__NOT_SET: | |
7d65b7b7 CH |
554 | default: |
555 | /* | |
556 | * A 'default' case is being added contrary to the | |
557 | * FRR code guidelines to take care of build | |
558 | * failures on certain build systems (courtesy of | |
559 | * the proto-c package). | |
560 | */ | |
561 | break; | |
562 | } | |
563 | ||
564 | return 0; | |
565 | } | |
566 | ||
7d65b7b7 CH |
567 | static int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter, |
568 | uint64_t txn_id, bool create) | |
569 | { | |
570 | Mgmtd__BeMessage be_msg; | |
571 | Mgmtd__BeTxnReq txn_req; | |
572 | ||
573 | mgmtd__be_txn_req__init(&txn_req); | |
574 | txn_req.create = create; | |
575 | txn_req.txn_id = txn_id; | |
576 | ||
577 | mgmtd__be_message__init(&be_msg); | |
578 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ; | |
579 | be_msg.txn_req = &txn_req; | |
580 | ||
218625aa CH |
581 | MGMTD_BE_ADAPTER_DBG("Sending TXN_REQ to '%s' txn-id: %" PRIu64, |
582 | adapter->name, txn_id); | |
7d65b7b7 CH |
583 | |
584 | return mgmt_be_adapter_send_msg(adapter, &be_msg); | |
585 | } | |
586 | ||
587 | static int | |
588 | mgmt_be_send_cfgdata_create_req(struct mgmt_be_client_adapter *adapter, | |
589 | uint64_t txn_id, uint64_t batch_id, | |
590 | Mgmtd__YangCfgDataReq **cfgdata_reqs, | |
591 | size_t num_reqs, bool end_of_data) | |
592 | { | |
593 | Mgmtd__BeMessage be_msg; | |
594 | Mgmtd__BeCfgDataCreateReq cfgdata_req; | |
595 | ||
596 | mgmtd__be_cfg_data_create_req__init(&cfgdata_req); | |
597 | cfgdata_req.batch_id = batch_id; | |
598 | cfgdata_req.txn_id = txn_id; | |
599 | cfgdata_req.data_req = cfgdata_reqs; | |
600 | cfgdata_req.n_data_req = num_reqs; | |
601 | cfgdata_req.end_of_data = end_of_data; | |
602 | ||
603 | mgmtd__be_message__init(&be_msg); | |
604 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ; | |
605 | be_msg.cfg_data_req = &cfgdata_req; | |
606 | ||
607 | MGMTD_BE_ADAPTER_DBG( | |
218625aa CH |
608 | "Sending CFGDATA_CREATE_REQ to '%s' txn-id: %" PRIu64 |
609 | " batch-id: %" PRIu64, | |
610 | adapter->name, txn_id, batch_id); | |
7d65b7b7 CH |
611 | |
612 | return mgmt_be_adapter_send_msg(adapter, &be_msg); | |
613 | } | |
614 | ||
615 | static int mgmt_be_send_cfgapply_req(struct mgmt_be_client_adapter *adapter, | |
616 | uint64_t txn_id) | |
617 | { | |
618 | Mgmtd__BeMessage be_msg; | |
619 | Mgmtd__BeCfgDataApplyReq apply_req; | |
620 | ||
621 | mgmtd__be_cfg_data_apply_req__init(&apply_req); | |
622 | apply_req.txn_id = txn_id; | |
623 | ||
624 | mgmtd__be_message__init(&be_msg); | |
625 | be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ; | |
626 | be_msg.cfg_apply_req = &apply_req; | |
627 | ||
218625aa CH |
628 | MGMTD_BE_ADAPTER_DBG("Sending CFG_APPLY_REQ to '%s' txn-id: %" PRIu64, |
629 | adapter->name, txn_id); | |
7d65b7b7 CH |
630 | |
631 | return mgmt_be_adapter_send_msg(adapter, &be_msg); | |
632 | } | |
633 | ||
070c5e7a | 634 | static void mgmt_be_adapter_process_msg(uint8_t version, uint8_t *data, |
99564edc | 635 | size_t len, struct msg_conn *conn) |
7d65b7b7 | 636 | { |
6dad9b53 CH |
637 | struct mgmt_be_client_adapter *adapter = conn->user; |
638 | Mgmtd__BeMessage *be_msg = mgmtd__be_message__unpack(NULL, len, data); | |
7d65b7b7 | 639 | |
f82370b4 CH |
640 | if (!be_msg) { |
641 | MGMTD_BE_ADAPTER_DBG( | |
642 | "Failed to decode %zu bytes for adapter: %s", len, | |
643 | adapter->name); | |
644 | return; | |
7d65b7b7 | 645 | } |
f82370b4 CH |
646 | MGMTD_BE_ADAPTER_DBG("Decoded %zu bytes of message: %u for adapter: %s", |
647 | len, be_msg->message_case, adapter->name); | |
648 | (void)mgmt_be_adapter_handle_msg(adapter, be_msg); | |
649 | mgmtd__be_message__free_unpacked(be_msg, NULL); | |
7d65b7b7 CH |
650 | } |
651 | ||
acd7aea0 CH |
652 | static void mgmt_be_iter_and_get_cfg(struct mgmt_ds_ctx *ds_ctx, |
653 | const char *xpath, struct lyd_node *node, | |
218625aa | 654 | struct nb_node *nb_node, void *ctx) |
7d65b7b7 | 655 | { |
0327be91 CH |
656 | struct mgmt_be_get_adapter_config_params *parms = ctx; |
657 | struct mgmt_be_client_adapter *adapter = parms->adapter; | |
658 | uint subscr; | |
7d65b7b7 | 659 | |
0327be91 CH |
660 | subscr = mgmt_be_get_subscr_for_xpath_and_client( |
661 | xpath, adapter->id, MGMT_SUBSCR_NOTIFY_CFG); | |
662 | if (subscr) | |
663 | nb_config_diff_created(node, &parms->seq, parms->cfg_chgs); | |
7d65b7b7 CH |
664 | } |
665 | ||
99564edc CH |
666 | /* |
667 | * Initialize a BE client over a new connection | |
668 | */ | |
e6685141 | 669 | static void mgmt_be_adapter_conn_init(struct event *thread) |
7d65b7b7 CH |
670 | { |
671 | struct mgmt_be_client_adapter *adapter; | |
672 | ||
e16d030c | 673 | adapter = (struct mgmt_be_client_adapter *)EVENT_ARG(thread); |
6dad9b53 | 674 | assert(adapter && adapter->conn->fd >= 0); |
7d65b7b7 CH |
675 | |
676 | /* | |
74335ceb | 677 | * Check first if the current session can run a CONFIG |
7d65b7b7 CH |
678 | * transaction or not. Reschedule if a CONFIG transaction |
679 | * from another session is already in progress. | |
74335ceb | 680 | */ |
7d65b7b7 | 681 | if (mgmt_config_txn_in_progress() != MGMTD_SESSION_ID_NONE) { |
99564edc CH |
682 | zlog_err("XXX txn in progress, retry init"); |
683 | mgmt_be_adapter_sched_init_event(adapter); | |
74335ceb | 684 | return; |
7d65b7b7 | 685 | } |
7d65b7b7 | 686 | |
74335ceb YR |
687 | /* |
688 | * Notify TXN module to create a CONFIG transaction and | |
689 | * download the CONFIGs identified for this new client. | |
690 | * If the TXN module fails to initiate the CONFIG transaction | |
691 | * disconnect from the client forcing a reconnect later. | |
692 | * That should also take care of destroying the adapter. | |
693 | */ | |
7d65b7b7 | 694 | if (mgmt_txn_notify_be_adapter_conn(adapter, true) != 0) { |
99564edc | 695 | zlog_err("XXX notify be adapter conn fail"); |
6dad9b53 | 696 | msg_conn_disconnect(adapter->conn, false); |
7d65b7b7 CH |
697 | adapter = NULL; |
698 | } | |
7d65b7b7 CH |
699 | } |
700 | ||
99564edc CH |
701 | /* |
702 | * Schedule the initialization of the BE client connection. | |
703 | */ | |
7d65b7b7 | 704 | static void |
99564edc | 705 | mgmt_be_adapter_sched_init_event(struct mgmt_be_client_adapter *adapter) |
7d65b7b7 | 706 | { |
99564edc CH |
707 | event_add_timer_msec(mgmt_loop, mgmt_be_adapter_conn_init, adapter, |
708 | MGMTD_BE_CONN_INIT_DELAY_MSEC, | |
709 | &adapter->conn_init_ev); | |
7d65b7b7 CH |
710 | } |
711 | ||
712 | void mgmt_be_adapter_lock(struct mgmt_be_client_adapter *adapter) | |
713 | { | |
714 | adapter->refcount++; | |
715 | } | |
716 | ||
717 | extern void mgmt_be_adapter_unlock(struct mgmt_be_client_adapter **adapter) | |
718 | { | |
99564edc CH |
719 | struct mgmt_be_client_adapter *a = *adapter; |
720 | assert(a && a->refcount); | |
721 | ||
722 | if (!--a->refcount) { | |
723 | mgmt_be_adapters_del(&mgmt_be_adapters, a); | |
724 | EVENT_OFF(a->conn_init_ev); | |
6dad9b53 | 725 | msg_server_conn_delete(a->conn); |
99564edc | 726 | XFREE(MTYPE_MGMTD_BE_ADPATER, a); |
7d65b7b7 CH |
727 | } |
728 | ||
729 | *adapter = NULL; | |
730 | } | |
731 | ||
99564edc CH |
732 | /* |
733 | * Initialize the BE adapter module | |
734 | */ | |
735 | void mgmt_be_adapter_init(struct event_loop *tm) | |
7d65b7b7 | 736 | { |
99564edc CH |
737 | assert(!mgmt_loop); |
738 | mgmt_loop = tm; | |
7d65b7b7 | 739 | |
99564edc CH |
740 | mgmt_be_adapters_init(&mgmt_be_adapters); |
741 | mgmt_be_xpath_map_init(); | |
742 | ||
743 | if (msg_server_init(&mgmt_be_server, MGMTD_BE_SERVER_PATH, tm, | |
744 | mgmt_be_create_adapter, "backend", | |
745 | &mgmt_debug_be)) { | |
746 | zlog_err("cannot initialize backend server"); | |
747 | exit(1); | |
748 | } | |
7d65b7b7 CH |
749 | } |
750 | ||
99564edc CH |
751 | /* |
752 | * Destroy the BE adapter module | |
753 | */ | |
7d65b7b7 CH |
754 | void mgmt_be_adapter_destroy(void) |
755 | { | |
e3cacd96 CH |
756 | struct mgmt_be_client_adapter *adapter; |
757 | ||
99564edc | 758 | msg_server_cleanup(&mgmt_be_server); |
e3cacd96 CH |
759 | FOREACH_ADAPTER_IN_LIST (adapter) { |
760 | mgmt_be_adapter_delete(adapter); | |
761 | } | |
0327be91 | 762 | mgmt_be_xpath_map_cleanup(); |
7d65b7b7 CH |
763 | } |
764 | ||
99564edc CH |
765 | /* |
766 | * The server accepted a new connection | |
767 | */ | |
768 | struct msg_conn *mgmt_be_create_adapter(int conn_fd, union sockunion *from) | |
7d65b7b7 CH |
769 | { |
770 | struct mgmt_be_client_adapter *adapter = NULL; | |
771 | ||
e3cacd96 CH |
772 | assert(!mgmt_be_find_adapter_by_fd(conn_fd)); |
773 | ||
774 | adapter = XCALLOC(MTYPE_MGMTD_BE_ADPATER, | |
775 | sizeof(struct mgmt_be_client_adapter)); | |
776 | adapter->id = MGMTD_BE_CLIENT_ID_MAX; | |
777 | snprintf(adapter->name, sizeof(adapter->name), "Unknown-FD-%d", | |
778 | conn_fd); | |
779 | ||
780 | mgmt_be_adapter_lock(adapter); | |
781 | mgmt_be_adapters_add_tail(&mgmt_be_adapters, adapter); | |
782 | RB_INIT(nb_config_cbs, &adapter->cfg_chgs); | |
783 | ||
784 | adapter->conn = msg_server_conn_create( | |
785 | mgmt_loop, conn_fd, mgmt_be_adapter_notify_disconnect, | |
786 | mgmt_be_adapter_process_msg, MGMTD_BE_MAX_NUM_MSG_PROC, | |
787 | MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MSG_MAX_LEN, adapter, | |
788 | "BE-adapter"); | |
789 | ||
790 | MGMTD_BE_ADAPTER_DBG("Added new MGMTD Backend adapter '%s'", | |
791 | adapter->name); | |
7d65b7b7 | 792 | |
99564edc | 793 | return adapter->conn; |
7d65b7b7 CH |
794 | } |
795 | ||
796 | struct mgmt_be_client_adapter * | |
797 | mgmt_be_get_adapter_by_id(enum mgmt_be_client_id id) | |
798 | { | |
799 | return (id < MGMTD_BE_CLIENT_ID_MAX ? mgmt_be_adapters_by_id[id] | |
800 | : NULL); | |
801 | } | |
802 | ||
803 | struct mgmt_be_client_adapter * | |
804 | mgmt_be_get_adapter_by_name(const char *name) | |
805 | { | |
806 | return mgmt_be_find_adapter_by_name(name); | |
807 | } | |
808 | ||
809 | int mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, | |
810 | struct mgmt_ds_ctx *ds_ctx, | |
811 | struct nb_config_cbs **cfg_chgs) | |
812 | { | |
7d65b7b7 CH |
813 | struct mgmt_be_get_adapter_config_params parms; |
814 | ||
815 | assert(cfg_chgs); | |
816 | ||
acd7aea0 | 817 | /* |
51941c19 | 818 | * TODO: we should consider making this an assertable condition and |
acd7aea0 CH |
819 | * guaranteeing it be true when this function is called. B/c what is |
820 | * going to happen if there are some changes being sent, and we don't | |
821 | * gather a new snapshot, what new changes that came after the previous | |
822 | * snapshot will then be lost? | |
823 | */ | |
7d65b7b7 CH |
824 | if (RB_EMPTY(nb_config_cbs, &adapter->cfg_chgs)) { |
825 | parms.adapter = adapter; | |
826 | parms.cfg_chgs = &adapter->cfg_chgs; | |
827 | parms.seq = 0; | |
828 | ||
acd7aea0 CH |
829 | mgmt_ds_iter_data(ds_ctx, "", mgmt_be_iter_and_get_cfg, |
830 | (void *)&parms); | |
7d65b7b7 CH |
831 | } |
832 | ||
833 | *cfg_chgs = &adapter->cfg_chgs; | |
834 | return 0; | |
835 | } | |
836 | ||
837 | int mgmt_be_create_txn(struct mgmt_be_client_adapter *adapter, | |
838 | uint64_t txn_id) | |
839 | { | |
840 | return mgmt_be_send_txn_req(adapter, txn_id, true); | |
841 | } | |
842 | ||
843 | int mgmt_be_destroy_txn(struct mgmt_be_client_adapter *adapter, | |
844 | uint64_t txn_id) | |
845 | { | |
846 | return mgmt_be_send_txn_req(adapter, txn_id, false); | |
847 | } | |
848 | ||
849 | int mgmt_be_send_cfg_data_create_req(struct mgmt_be_client_adapter *adapter, | |
850 | uint64_t txn_id, uint64_t batch_id, | |
851 | struct mgmt_be_cfgreq *cfg_req, | |
852 | bool end_of_data) | |
853 | { | |
854 | return mgmt_be_send_cfgdata_create_req( | |
855 | adapter, txn_id, batch_id, cfg_req->cfgdata_reqs, | |
856 | cfg_req->num_reqs, end_of_data); | |
857 | } | |
858 | ||
859 | extern int | |
860 | mgmt_be_send_cfg_apply_req(struct mgmt_be_client_adapter *adapter, | |
861 | uint64_t txn_id) | |
862 | { | |
863 | return mgmt_be_send_cfgapply_req(adapter, txn_id); | |
864 | } | |
865 | ||
0327be91 | 866 | void mgmt_be_get_subscr_info_for_xpath( |
7d65b7b7 CH |
867 | const char *xpath, struct mgmt_be_client_subscr_info *subscr_info) |
868 | { | |
7d65b7b7 | 869 | enum mgmt_be_client_id id; |
0327be91 | 870 | uint i; |
7d65b7b7 | 871 | |
7d65b7b7 CH |
872 | memset(subscr_info, 0, sizeof(*subscr_info)); |
873 | ||
218625aa | 874 | MGMTD_BE_ADAPTER_DBG("XPATH: '%s'", xpath); |
0327be91 CH |
875 | for (i = 0; i < mgmt_num_xpath_maps; i++) { |
876 | if (!mgmt_be_eval_regexp_match(mgmt_xpath_map[i].xpath_regexp, | |
877 | xpath)) | |
878 | continue; | |
879 | FOREACH_MGMTD_BE_CLIENT_ID (id) { | |
880 | subscr_info->xpath_subscr[id] |= | |
881 | mgmt_xpath_map[i].subscr_info[id]; | |
7d65b7b7 | 882 | } |
7d65b7b7 CH |
883 | } |
884 | ||
0327be91 | 885 | if (DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL)) { |
7d65b7b7 | 886 | FOREACH_MGMTD_BE_CLIENT_ID (id) { |
0327be91 CH |
887 | if (!subscr_info->xpath_subscr[id]) |
888 | continue; | |
889 | MGMTD_BE_ADAPTER_DBG("Cient: %s: subscribed: 0x%x", | |
890 | mgmt_be_client_id2name(id), | |
891 | subscr_info->xpath_subscr[id]); | |
7d65b7b7 CH |
892 | } |
893 | } | |
0327be91 | 894 | } |
7d65b7b7 | 895 | |
0327be91 CH |
896 | /** |
897 | * Return the subscription info bits for a given `xpath` for a given | |
898 | * `client_id`. | |
899 | * | |
900 | * Args: | |
901 | * xpath - the xpath to check for subscription information. | |
902 | * client_id - the BE client being checked for. | |
903 | * subscr_mask - The subscr bits the caller is interested in seeing | |
904 | * if set. | |
905 | * | |
906 | * Returns: | |
907 | * The subscription info bits. | |
908 | */ | |
909 | static uint mgmt_be_get_subscr_for_xpath_and_client( | |
910 | const char *xpath, enum mgmt_be_client_id client_id, uint subscr_mask) | |
911 | { | |
912 | struct mgmt_be_client_xpath_map *map; | |
913 | uint subscr = 0; | |
914 | uint i; | |
915 | ||
916 | assert(client_id < MGMTD_BE_CLIENT_ID_MAX); | |
917 | ||
918 | MGMTD_BE_ADAPTER_DBG("Checking client: %s for xpath: '%s'", | |
919 | mgmt_be_client_id2name(client_id), xpath); | |
920 | ||
921 | map = &mgmt_client_xpaths[client_id]; | |
922 | for (i = 0; i < map->nxpaths; i++) { | |
923 | if (!mgmt_be_eval_regexp_match(map->xpaths[i].xpath, xpath)) | |
924 | continue; | |
925 | MGMTD_BE_ADAPTER_DBG("xpath: %s: matched: %s", | |
926 | map->xpaths[i].xpath, xpath); | |
927 | subscr |= map->xpaths[i].subscribed; | |
928 | if ((subscr & subscr_mask) == subscr_mask) | |
929 | break; | |
930 | } | |
931 | MGMTD_BE_ADAPTER_DBG("client: %s: subscribed: 0x%x", | |
932 | mgmt_be_client_id2name(client_id), subscr); | |
933 | return subscr; | |
7d65b7b7 CH |
934 | } |
935 | ||
936 | void mgmt_be_adapter_status_write(struct vty *vty) | |
937 | { | |
938 | struct mgmt_be_client_adapter *adapter; | |
939 | ||
940 | vty_out(vty, "MGMTD Backend Adapters\n"); | |
941 | ||
942 | FOREACH_ADAPTER_IN_LIST (adapter) { | |
943 | vty_out(vty, " Client: \t\t\t%s\n", adapter->name); | |
6dad9b53 | 944 | vty_out(vty, " Conn-FD: \t\t\t%d\n", adapter->conn->fd); |
7d65b7b7 CH |
945 | vty_out(vty, " Client-Id: \t\t\t%d\n", adapter->id); |
946 | vty_out(vty, " Ref-Count: \t\t\t%u\n", adapter->refcount); | |
f82370b4 | 947 | vty_out(vty, " Msg-Recvd: \t\t\t%" PRIu64 "\n", |
6dad9b53 | 948 | adapter->conn->mstate.nrxm); |
f82370b4 | 949 | vty_out(vty, " Bytes-Recvd: \t\t%" PRIu64 "\n", |
6dad9b53 | 950 | adapter->conn->mstate.nrxb); |
f82370b4 | 951 | vty_out(vty, " Msg-Sent: \t\t\t%" PRIu64 "\n", |
6dad9b53 | 952 | adapter->conn->mstate.ntxm); |
f82370b4 | 953 | vty_out(vty, " Bytes-Sent: \t\t%" PRIu64 "\n", |
6dad9b53 | 954 | adapter->conn->mstate.ntxb); |
7d65b7b7 CH |
955 | } |
956 | vty_out(vty, " Total: %d\n", | |
957 | (int)mgmt_be_adapters_count(&mgmt_be_adapters)); | |
958 | } | |
959 | ||
960 | void mgmt_be_xpath_register_write(struct vty *vty) | |
961 | { | |
0327be91 | 962 | uint indx; |
7d65b7b7 CH |
963 | enum mgmt_be_client_id id; |
964 | struct mgmt_be_client_adapter *adapter; | |
0327be91 | 965 | uint info; |
7d65b7b7 CH |
966 | |
967 | vty_out(vty, "MGMTD Backend XPath Registry\n"); | |
968 | ||
969 | for (indx = 0; indx < mgmt_num_xpath_maps; indx++) { | |
970 | vty_out(vty, " - XPATH: '%s'\n", | |
971 | mgmt_xpath_map[indx].xpath_regexp); | |
972 | FOREACH_MGMTD_BE_CLIENT_ID (id) { | |
0327be91 CH |
973 | info = mgmt_xpath_map[indx].subscr_info[id]; |
974 | if (!info) | |
975 | continue; | |
976 | vty_out(vty, | |
977 | " -- Client: '%s'\tValidate:%d, Notify:%d, Own:%d\n", | |
978 | mgmt_be_client_id2name(id), | |
979 | (info & MGMT_SUBSCR_VALIDATE_CFG) != 0, | |
980 | (info & MGMT_SUBSCR_NOTIFY_CFG) != 0, | |
981 | (info & MGMT_SUBSCR_OPER_OWN) != 0); | |
982 | adapter = mgmt_be_get_adapter_by_id(id); | |
983 | if (adapter) | |
984 | vty_out(vty, " -- Adapter: %p\n", adapter); | |
7d65b7b7 CH |
985 | } |
986 | } | |
987 | ||
988 | vty_out(vty, "Total XPath Registries: %u\n", mgmt_num_xpath_maps); | |
989 | } | |
990 | ||
991 | void mgmt_be_xpath_subscr_info_write(struct vty *vty, const char *xpath) | |
992 | { | |
993 | struct mgmt_be_client_subscr_info subscr; | |
994 | enum mgmt_be_client_id id; | |
995 | struct mgmt_be_client_adapter *adapter; | |
0327be91 | 996 | uint info; |
7d65b7b7 | 997 | |
0327be91 | 998 | mgmt_be_get_subscr_info_for_xpath(xpath, &subscr); |
7d65b7b7 CH |
999 | |
1000 | vty_out(vty, "XPath: '%s'\n", xpath); | |
1001 | FOREACH_MGMTD_BE_CLIENT_ID (id) { | |
0327be91 CH |
1002 | info = subscr.xpath_subscr[id]; |
1003 | if (!info) | |
1004 | continue; | |
1005 | vty_out(vty, | |
1006 | " -- Client: '%s'\tValidate:%d, Notify:%d, Own:%d\n", | |
1007 | mgmt_be_client_id2name(id), | |
1008 | (info & MGMT_SUBSCR_VALIDATE_CFG) != 0, | |
1009 | (info & MGMT_SUBSCR_NOTIFY_CFG) != 0, | |
1010 | (info & MGMT_SUBSCR_OPER_OWN) != 0); | |
1011 | adapter = mgmt_be_get_adapter_by_id(id); | |
1012 | if (adapter) | |
1013 | vty_out(vty, " -- Adapter: %p\n", adapter); | |
7d65b7b7 CH |
1014 | } |
1015 | } |