]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_fpm_dt.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / zebra / zebra_fpm_dt.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * zebra_fpm_dt.c
4 *
5 * @copyright Copyright (C) 2016 Sproute Networks, Inc.
6 *
7 * @author Avneesh Sachdev <avneesh@sproute.com>
8 */
9
10 /*
11 * Developer tests for the zebra code that interfaces with the
12 * forwarding plane manager.
13 *
14 * The functions here are built into developer builds of zebra (when
15 * DEV_BUILD is defined), and can be called via the 'invoke' cli
16 * command.
17 *
18 * For example:
19 *
20 * # invoke zebra function zfpm_dt_benchmark_protobuf_encode 100000
21 *
22 */
23
24 #include <zebra.h>
25 #include "log.h"
26 #include "vrf.h"
27
28 #include "zebra/rib.h"
29 #include "zebra/zserv.h"
30 #include "zebra/zebra_vrf.h"
31
32 #include "zebra_fpm_private.h"
33
34 #include "qpb/qpb_allocator.h"
35 #include "qpb/linear_allocator.h"
36
37 #ifdef HAVE_PROTOBUF
38 #include "qpb/qpb.h"
39 #include "fpm/fpm.pb-c.h"
40 #endif
41
42 /*
43 * Externs.
44 */
45 extern int zfpm_dt_benchmark_netlink_encode(int argc, const char **argv);
46 extern int zfpm_dt_benchmark_protobuf_encode(int argc, const char **argv);
47 extern int zfpm_dt_benchmark_protobuf_decode(int argc, const char **argv);
48
49 /*
50 * zfpm_dt_find_route
51 *
52 * Selects a suitable rib destination for fpm interface tests.
53 */
54 static int zfpm_dt_find_route(rib_dest_t **dest_p, struct route_entry **re_p)
55 {
56 struct route_node *rnode;
57 route_table_iter_t iter;
58 struct route_table *table;
59 rib_dest_t *dest;
60 struct route_entry *re;
61 int ret;
62
63 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
64 if (!table)
65 return 0;
66
67 route_table_iter_init(&iter, table);
68 while ((rnode = route_table_iter_next(&iter))) {
69 dest = rib_dest_from_rnode(rnode);
70
71 if (!dest)
72 continue;
73
74 re = zfpm_route_for_update(dest);
75 if (!re)
76 continue;
77
78 if (nexthop_group_active_nexthop_num(&(re->nhe->nhg)) == 0)
79 continue;
80
81 *dest_p = dest;
82 *re_p = re;
83 ret = 1;
84 goto done;
85 }
86
87 ret = 0;
88
89 done:
90 route_table_iter_cleanup(&iter);
91 return ret;
92 }
93 #ifdef HAVE_NETLINK
94
95 /*
96 * zfpm_dt_benchmark_netlink_encode
97 */
98 int zfpm_dt_benchmark_netlink_encode(int argc, const char **argv)
99 {
100 int times, i, len;
101 rib_dest_t *dest;
102 struct route_entry *re;
103 char buf[4096];
104
105 times = 100000;
106 if (argc > 0) {
107 times = atoi(argv[0]);
108 }
109
110 if (!zfpm_dt_find_route(&dest, &re)) {
111 return 1;
112 }
113
114 for (i = 0; i < times; i++) {
115 len = zfpm_netlink_encode_route(RTM_NEWROUTE, dest, re, buf,
116 sizeof(buf));
117 if (len <= 0) {
118 return 2;
119 }
120 }
121 return 0;
122 }
123
124 #endif /* HAVE_NETLINK */
125
126 #ifdef HAVE_PROTOBUF
127
128 /*
129 * zfpm_dt_benchmark_protobuf_encode
130 */
131 int zfpm_dt_benchmark_protobuf_encode(int argc, const char **argv)
132 {
133 int times, i, len;
134 rib_dest_t *dest;
135 struct route_entry *re;
136 uint8_t buf[4096];
137
138 times = 100000;
139 if (argc > 0) {
140 times = atoi(argv[0]);
141 }
142
143 if (!zfpm_dt_find_route(&dest, &re)) {
144 return 1;
145 }
146
147 for (i = 0; i < times; i++) {
148 len = zfpm_protobuf_encode_route(dest, re, buf, sizeof(buf));
149 if (len <= 0) {
150 return 2;
151 }
152 }
153 return 0;
154 }
155
156 /*
157 * zfpm_dt_log_fpm_message
158 */
159 static void zfpm_dt_log_fpm_message(Fpm__Message *msg)
160 {
161 Fpm__AddRoute *add_route;
162 Fpm__Nexthop *nexthop;
163 struct prefix prefix;
164 uint8_t family, nh_family;
165 uint if_index;
166 char *if_name;
167 size_t i;
168 char buf[INET6_ADDRSTRLEN];
169 char addr_buf[PREFIX_STRLEN];
170 union g_addr nh_addr;
171
172 if (msg->type != FPM__MESSAGE__TYPE__ADD_ROUTE)
173 return;
174
175 zfpm_debug("Add route message");
176 add_route = msg->add_route;
177
178 if (!qpb_address_family_get(add_route->address_family, &family))
179 return;
180
181 if (!qpb_l3_prefix_get(add_route->key->prefix, family, &prefix))
182 return;
183
184 zfpm_debug("Vrf id: %d, Prefix: %s/%d, Metric: %d", add_route->vrf_id,
185 inet_ntop(family, &prefix.u.prefix, buf, sizeof(buf)),
186 prefix.prefixlen, add_route->metric);
187
188 /*
189 * Go over nexthops.
190 */
191 for (i = 0; i < add_route->n_nexthops; i++) {
192 nexthop = add_route->nexthops[i];
193 if (!qpb_if_identifier_get(nexthop->if_id, &if_index, &if_name))
194 continue;
195
196 if (nexthop->address)
197 qpb_l3_address_get(nexthop->address, &nh_family,
198 &nh_addr);
199
200 zfpm_debug("Nexthop - if_index: %d (%s), gateway: %s, ",
201 if_index, if_name ? if_name : "name not specified",
202 nexthop->address ?
203 inet_ntop(AF_INET, &nh_addr.ipv4,
204 addr_buf, sizeof(addr_buf)) : "None");
205 }
206 }
207
208 /*
209 * zfpm_dt_benchmark_protobuf_decode
210 */
211 int zfpm_dt_benchmark_protobuf_decode(int argc, const char **argv)
212 {
213 int times, i, len;
214 rib_dest_t *dest;
215 struct route_entry *re;
216 uint8_t msg_buf[4096];
217 QPB_DECLARE_STACK_ALLOCATOR(allocator, 8192);
218 Fpm__Message *fpm_msg;
219
220 QPB_INIT_STACK_ALLOCATOR(allocator);
221
222 times = 100000;
223 if (argc > 0)
224 times = atoi(argv[0]);
225
226 if (!zfpm_dt_find_route(&dest, &re))
227 return 1;
228
229 /*
230 * Encode the route into the message buffer once only.
231 */
232 len = zfpm_protobuf_encode_route(dest, re, msg_buf, sizeof(msg_buf));
233 if (len <= 0)
234 return 2;
235
236 // Decode once, and display the decoded message
237 fpm_msg = fpm__message__unpack(&allocator, len, msg_buf);
238
239 if (fpm_msg) {
240 zfpm_dt_log_fpm_message(fpm_msg);
241 QPB_RESET_STACK_ALLOCATOR(allocator);
242 }
243
244 /*
245 * Decode encoded message the specified number of times.
246 */
247 for (i = 0; i < times; i++) {
248 fpm_msg = fpm__message__unpack(&allocator, len, msg_buf);
249
250 if (!fpm_msg)
251 return 3;
252
253 // fpm__message__free_unpacked(msg, NULL);
254 QPB_RESET_STACK_ALLOCATOR(allocator);
255 }
256 return 0;
257 }
258
259 #endif /* HAVE_PROTOBUF */