]>
Commit | Line | Data |
---|---|---|
8a71d93d DS |
1 | /* |
2 | * Zebra connect code. | |
3 | * Copyright (C) Cumulus Networks, Inc. | |
4 | * Donald Sharp | |
5 | * | |
6 | * This file is part of FRR. | |
7 | * | |
8 | * FRR is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2, or (at your option) any | |
11 | * later version. | |
12 | * | |
13 | * FRR is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; see the file COPYING; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | */ | |
22 | #include <zebra.h> | |
23 | ||
24 | #include "thread.h" | |
25 | #include "command.h" | |
26 | #include "network.h" | |
27 | #include "prefix.h" | |
8a71d93d DS |
28 | #include "stream.h" |
29 | #include "memory.h" | |
30 | #include "zclient.h" | |
8a71d93d | 31 | #include "nexthop.h" |
694b242f | 32 | #include "nexthop_group.h" |
8a71d93d | 33 | |
547dc642 | 34 | #include "sharp_globals.h" |
86da53ab | 35 | #include "sharp_nht.h" |
8a71d93d DS |
36 | #include "sharp_zebra.h" |
37 | ||
38 | /* Zebra structure to hold current status. */ | |
39 | struct zclient *zclient = NULL; | |
40 | ||
41 | /* For registering threads. */ | |
2be4d61a | 42 | struct thread_master *master; |
8a71d93d | 43 | |
2be4d61a MS |
44 | /* Privs info */ |
45 | struct zebra_privs_t sharp_privs; | |
46 | ||
47 | DEFINE_MTYPE_STATIC(SHARPD, ZC, "Test zclients"); | |
48 | ||
49 | /* Struct to hold list of test zclients */ | |
50 | struct sharp_zclient { | |
51 | struct sharp_zclient *prev; | |
52 | struct sharp_zclient *next; | |
53 | struct zclient *client; | |
54 | }; | |
55 | ||
56 | /* Head of test zclient list */ | |
57 | static struct sharp_zclient *sharp_clients_head; | |
58 | ||
59 | static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS); | |
60 | ||
61 | /* Utility to add a test zclient struct to the list */ | |
62 | static void add_zclient(struct zclient *client) | |
63 | { | |
64 | struct sharp_zclient *node; | |
65 | ||
66 | node = XCALLOC(MTYPE_ZC, sizeof(struct sharp_zclient)); | |
67 | ||
68 | node->client = client; | |
69 | ||
70 | node->next = sharp_clients_head; | |
71 | if (sharp_clients_head) | |
72 | sharp_clients_head->prev = node; | |
73 | sharp_clients_head = node; | |
74 | } | |
75 | ||
76 | /* Interface addition message from zebra. */ | |
ef7bd2a3 | 77 | static int sharp_ifp_create(struct interface *ifp) |
8a71d93d | 78 | { |
8a71d93d DS |
79 | return 0; |
80 | } | |
81 | ||
3c3c3252 | 82 | static int sharp_ifp_destroy(struct interface *ifp) |
8a71d93d | 83 | { |
8a71d93d DS |
84 | return 0; |
85 | } | |
86 | ||
121f9dee | 87 | static int interface_address_add(ZAPI_CALLBACK_ARGS) |
8a71d93d | 88 | { |
121f9dee | 89 | zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
8a71d93d DS |
90 | |
91 | return 0; | |
92 | } | |
93 | ||
121f9dee | 94 | static int interface_address_delete(ZAPI_CALLBACK_ARGS) |
8a71d93d DS |
95 | { |
96 | struct connected *c; | |
97 | ||
121f9dee | 98 | c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
8a71d93d DS |
99 | |
100 | if (!c) | |
101 | return 0; | |
102 | ||
721c0857 | 103 | connected_free(&c); |
8a71d93d DS |
104 | return 0; |
105 | } | |
106 | ||
ddbf3e60 | 107 | static int sharp_ifp_up(struct interface *ifp) |
8a71d93d | 108 | { |
8a71d93d DS |
109 | return 0; |
110 | } | |
111 | ||
b0b69e59 | 112 | static int sharp_ifp_down(struct interface *ifp) |
8a71d93d | 113 | { |
8a71d93d DS |
114 | return 0; |
115 | } | |
116 | ||
c9e5adba MS |
117 | int sharp_install_lsps_helper(bool install_p, const struct prefix *p, |
118 | uint8_t type, int instance, uint32_t in_label, | |
665edffd MS |
119 | const struct nexthop_group *nhg, |
120 | const struct nexthop_group *backup_nhg) | |
c9e5adba MS |
121 | { |
122 | struct zapi_labels zl = {}; | |
123 | struct zapi_nexthop *znh; | |
124 | const struct nexthop *nh; | |
125 | int i, ret; | |
126 | ||
127 | zl.type = ZEBRA_LSP_SHARP; | |
128 | zl.local_label = in_label; | |
129 | ||
130 | if (p) { | |
131 | SET_FLAG(zl.message, ZAPI_LABELS_FTN); | |
132 | prefix_copy(&zl.route.prefix, p); | |
133 | zl.route.type = type; | |
134 | zl.route.instance = instance; | |
135 | } | |
136 | ||
665edffd | 137 | /* List of nexthops is optional for delete */ |
c9e5adba | 138 | i = 0; |
665edffd MS |
139 | if (nhg) { |
140 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { | |
141 | znh = &zl.nexthops[i]; | |
142 | ||
143 | /* Must have labels to be useful */ | |
144 | if (nh->nh_label == NULL || | |
145 | nh->nh_label->num_labels == 0) | |
146 | continue; | |
147 | ||
148 | if (nh->type == NEXTHOP_TYPE_IFINDEX || | |
149 | nh->type == NEXTHOP_TYPE_BLACKHOLE) | |
150 | /* Hmm - can't really deal with these types */ | |
151 | continue; | |
152 | ||
153 | ret = zapi_nexthop_from_nexthop(znh, nh); | |
154 | if (ret < 0) | |
155 | return -1; | |
156 | ||
157 | i++; | |
158 | } | |
159 | } | |
c9e5adba | 160 | |
665edffd MS |
161 | /* Whoops - no nexthops isn't very useful for install */ |
162 | if (i == 0 && install_p) | |
163 | return -1; | |
c9e5adba | 164 | |
665edffd | 165 | zl.nexthop_num = i; |
c9e5adba | 166 | |
665edffd MS |
167 | /* Add optional backup nexthop info. Since these are used by index, |
168 | * we can't just skip over an invalid backup nexthop: we will | |
169 | * invalidate the entire operation. | |
170 | */ | |
171 | if (backup_nhg != NULL) { | |
172 | i = 0; | |
173 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
174 | znh = &zl.backup_nexthops[i]; | |
c9e5adba | 175 | |
665edffd MS |
176 | /* Must have labels to be useful */ |
177 | if (nh->nh_label == NULL || | |
178 | nh->nh_label->num_labels == 0) | |
179 | return -1; | |
c9e5adba | 180 | |
665edffd MS |
181 | if (nh->type == NEXTHOP_TYPE_IFINDEX || |
182 | nh->type == NEXTHOP_TYPE_BLACKHOLE) | |
183 | /* Hmm - can't really deal with these types */ | |
184 | return -1; | |
c9e5adba | 185 | |
665edffd MS |
186 | ret = zapi_nexthop_from_nexthop(znh, nh); |
187 | if (ret < 0) | |
188 | return -1; | |
189 | ||
190 | i++; | |
191 | } | |
192 | ||
193 | if (i > 0) | |
194 | SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS); | |
195 | ||
196 | zl.backup_nexthop_num = i; | |
197 | } | |
c9e5adba MS |
198 | |
199 | if (install_p) | |
200 | ret = zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_ADD, | |
201 | &zl); | |
202 | else | |
203 | ret = zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, | |
204 | &zl); | |
205 | ||
206 | return ret; | |
207 | } | |
208 | ||
0cf08685 | 209 | void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, |
1df3b1dc MS |
210 | uint8_t instance, |
211 | const struct nexthop_group *nhg, | |
212 | const struct nexthop_group *backup_nhg, | |
6b98d34f DS |
213 | uint32_t routes) |
214 | { | |
215 | uint32_t temp, i; | |
dbc1bf46 | 216 | bool v4 = false; |
6b98d34f DS |
217 | |
218 | zlog_debug("Inserting %u routes", routes); | |
219 | ||
dbc1bf46 DS |
220 | if (p->family == AF_INET) { |
221 | v4 = true; | |
222 | temp = ntohl(p->u.prefix4.s_addr); | |
223 | } else | |
224 | temp = ntohl(p->u.val32[3]); | |
225 | ||
1df3b1dc MS |
226 | /* Only use backup route/nexthops if present */ |
227 | if (backup_nhg && (backup_nhg->nexthop == NULL)) | |
228 | backup_nhg = NULL; | |
229 | ||
547dc642 | 230 | monotime(&sg.r.t_start); |
6b98d34f | 231 | for (i = 0; i < routes; i++) { |
1df3b1dc | 232 | route_add(p, vrf_id, (uint8_t)instance, nhg, backup_nhg); |
dbc1bf46 DS |
233 | if (v4) |
234 | p->u.prefix4.s_addr = htonl(++temp); | |
235 | else | |
236 | p->u.val32[3] = htonl(++temp); | |
6b98d34f DS |
237 | } |
238 | } | |
239 | ||
0cf08685 DS |
240 | void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, |
241 | uint8_t instance, uint32_t routes) | |
6b98d34f DS |
242 | { |
243 | uint32_t temp, i; | |
dbc1bf46 | 244 | bool v4 = false; |
6b98d34f DS |
245 | |
246 | zlog_debug("Removing %u routes", routes); | |
247 | ||
dbc1bf46 DS |
248 | if (p->family == AF_INET) { |
249 | v4 = true; | |
250 | temp = ntohl(p->u.prefix4.s_addr); | |
251 | } else | |
252 | temp = ntohl(p->u.val32[3]); | |
253 | ||
547dc642 | 254 | monotime(&sg.r.t_start); |
6b98d34f | 255 | for (i = 0; i < routes; i++) { |
0cf08685 | 256 | route_delete(p, vrf_id, (uint8_t)instance); |
dbc1bf46 DS |
257 | if (v4) |
258 | p->u.prefix4.s_addr = htonl(++temp); | |
259 | else | |
260 | p->u.val32[3] = htonl(++temp); | |
6b98d34f DS |
261 | } |
262 | } | |
263 | ||
b939f6ff | 264 | static void handle_repeated(bool installed) |
6b98d34f | 265 | { |
547dc642 DS |
266 | struct prefix p = sg.r.orig_prefix; |
267 | sg.r.repeat--; | |
6b98d34f | 268 | |
547dc642 | 269 | if (sg.r.repeat <= 0) |
6b98d34f DS |
270 | return; |
271 | ||
272 | if (installed) { | |
547dc642 | 273 | sg.r.removed_routes = 0; |
0cf08685 DS |
274 | sharp_remove_routes_helper(&p, sg.r.vrf_id, |
275 | sg.r.inst, sg.r.total_routes); | |
6b98d34f DS |
276 | } |
277 | ||
f54f37c1 | 278 | if (!installed) { |
547dc642 | 279 | sg.r.installed_routes = 0; |
0cf08685 DS |
280 | sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, |
281 | &sg.r.nhop_group, | |
1df3b1dc | 282 | &sg.r.backup_nhop_group, |
547dc642 | 283 | sg.r.total_routes); |
6b98d34f DS |
284 | } |
285 | } | |
286 | ||
121f9dee | 287 | static int route_notify_owner(ZAPI_CALLBACK_ARGS) |
8a71d93d | 288 | { |
25c84d86 | 289 | struct timeval r; |
8a71d93d DS |
290 | struct prefix p; |
291 | enum zapi_route_notify_owner note; | |
28610f7e | 292 | uint32_t table; |
8a71d93d | 293 | |
28610f7e | 294 | if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, ¬e)) |
8a71d93d DS |
295 | return -1; |
296 | ||
5e54c602 DS |
297 | switch (note) { |
298 | case ZAPI_ROUTE_INSTALLED: | |
547dc642 DS |
299 | sg.r.installed_routes++; |
300 | if (sg.r.total_routes == sg.r.installed_routes) { | |
301 | monotime(&sg.r.t_end); | |
302 | timersub(&sg.r.t_end, &sg.r.t_start, &r); | |
051a0be4 DL |
303 | zlog_debug("Installed All Items %jd.%ld", |
304 | (intmax_t)r.tv_sec, (long)r.tv_usec); | |
6b98d34f DS |
305 | handle_repeated(true); |
306 | } | |
5e54c602 DS |
307 | break; |
308 | case ZAPI_ROUTE_FAIL_INSTALL: | |
309 | zlog_debug("Failed install of route"); | |
310 | break; | |
311 | case ZAPI_ROUTE_BETTER_ADMIN_WON: | |
312 | zlog_debug("Better Admin Distance won over us"); | |
313 | break; | |
314 | case ZAPI_ROUTE_REMOVED: | |
547dc642 DS |
315 | sg.r.removed_routes++; |
316 | if (sg.r.total_routes == sg.r.removed_routes) { | |
317 | monotime(&sg.r.t_end); | |
318 | timersub(&sg.r.t_end, &sg.r.t_start, &r); | |
051a0be4 DL |
319 | zlog_debug("Removed all Items %jd.%ld", |
320 | (intmax_t)r.tv_sec, (long)r.tv_usec); | |
6b98d34f DS |
321 | handle_repeated(false); |
322 | } | |
5e54c602 DS |
323 | break; |
324 | case ZAPI_ROUTE_REMOVE_FAIL: | |
325 | zlog_debug("Route removal Failure"); | |
326 | break; | |
327 | } | |
8a71d93d DS |
328 | return 0; |
329 | } | |
330 | ||
331 | static void zebra_connected(struct zclient *zclient) | |
332 | { | |
333 | zclient_send_reg_requests(zclient, VRF_DEFAULT); | |
67a9eda9 DS |
334 | |
335 | /* | |
336 | * Do not actually turn this on yet | |
337 | * This is just the start of the infrastructure needed here | |
338 | * This can be fixed at a later time. | |
339 | * | |
340 | * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, | |
341 | * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); | |
342 | */ | |
8a71d93d DS |
343 | } |
344 | ||
7d061b3c | 345 | void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) |
ab18a495 | 346 | { |
7d061b3c | 347 | zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); |
ab18a495 DS |
348 | } |
349 | ||
1df3b1dc MS |
350 | void route_add(const struct prefix *p, vrf_id_t vrf_id, |
351 | uint8_t instance, const struct nexthop_group *nhg, | |
352 | const struct nexthop_group *backup_nhg) | |
8a71d93d DS |
353 | { |
354 | struct zapi_route api; | |
355 | struct zapi_nexthop *api_nh; | |
694b242f DS |
356 | struct nexthop *nh; |
357 | int i = 0; | |
8a71d93d DS |
358 | |
359 | memset(&api, 0, sizeof(api)); | |
0cf08685 | 360 | api.vrf_id = vrf_id; |
8a71d93d | 361 | api.type = ZEBRA_ROUTE_SHARP; |
ae252c02 | 362 | api.instance = instance; |
8a71d93d DS |
363 | api.safi = SAFI_UNICAST; |
364 | memcpy(&api.prefix, p, sizeof(*p)); | |
365 | ||
a3896844 | 366 | SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); |
8a71d93d DS |
367 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); |
368 | ||
694b242f DS |
369 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { |
370 | api_nh = &api.nexthops[i]; | |
054af19a | 371 | |
c9e5adba | 372 | zapi_nexthop_from_nexthop(api_nh, nh); |
1df3b1dc | 373 | |
694b242f DS |
374 | i++; |
375 | } | |
376 | api.nexthop_num = i; | |
8a71d93d | 377 | |
1df3b1dc MS |
378 | /* Include backup nexthops, if present */ |
379 | if (backup_nhg && backup_nhg->nexthop) { | |
380 | SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS); | |
381 | ||
382 | i = 0; | |
383 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
384 | api_nh = &api.backup_nexthops[i]; | |
385 | ||
386 | zapi_backup_nexthop_from_nexthop(api_nh, nh); | |
387 | ||
388 | i++; | |
389 | } | |
390 | ||
391 | api.backup_nexthop_num = i; | |
392 | } | |
393 | ||
8a71d93d DS |
394 | zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
395 | } | |
396 | ||
0cf08685 | 397 | void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance) |
8a71d93d DS |
398 | { |
399 | struct zapi_route api; | |
400 | ||
401 | memset(&api, 0, sizeof(api)); | |
0cf08685 | 402 | api.vrf_id = vrf_id; |
8a71d93d DS |
403 | api.type = ZEBRA_ROUTE_SHARP; |
404 | api.safi = SAFI_UNICAST; | |
ae252c02 | 405 | api.instance = instance; |
8a71d93d DS |
406 | memcpy(&api.prefix, p, sizeof(*p)); |
407 | zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); | |
408 | ||
409 | return; | |
410 | } | |
411 | ||
91529dc8 | 412 | void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, |
b47dc61a | 413 | bool watch, bool connected) |
0ae8130d | 414 | { |
b47dc61a | 415 | int command; |
0ae8130d | 416 | |
b47dc61a DS |
417 | if (!import) { |
418 | command = ZEBRA_NEXTHOP_REGISTER; | |
419 | ||
420 | if (!watch) | |
421 | command = ZEBRA_NEXTHOP_UNREGISTER; | |
422 | } else { | |
423 | command = ZEBRA_IMPORT_ROUTE_REGISTER; | |
424 | ||
425 | if (!watch) | |
426 | command = ZEBRA_IMPORT_ROUTE_UNREGISTER; | |
427 | } | |
0ae8130d | 428 | |
91529dc8 | 429 | if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0) |
15569c58 | 430 | zlog_warn("%s: Failure to send nexthop to zebra", __func__); |
0ae8130d DS |
431 | } |
432 | ||
67a9eda9 | 433 | static int sharp_debug_nexthops(struct zapi_route *api) |
0ae8130d | 434 | { |
0ae8130d | 435 | int i; |
67a9eda9 | 436 | char buf[PREFIX_STRLEN]; |
0ae8130d | 437 | |
67a9eda9 DS |
438 | for (i = 0; i < api->nexthop_num; i++) { |
439 | struct zapi_nexthop *znh = &api->nexthops[i]; | |
0ae8130d DS |
440 | |
441 | switch (znh->type) { | |
442 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
443 | case NEXTHOP_TYPE_IPV4: | |
444 | zlog_debug( | |
d6951e5e | 445 | " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", |
0ae8130d DS |
446 | inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf, |
447 | sizeof(buf)), | |
448 | znh->type, znh->ifindex, znh->vrf_id, | |
449 | znh->label_num); | |
450 | break; | |
451 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
452 | case NEXTHOP_TYPE_IPV6: | |
453 | zlog_debug( | |
d6951e5e | 454 | " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", |
0ae8130d DS |
455 | inet_ntop(AF_INET6, &znh->gate.ipv6, buf, |
456 | sizeof(buf)), | |
457 | znh->type, znh->ifindex, znh->vrf_id, | |
458 | znh->label_num); | |
459 | break; | |
460 | case NEXTHOP_TYPE_IFINDEX: | |
d6951e5e | 461 | zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d", |
0ae8130d DS |
462 | znh->type, znh->ifindex); |
463 | break; | |
464 | case NEXTHOP_TYPE_BLACKHOLE: | |
d6951e5e | 465 | zlog_debug(" Nexthop blackhole"); |
0ae8130d DS |
466 | break; |
467 | } | |
468 | } | |
67a9eda9 DS |
469 | |
470 | return i; | |
471 | } | |
472 | static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) | |
473 | { | |
474 | struct sharp_nh_tracker *nht; | |
475 | struct zapi_route nhr; | |
476 | ||
477 | if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { | |
15569c58 | 478 | zlog_warn("%s: Decode of update failed", __func__); |
67a9eda9 DS |
479 | |
480 | return 0; | |
481 | } | |
482 | ||
483 | zlog_debug("Received update for %pFX", &nhr.prefix); | |
484 | ||
485 | nht = sharp_nh_tracker_get(&nhr.prefix); | |
486 | nht->nhop_num = nhr.nexthop_num; | |
487 | nht->updates++; | |
488 | ||
489 | sharp_debug_nexthops(&nhr); | |
490 | ||
491 | return 0; | |
492 | } | |
493 | ||
494 | static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS) | |
495 | { | |
496 | struct zapi_route api; | |
497 | ||
498 | if (zapi_route_decode(zclient->ibuf, &api) < 0) | |
15569c58 | 499 | zlog_warn("%s: Decode of redistribute failed: %d", __func__, |
67a9eda9 DS |
500 | ZEBRA_REDISTRIBUTE_ROUTE_ADD); |
501 | ||
502 | zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), | |
503 | &api.prefix, zebra_route_string(api.type)); | |
504 | ||
505 | sharp_debug_nexthops(&api); | |
506 | ||
0ae8130d DS |
507 | return 0; |
508 | } | |
509 | ||
2be4d61a MS |
510 | /* Add a zclient with a specified session id, for testing. */ |
511 | int sharp_zclient_create(uint32_t session_id) | |
512 | { | |
513 | struct zclient *client; | |
514 | struct sharp_zclient *node; | |
515 | ||
516 | /* Check for duplicates */ | |
517 | for (node = sharp_clients_head; node != NULL; node = node->next) { | |
518 | if (node->client->session_id == session_id) | |
519 | return -1; | |
520 | } | |
521 | ||
522 | client = zclient_new(master, &zclient_options_default); | |
523 | client->sock = -1; | |
524 | client->session_id = session_id; | |
525 | ||
526 | zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); | |
527 | ||
528 | /* Register handlers for messages we expect this session to see */ | |
529 | client->opaque_msg_handler = sharp_opaque_handler; | |
530 | ||
531 | /* Enqueue on the list of test clients */ | |
532 | add_zclient(client); | |
533 | ||
534 | return 0; | |
535 | } | |
536 | ||
537 | /* Delete one of the extra test zclients */ | |
538 | int sharp_zclient_delete(uint32_t session_id) | |
539 | { | |
540 | struct sharp_zclient *node; | |
541 | ||
542 | /* Search for session */ | |
543 | for (node = sharp_clients_head; node != NULL; node = node->next) { | |
544 | if (node->client->session_id == session_id) { | |
545 | /* Dequeue from list */ | |
546 | if (node->next) | |
547 | node->next->prev = node->prev; | |
548 | if (node->prev) | |
549 | node->prev->next = node->next; | |
550 | if (node == sharp_clients_head) | |
551 | sharp_clients_head = node->next; | |
552 | ||
553 | /* Clean up zclient */ | |
554 | zclient_stop(node->client); | |
555 | zclient_free(node->client); | |
556 | ||
557 | /* Free memory */ | |
558 | XFREE(MTYPE_ZC, node); | |
559 | break; | |
560 | } | |
561 | } | |
562 | ||
563 | return 0; | |
564 | } | |
565 | ||
7f5ac773 MS |
566 | /* Handler for opaque messages */ |
567 | static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) | |
568 | { | |
7f5ac773 | 569 | struct stream *s; |
387831ff | 570 | struct zapi_opaque_msg info; |
7f5ac773 MS |
571 | |
572 | s = zclient->ibuf; | |
573 | ||
387831ff MS |
574 | if (zclient_opaque_decode(s, &info) != 0) |
575 | return -1; | |
7f5ac773 | 576 | |
2be4d61a | 577 | zlog_debug("%s: [%u] received opaque type %u", __func__, |
c8b27f2a | 578 | zclient->session_id, info.type); |
7f5ac773 MS |
579 | |
580 | return 0; | |
581 | } | |
582 | ||
2ac6c90d MS |
583 | /* |
584 | * Send OPAQUE messages, using subtype 'type'. | |
585 | */ | |
c8b27f2a MS |
586 | void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance, |
587 | uint32_t session_id, uint32_t count) | |
2ac6c90d | 588 | { |
7f5ac773 | 589 | uint8_t buf[32]; |
2ac6c90d MS |
590 | int ret; |
591 | uint32_t i; | |
592 | ||
593 | /* Prepare a small payload */ | |
594 | for (i = 0; i < sizeof(buf); i++) { | |
595 | if (type < 255) | |
596 | buf[i] = type; | |
597 | else | |
598 | buf[i] = 255; | |
599 | } | |
600 | ||
c8b27f2a | 601 | /* Send some messages - broadcast and unicast are supported */ |
2ac6c90d | 602 | for (i = 0; i < count; i++) { |
c8b27f2a MS |
603 | if (proto == 0) |
604 | ret = zclient_send_opaque(zclient, type, buf, | |
605 | sizeof(buf)); | |
606 | else | |
607 | ret = zclient_send_opaque_unicast(zclient, type, proto, | |
608 | instance, session_id, | |
609 | buf, sizeof(buf)); | |
2ac6c90d MS |
610 | if (ret < 0) { |
611 | zlog_debug("%s: send_opaque() failed => %d", | |
612 | __func__, ret); | |
613 | break; | |
614 | } | |
615 | } | |
616 | ||
617 | } | |
618 | ||
939b2339 MS |
619 | /* |
620 | * Send OPAQUE registration messages, using subtype 'type'. | |
621 | */ | |
622 | void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance, | |
623 | uint32_t session_id, uint32_t type) | |
624 | { | |
625 | struct stream *s; | |
626 | ||
627 | s = zclient->obuf; | |
628 | stream_reset(s); | |
629 | ||
630 | if (is_reg) | |
631 | zclient_create_header(s, ZEBRA_OPAQUE_REGISTER, VRF_DEFAULT); | |
632 | else | |
633 | zclient_create_header(s, ZEBRA_OPAQUE_UNREGISTER, VRF_DEFAULT); | |
634 | ||
635 | /* Send sub-type */ | |
636 | stream_putl(s, type); | |
637 | ||
638 | /* Add zclient info */ | |
639 | stream_putc(s, proto); | |
640 | stream_putw(s, instance); | |
641 | stream_putl(s, session_id); | |
642 | ||
643 | /* Put length at the first point of the stream. */ | |
644 | stream_putw_at(s, 0, stream_get_endp(s)); | |
645 | ||
646 | (void)zclient_send_message(zclient); | |
647 | ||
648 | } | |
649 | ||
8a71d93d DS |
650 | void sharp_zebra_init(void) |
651 | { | |
996c9314 | 652 | struct zclient_options opt = {.receive_notify = true}; |
8a71d93d | 653 | |
138c5a74 DS |
654 | if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, |
655 | sharp_ifp_down, sharp_ifp_destroy); | |
656 | ||
26f63a1e | 657 | zclient = zclient_new(master, &opt); |
8a71d93d DS |
658 | |
659 | zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); | |
660 | zclient->zebra_connected = zebra_connected; | |
8a71d93d DS |
661 | zclient->interface_address_add = interface_address_add; |
662 | zclient->interface_address_delete = interface_address_delete; | |
28b11f81 | 663 | zclient->route_notify_owner = route_notify_owner; |
0ae8130d | 664 | zclient->nexthop_update = sharp_nexthop_update; |
b47dc61a | 665 | zclient->import_check_update = sharp_nexthop_update; |
67a9eda9 DS |
666 | |
667 | zclient->redistribute_route_add = sharp_redistribute_route; | |
668 | zclient->redistribute_route_del = sharp_redistribute_route; | |
7f5ac773 | 669 | zclient->opaque_msg_handler = sharp_opaque_handler; |
8a71d93d | 670 | } |