Line data Source code
1 : /*
2 : * vr_info.c -- vr_info functions
3 : *
4 : * Copyright (c) 2020 Juniper Networks, Inc. All rights reserved.
5 : */
6 :
7 : #include <vr_os.h>
8 : #if defined(__linux__)
9 : #include <linux/version.h>
10 : #endif
11 : #include "vr_types.h"
12 : #include "vr_sandesh.h"
13 : #include "vr_message.h"
14 : #include "vr_cpuid.h"
15 : #include <vr_packet.h>
16 :
17 : /* vr_info_buff_table_p pointer used to handle multiple clients in parallel.
18 : * When user callback function returns outbuf pointer, its stored in this
19 : * table and sends the msg buffer to its corresponding CLI client */
20 : static struct vr_info_buff_table vr_info_buff_table_p[VR_INFO_MSG_BUF_TABLE];
21 :
22 : /* Register the user callback function in below table */
23 : struct vr_info_callback users_cb_reg[VR_INFO_MAX_CALLBACK];
24 :
25 : /* Register callback using below function for vr_info.
26 : * */
27 : static int
28 1 : vr_info_callback_register(void)
29 : {
30 : /* Below macro would be expanded and register each callback function in
31 : * users_cb_reg table */
32 1 : FOREACH_VR_INFO_CB_REG_INIT();
33 :
34 1 : return 0;
35 : }
36 :
37 : /* Sandesh handler for vr_info message */
38 : void
39 1 : vr_info_req_process(void *s_req)
40 : {
41 1 : int i, ret = 0, buff_sz = 0, max_buff_sz = 0;
42 : vr_info_t msg_req;
43 1 : vr_info_req *req = (vr_info_req *)s_req;
44 : vr_info_req resp;
45 1 : struct vr_message_dumper *dumper = NULL;
46 1 : bool vr_info_last_buf = 0;
47 1 : char *trunc = "\n Message Truncated\n";
48 :
49 1 : if (req->h_op != SANDESH_OP_DUMP) {
50 0 : goto generate_response;
51 : }
52 :
53 : /* Copy request to response */
54 1 : resp = *req;
55 :
56 : /* Initialize the dumper buffer */
57 1 : dumper = vr_message_dump_init(req);
58 :
59 : /* Register callabck function before processing client request */
60 1 : ret = vr_info_callback_register();
61 1 : if(ret < 0) {
62 0 : vr_printf("vr_info: Callback registration failed\n with %d\n", ret);
63 0 : goto generate_response;
64 : }
65 :
66 : /* When CLI request comes, call the registered callback function and store
67 : * the address in msg_buff_table, If msginfo is more than 4K, split the
68 : * data into 4k chunks and send it serially to client. The client will
69 : * request back with vdu_buff_table_id and its index.
70 : * */
71 1 : if(!req->vdu_buff_table_id) {
72 : /* Maximum supported Client by server is 64, so based on that message
73 : * buffer table size is determined.
74 : * Buf table_id[0] is unused, so starting i with '1' */
75 1 : for(i = 1; i < VR_INFO_MSG_BUF_TABLE; i++) {
76 : /* Iterate through message buffer table and find the free entry */
77 1 : if(vr_info_buff_table_p[i].buff == NULL) {
78 :
79 1 : memset(&msg_req, 0, sizeof(vr_info_t));
80 :
81 : /* Copy Inbuf request to msg_req */
82 1 : msg_req.inbuf = req->vdu_inbuf;
83 1 : msg_req.inbuf_len = req->vdu_inbuf_size;
84 :
85 : /* Check requested msginfo is within boundary range */
86 1 : if((req->vdu_msginfo <= 0) || (req->vdu_msginfo >= INFO_MAX)) {
87 0 : vr_printf("vr_info: Callback function is not registered \
88 0 : for msginfo %d", req->vdu_msginfo);
89 0 : goto generate_response;
90 : }
91 :
92 : /* If --bufsz is sent from CLI, then copy the value as part of
93 : * msg_req */
94 1 : if(req->vdu_outbufsz) {
95 0 : msg_req.bufsz = req->vdu_outbufsz;
96 : }
97 :
98 : /* Check requested msginfo is avaialable in users callback
99 : * registered table */
100 1 : if(req->vdu_msginfo ==
101 1 : users_cb_reg[req->vdu_msginfo].msginfo) {
102 1 : ret = users_cb_reg[req->vdu_msginfo].cb_fn(&msg_req);
103 : } else {
104 0 : vr_printf("vr_info: Requested msginfo %d is not registered \
105 0 : in VR_INFO_REG() table\n", req->vdu_msginfo);
106 0 : goto generate_response;
107 : }
108 :
109 : /* Callback function returned failure msg */
110 1 : if(ret < 0) {
111 0 : vr_printf("vr_info: User callback function returned \
112 0 : failure for msg %d", req->vdu_msginfo);
113 : /* Suppose if message buffer is not completed, we append
114 : * "Message Truncated" in the buffer and send to client */
115 0 : if(ret == VR_INFO_MSG_TRUNC) {
116 0 : snprintf(((msg_req.outbuf + msg_req.outbuf_len) - strlen(trunc)),
117 : VR_MESSAGE_PAGE_SIZE, "%s", trunc);
118 : } else {
119 0 : goto generate_response;
120 : }
121 : }
122 : /* Copy buffer table id as part of response, so when
123 : * dump_pending is true, will callback with same buf table id */
124 1 : resp.vdu_buff_table_id = i;
125 :
126 : /* Copy message buffer_ptr to buffer table */
127 1 : vr_info_buff_table_p[i].buff = msg_req.outbuf;
128 : /* Copy message buffer length to buff_table pointer */
129 1 : vr_info_buff_table_p[i].buf_len = msg_req.outbuf_len;
130 :
131 : /* Check if Output buffer has contents */
132 1 : if(msg_req.outbuf == NULL) {
133 0 : vr_printf("vrinfo: Output buffer is NULL \n");
134 0 : vr_info_last_buf = true;
135 0 : goto generate_response;
136 :
137 : }
138 : /* If outbuf_len is not supplied from callback, calculate it */
139 1 : if(!msg_req.outbuf_len) {
140 0 : buff_sz = strlen(msg_req.outbuf);
141 : } else {
142 1 : buff_sz = msg_req.outbuf_len;
143 : }
144 :
145 1 : if(!msg_req.outbuf_len) {
146 0 : vr_printf("vrinfo: Output buffer is not filled\n");
147 0 : vr_info_last_buf = true;
148 0 : goto generate_response;
149 : }
150 :
151 : /* this is first iteration, so make vdu_marker as zero */
152 1 : req->vdu_marker = 0;
153 1 : break;
154 : }
155 : }
156 : } else {
157 0 : if(vr_info_buff_table_p[resp.vdu_buff_table_id].buff != NULL) {
158 0 : buff_sz = vr_info_buff_table_p[resp.vdu_buff_table_id].buf_len;
159 : } else {
160 0 : vr_printf("vr_info: vr_info_buff_table_p buf_id %d is NULL\n",
161 0 : req->vdu_buff_table_id);
162 0 : vr_info_last_buf = true;
163 0 : goto generate_response;
164 : }
165 : }
166 :
167 : /* Sandesh has limitation of macro(VR_MESSAGE_PAGE_SIZE) size, so
168 : * calculating max buffer size, and those much amount of data would be sent
169 : * on each iteration */
170 1 : max_buff_sz = VR_MESSAGE_PAGE_SIZE - (sizeof(resp) +
171 : sizeof(struct vr_message_dumper));
172 :
173 : /* Check if the buffer size is greater than max buffer, If so, have to send
174 : * it through multiple iteration. */
175 1 : if(buff_sz > max_buff_sz) {
176 : /* To send whole buffer, (buff_sz/max_buff_sz + 1) => these many
177 : * number of times have to send it to client CLI. */
178 : while(1) {
179 : /* To find the last iteration */
180 0 : if( req->vdu_marker == buff_sz/max_buff_sz ) {
181 : /* Calculate the number of remaining bytes to send it to
182 : * client CLI */
183 0 : resp.vdu_proc_info_size = (buff_sz -
184 0 : (max_buff_sz * req->vdu_marker) + 1);
185 0 : vr_info_last_buf = true;
186 : } else {
187 : /* Increment with 1 to include the '\0' character */
188 0 : resp.vdu_proc_info_size = max_buff_sz + 1;
189 : }
190 :
191 : /* Update the index value, querying for next iteration */
192 0 : resp.vdu_index = (req->vdu_marker + 1);
193 :
194 0 : resp.vdu_proc_info = vr_zalloc((resp.vdu_proc_info_size *
195 : sizeof(uint8_t)), VR_INFO_REQ_OBJECT);
196 0 : if(resp.vdu_proc_info == NULL) {
197 0 : vr_info_last_buf = true;
198 0 : goto generate_response;
199 : }
200 :
201 : /* Copy the message to "resp.vdu_proc_info" from
202 : * "vr_info_buff_table_p[id]+offset". Here offset is calculated
203 : * from (max_buff_sz * req->vdu_marker) */
204 0 : snprintf(resp.vdu_proc_info, (resp.vdu_proc_info_size),
205 0 : "%s", (vr_info_buff_table_p[resp.vdu_buff_table_id].buff +
206 0 : (max_buff_sz * req->vdu_marker)));
207 :
208 : /* If message buffer copy is not complete, it will return with -1.
209 : * so it will send to client and client will request back. */
210 0 : ret = vr_message_dump_object(dumper, VR_INFO_OBJECT_ID, &resp);
211 :
212 0 : if(resp.vdu_proc_info != NULL) {
213 0 : vr_free(resp.vdu_proc_info, VR_INFO_REQ_OBJECT);
214 : }
215 0 : if((ret <= 0) || vr_info_last_buf) {
216 : break;
217 : }
218 : }
219 : } else {
220 : /* Total message buffer size is less than 4k, so it can send in
221 : * one iteration. */
222 1 : vr_info_last_buf = true;
223 1 : resp.vdu_proc_info_size = buff_sz;
224 :
225 1 : resp.vdu_proc_info = vr_zalloc((resp.vdu_proc_info_size *
226 : sizeof(uint8_t)), VR_INFO_REQ_OBJECT);
227 1 : if(resp.vdu_proc_info == NULL) {
228 0 : goto generate_response;
229 : }
230 :
231 : /* Copy message buffer */
232 1 : snprintf(resp.vdu_proc_info, resp.vdu_proc_info_size, "%s", msg_req.outbuf);
233 1 : vr_message_dump_object(dumper, VR_INFO_OBJECT_ID, &resp);
234 :
235 1 : if(resp.vdu_proc_info) {
236 1 : vr_free(resp.vdu_proc_info, VR_INFO_REQ_OBJECT);
237 : }
238 : }
239 :
240 0 : generate_response:
241 1 : vr_message_dump_exit(dumper, ret);
242 :
243 : /* Once last buffer element has reached, clear all message buffers.
244 : * Memory(malloc) is allocated by end users and infra will free the memory */
245 1 : if(vr_info_last_buf) {
246 2 : for (i = resp.vdu_buff_table_id; i > 0; i--) {
247 1 : if(vr_info_buff_table_p[i].buff != NULL) {
248 1 : vr_free(vr_info_buff_table_p[i].buff, VR_INFO_REQ_OBJECT);
249 1 : vr_info_buff_table_p[i].buff = NULL;
250 1 : vr_info_buff_table_p[i].buf_len = 0;
251 : } else
252 0 : vr_printf("Memory free failed for vr_info pointer instance %d\n", i);
253 : }
254 : }
255 :
256 1 : return;
257 : }
|