Line data Source code
1 : /* Hey Emacs use -*- mode: C -*- */
2 : /*
3 : * Copyright 2020 Rubicon Communications, LLC.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vnet/vnet.h>
19 : #include <vlibmemory/api.h>
20 :
21 : #include <tracedump/graph.api_enum.h>
22 : #include <tracedump/graph.api_types.h>
23 :
24 : #define REPLY_MSG_ID_BASE gmp->msg_id_base
25 : #include <vlibapi/api_helper_macros.h>
26 :
27 : #include <tracedump/graph.h>
28 :
29 :
30 : graph_main_t graph_main;
31 :
32 :
33 : #define MIN(x,y) (((x) < (y)) ? (x) : (y))
34 :
35 :
36 : /*
37 : * If ever the graph or set of nodes changes, this cache of
38 : * nodes in sorted order should be invalidated.
39 : */
40 : void
41 1241 : graph_node_invalid_cache (void)
42 : {
43 1241 : graph_main_t *gmp = &graph_main;
44 :
45 1241 : vec_free (gmp->sorted_node_vec);
46 1241 : }
47 :
48 :
49 : static clib_error_t *
50 1241 : graph_node_cache_reaper (u32 client_index)
51 : {
52 1241 : graph_node_invalid_cache ();
53 1241 : return 0;
54 : }
55 :
56 575 : VL_MSG_API_REAPER_FUNCTION (graph_node_cache_reaper);
57 :
58 :
59 : static void
60 0 : send_graph_node_reply (vl_api_registration_t * rp,
61 : u32 context, u32 retval, u32 cursor)
62 : {
63 0 : graph_main_t *gmp = &graph_main;
64 : vl_api_graph_node_get_reply_t *rmp;
65 :
66 0 : rmp = vl_msg_api_alloc (sizeof (*rmp));
67 0 : rmp->_vl_msg_id = htons (VL_API_GRAPH_NODE_GET_REPLY + gmp->msg_id_base);
68 0 : rmp->context = context;
69 0 : rmp->retval = clib_host_to_net_u32 (retval);
70 0 : rmp->cursor = htonl (cursor);
71 :
72 0 : vl_api_send_msg (rp, (u8 *) rmp);
73 0 : }
74 :
75 :
76 : static void
77 0 : send_graph_node_details (vlib_node_main_t * nm,
78 : vl_api_registration_t * reg,
79 : u32 context, vlib_node_t * n, bool want_arcs)
80 : {
81 0 : graph_main_t *gmp = &graph_main;
82 : vl_api_graph_node_details_t *mp;
83 : u32 msg_size;
84 :
85 0 : msg_size = sizeof (*mp);
86 0 : if (want_arcs)
87 0 : msg_size += vec_len (n->next_nodes) * sizeof (*n->next_nodes);
88 :
89 0 : mp = vl_msg_api_alloc (msg_size);
90 0 : if (!mp)
91 0 : return;
92 :
93 0 : clib_memset (mp, 0, msg_size);
94 :
95 0 : mp->_vl_msg_id = htons (VL_API_GRAPH_NODE_DETAILS + gmp->msg_id_base);
96 0 : mp->context = context;
97 0 : mp->index = htonl (n->index);
98 0 : mp->flags = htonl (n->flags);
99 :
100 0 : clib_strncpy ((char *) mp->name, (char *) n->name,
101 : MIN (sizeof (mp->name) - 1, vec_len (n->name)));
102 :
103 0 : if (want_arcs)
104 : {
105 : int i;
106 :
107 0 : mp->n_arcs = htonl (vec_len (n->next_nodes));
108 0 : for (i = 0; i < vec_len (n->next_nodes); ++i)
109 : {
110 0 : mp->arcs_out[i] = htonl (n->next_nodes[i]);
111 : }
112 : }
113 :
114 0 : vl_api_send_msg (reg, (u8 *) mp);
115 : }
116 :
117 :
118 : static int
119 0 : node_cmp (void *a1, void *a2)
120 : {
121 0 : vlib_node_t **n1 = a1;
122 0 : vlib_node_t **n2 = a2;
123 :
124 0 : return vec_cmp (n1[0]->name, n2[0]->name);
125 : }
126 :
127 :
128 : /*
129 : * When cursor == ~0, it begins a request:
130 : * if index != ~0, dump node with given index
131 : * if index == ~0 and name[0] != 0, dump node with given name
132 : * if index == ~0 and name[0] == 0, and flag != 0, dump flagged nodes
133 : * else
134 : * index == ~0 and name[0] == 0 and flag == 0, so dump all nodes.
135 : *
136 : * When cursor != ~0, it is the middle of a request:
137 : * The same (index, name, and flag) parameters are assumed,
138 : * The next results resume from cursor.
139 : */
140 : static void
141 0 : vl_api_graph_node_get_t_handler (vl_api_graph_node_get_t * mp)
142 : {
143 : vl_api_registration_t *rp;
144 :
145 0 : rp = vl_api_client_index_to_registration (mp->client_index);
146 0 : if (!rp)
147 0 : return;
148 :
149 0 : vlib_main_t *vm = vlib_get_main ();
150 0 : vlib_node_main_t *nm = &vm->node_main;
151 0 : graph_main_t *gmp = &graph_main;
152 : vlib_node_t *n;
153 : u32 cursor;
154 : u32 node_index;
155 : bool want_arcs;
156 :
157 0 : want_arcs = ! !mp->want_arcs;
158 0 : cursor = ntohl (mp->cursor);
159 0 : n = 0;
160 :
161 : /*
162 : * Return details on a specific node by index?
163 : */
164 0 : node_index = ntohl (mp->index);
165 0 : if (cursor == ~0 && node_index != ~0)
166 : {
167 0 : if (node_index < vec_len (nm->nodes))
168 0 : n = vlib_get_node (vm, node_index);
169 0 : if (!n)
170 : {
171 0 : send_graph_node_reply (rp, mp->context,
172 : VNET_API_ERROR_NO_SUCH_ENTRY, ~0);
173 0 : return;
174 : }
175 0 : send_graph_node_details (nm, rp, mp->context, n, want_arcs);
176 0 : send_graph_node_reply (rp, mp->context, 0, ~0);
177 0 : return;
178 : }
179 :
180 : /*
181 : * Return details on a specific node by name?
182 : */
183 0 : if (cursor == ~0 && mp->name[0] != 0)
184 : {
185 0 : n = vlib_get_node_by_name (vm, (u8 *) mp->name);
186 0 : if (!n)
187 : {
188 0 : send_graph_node_reply (rp, mp->context,
189 : VNET_API_ERROR_NO_SUCH_ENTRY, ~0);
190 0 : return;
191 : }
192 :
193 0 : send_graph_node_details (nm, rp, mp->context, n, want_arcs);
194 0 : send_graph_node_reply (rp, mp->context, 0, ~0);
195 0 : return;
196 : }
197 :
198 : /*
199 : * Inspect all nodes, but potentially limit them by flag selection.
200 : * As iteration my need to occur over multiple streaming API calls,
201 : * determine the API client index and cache a sorted list of nodes.
202 : *
203 : * First time through, make a sorted node list and cache it.
204 : */
205 0 : vlib_node_t **nodes = gmp->sorted_node_vec;
206 0 : if (!nodes)
207 : {
208 0 : nodes = vec_dup (nm->nodes);
209 0 : vec_sort_with_function (nodes, node_cmp);
210 0 : gmp->sorted_node_vec = nodes;
211 : }
212 :
213 0 : u32 flags = ntohl (mp->flags);
214 0 : u32 first_index = (cursor == ~0) ? 0 : cursor;
215 :
216 : /* Don't overflow the existing queue space. */
217 0 : svm_queue_t *q = rp->vl_input_queue;
218 0 : u32 queue_slots_available = q->maxsize - q->cursize;
219 0 : int chunk = (queue_slots_available > 0) ? queue_slots_available - 1 : 0;
220 : u32 i;
221 :
222 0 : for (i = first_index; i < vec_len (nodes); ++i)
223 : {
224 0 : if (chunk-- == 0)
225 : {
226 : /*
227 : * Pick up again at cursor = i.
228 : */
229 0 : send_graph_node_reply (rp, mp->context, VNET_API_ERROR_EAGAIN, i);
230 0 : return;
231 : }
232 :
233 0 : n = nodes[i];
234 0 : if (flags == 0 || (n->flags & flags))
235 : {
236 0 : send_graph_node_details (nm, rp, mp->context, n, want_arcs);
237 : }
238 : }
239 :
240 0 : send_graph_node_reply (rp, mp->context, 0, ~0);
241 : }
242 :
243 :
244 : #include <vnet/format_fns.h>
245 : #include <tracedump/graph.api.c>
246 :
247 : static clib_error_t *
248 575 : graph_api_hookup (vlib_main_t * vm)
249 : {
250 575 : api_main_t *am = vlibapi_get_main ();
251 575 : graph_main_t *gmp = &graph_main;
252 :
253 575 : gmp->msg_id_base = setup_message_id_table ();
254 :
255 575 : vl_api_set_msg_thread_safe (am, gmp->msg_id_base + VL_API_GRAPH_NODE_GET, 1);
256 :
257 575 : return 0;
258 : }
259 :
260 1151 : VLIB_INIT_FUNCTION (graph_api_hookup);
261 :
262 : /*
263 : * fd.io coding-style-patch-verification: ON
264 : *
265 : * Local Variables:
266 : * eval: (c-set-style "gnu")
267 : * End:
268 : */
|