]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
b80f3b24 AS |
2 | /* |
3 | * zebra_fpm_dt.c | |
4 | * | |
5 | * @copyright Copyright (C) 2016 Sproute Networks, Inc. | |
6 | * | |
7 | * @author Avneesh Sachdev <avneesh@sproute.com> | |
b80f3b24 AS |
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" | |
b5a8526b DL |
29 | #include "zebra/zserv.h" |
30 | #include "zebra/zebra_vrf.h" | |
b80f3b24 AS |
31 | |
32 | #include "zebra_fpm_private.h" | |
33 | ||
34 | #include "qpb/qpb_allocator.h" | |
35 | #include "qpb/linear_allocator.h" | |
36 | ||
358336ef | 37 | #ifdef HAVE_PROTOBUF |
b80f3b24 AS |
38 | #include "qpb/qpb.h" |
39 | #include "fpm/fpm.pb-c.h" | |
358336ef | 40 | #endif |
b80f3b24 AS |
41 | |
42 | /* | |
43 | * Externs. | |
44 | */ | |
d62a17ae | 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); | |
b80f3b24 AS |
48 | |
49 | /* | |
50 | * zfpm_dt_find_route | |
51 | * | |
52 | * Selects a suitable rib destination for fpm interface tests. | |
53 | */ | |
d62a17ae | 54 | static int zfpm_dt_find_route(rib_dest_t **dest_p, struct route_entry **re_p) |
b80f3b24 | 55 | { |
d62a17ae | 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 | ||
97cd9bfc | 78 | if (nexthop_group_active_nexthop_num(&(re->nhe->nhg)) == 0) |
d62a17ae | 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; | |
b80f3b24 AS |
92 | } |
93 | #ifdef HAVE_NETLINK | |
94 | ||
95 | /* | |
96 | * zfpm_dt_benchmark_netlink_encode | |
97 | */ | |
d62a17ae | 98 | int zfpm_dt_benchmark_netlink_encode(int argc, const char **argv) |
b80f3b24 | 99 | { |
d62a17ae | 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; | |
b80f3b24 AS |
122 | } |
123 | ||
124 | #endif /* HAVE_NETLINK */ | |
125 | ||
126 | #ifdef HAVE_PROTOBUF | |
127 | ||
128 | /* | |
129 | * zfpm_dt_benchmark_protobuf_encode | |
130 | */ | |
d62a17ae | 131 | int zfpm_dt_benchmark_protobuf_encode(int argc, const char **argv) |
b80f3b24 | 132 | { |
d62a17ae | 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; | |
b80f3b24 AS |
154 | } |
155 | ||
156 | /* | |
157 | * zfpm_dt_log_fpm_message | |
158 | */ | |
d62a17ae | 159 | static void zfpm_dt_log_fpm_message(Fpm__Message *msg) |
b80f3b24 | 160 | { |
d62a17ae | 161 | Fpm__AddRoute *add_route; |
162 | Fpm__Nexthop *nexthop; | |
163 | struct prefix prefix; | |
d7c0a89a | 164 | uint8_t family, nh_family; |
d62a17ae | 165 | uint if_index; |
166 | char *if_name; | |
167 | size_t i; | |
168 | char buf[INET6_ADDRSTRLEN]; | |
9bcef951 | 169 | char addr_buf[PREFIX_STRLEN]; |
d62a17ae | 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", | |
9bcef951 MS |
202 | nexthop->address ? |
203 | inet_ntop(AF_INET, &nh_addr.ipv4, | |
204 | addr_buf, sizeof(addr_buf)) : "None"); | |
d62a17ae | 205 | } |
b80f3b24 AS |
206 | } |
207 | ||
208 | /* | |
209 | * zfpm_dt_benchmark_protobuf_decode | |
210 | */ | |
d62a17ae | 211 | int zfpm_dt_benchmark_protobuf_decode(int argc, const char **argv) |
b80f3b24 | 212 | { |
d62a17ae | 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; | |
b80f3b24 AS |
257 | } |
258 | ||
259 | #endif /* HAVE_PROTOBUF */ |