1 /* Hey Emacs use -*- mode: C -*- */
3 * Copyright 2020 Rubicon Communications, LLC.
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/vnet.h>
19 #include <vlibmemory/api.h>
21 #include <tracedump/graph.api_enum.h>
22 #include <tracedump/graph.api_types.h>
24 #define REPLY_MSG_ID_BASE gmp->msg_id_base
25 #include <vlibapi/api_helper_macros.h>
27 #include <tracedump/graph.h>
30 graph_main_t graph_main;
33 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
37 * If ever the graph or set of nodes changes, this cache of
38 * nodes in sorted order should be invalidated.
41 graph_node_invalid_cache (void)
43 graph_main_t *gmp = &graph_main;
45 vec_free (gmp->sorted_node_vec);
50 graph_node_cache_reaper (u32 client_index)
52 graph_node_invalid_cache ();
56 VL_MSG_API_REAPER_FUNCTION (graph_node_cache_reaper);
60 send_graph_node_reply (vl_api_registration_t * rp,
61 u32 context, u32 retval, u32 cursor)
63 graph_main_t *gmp = &graph_main;
64 vl_api_graph_node_get_reply_t *rmp;
66 rmp = vl_msg_api_alloc (sizeof (*rmp));
67 rmp->_vl_msg_id = htons (VL_API_GRAPH_NODE_GET_REPLY + gmp->msg_id_base);
68 rmp->context = context;
69 rmp->retval = clib_host_to_net_u32 (retval);
70 rmp->cursor = htonl (cursor);
72 vl_api_send_msg (rp, (u8 *) rmp);
77 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)
81 graph_main_t *gmp = &graph_main;
82 vl_api_graph_node_details_t *mp;
85 msg_size = sizeof (*mp);
87 msg_size += vec_len (n->next_nodes) * sizeof (*n->next_nodes);
89 mp = vl_msg_api_alloc (msg_size);
93 clib_memset (mp, 0, msg_size);
95 mp->_vl_msg_id = htons (VL_API_GRAPH_NODE_DETAILS + gmp->msg_id_base);
96 mp->context = context;
97 mp->index = htonl (n->index);
98 mp->flags = htonl (n->flags);
100 clib_strncpy ((char *) mp->name, (char *) n->name,
101 MIN (sizeof (mp->name) - 1, vec_len (n->name)));
107 mp->n_arcs = htonl (vec_len (n->next_nodes));
108 for (i = 0; i < vec_len (n->next_nodes); ++i)
110 mp->arcs_out[i] = htonl (n->next_nodes[i]);
114 vl_api_send_msg (reg, (u8 *) mp);
119 node_cmp (void *a1, void *a2)
121 vlib_node_t **n1 = a1;
122 vlib_node_t **n2 = a2;
124 return vec_cmp (n1[0]->name, n2[0]->name);
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
134 * index == ~0 and name[0] == 0 and flag == 0, so dump all nodes.
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.
141 vl_api_graph_node_get_t_handler (vl_api_graph_node_get_t * mp)
143 vl_api_registration_t *rp;
145 rp = vl_api_client_index_to_registration (mp->client_index);
149 vlib_main_t *vm = vlib_get_main ();
150 vlib_node_main_t *nm = &vm->node_main;
151 graph_main_t *gmp = &graph_main;
157 want_arcs = ! !mp->want_arcs;
158 cursor = ntohl (mp->cursor);
162 * Return details on a specific node by index?
164 node_index = ntohl (mp->index);
165 if (cursor == ~0 && node_index != ~0)
167 if (node_index < vec_len (nm->nodes))
168 n = vlib_get_node (vm, node_index);
171 send_graph_node_reply (rp, mp->context,
172 VNET_API_ERROR_NO_SUCH_ENTRY, ~0);
175 send_graph_node_details (nm, rp, mp->context, n, want_arcs);
176 send_graph_node_reply (rp, mp->context, 0, ~0);
181 * Return details on a specific node by name?
183 if (cursor == ~0 && mp->name[0] != 0)
185 n = vlib_get_node_by_name (vm, (u8 *) mp->name);
188 send_graph_node_reply (rp, mp->context,
189 VNET_API_ERROR_NO_SUCH_ENTRY, ~0);
193 send_graph_node_details (nm, rp, mp->context, n, want_arcs);
194 send_graph_node_reply (rp, mp->context, 0, ~0);
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.
203 * First time through, make a sorted node list and cache it.
205 vlib_node_t **nodes = gmp->sorted_node_vec;
208 nodes = vec_dup (nm->nodes);
209 vec_sort_with_function (nodes, node_cmp);
210 gmp->sorted_node_vec = nodes;
213 u32 flags = ntohl (mp->flags);
214 u32 first_index = (cursor == ~0) ? 0 : cursor;
216 /* Don't overflow the existing queue space. */
217 svm_queue_t *q = rp->vl_input_queue;
218 u32 queue_slots_available = q->maxsize - q->cursize;
219 int chunk = (queue_slots_available > 0) ? queue_slots_available - 1 : 0;
222 for (i = first_index; i < vec_len (nodes); ++i)
227 * Pick up again at cursor = i.
229 send_graph_node_reply (rp, mp->context, VNET_API_ERROR_EAGAIN, i);
234 if (flags == 0 || (n->flags & flags))
236 send_graph_node_details (nm, rp, mp->context, n, want_arcs);
240 send_graph_node_reply (rp, mp->context, 0, ~0);
244 #include <vnet/format_fns.h>
245 #include <tracedump/graph.api.c>
247 static clib_error_t *
248 graph_api_hookup (vlib_main_t * vm)
250 api_main_t *am = vlibapi_get_main ();
251 graph_main_t *gmp = &graph_main;
253 gmp->msg_id_base = setup_message_id_table ();
255 am->is_mp_safe[gmp->msg_id_base + VL_API_GRAPH_NODE_GET] = 1;
257 am->is_autoendian[gmp->msg_id_base + VL_API_GRAPH_NODE_DETAILS] = 1;
262 VLIB_INIT_FUNCTION (graph_api_hookup);
265 * fd.io coding-style-patch-verification: ON
268 * eval: (c-set-style "gnu")