]>
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. */ | |
04cbc08f | 42 | extern struct thread_master *master; |
8a71d93d | 43 | |
2be4d61a | 44 | /* Privs info */ |
04cbc08f | 45 | extern struct zebra_privs_t sharp_privs; |
2be4d61a MS |
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 | ||
faa75dfa MS |
117 | int sharp_install_lsps_helper(bool install_p, bool update_p, |
118 | const struct prefix *p, uint8_t type, | |
119 | int instance, uint32_t in_label, | |
665edffd MS |
120 | const struct nexthop_group *nhg, |
121 | const struct nexthop_group *backup_nhg) | |
c9e5adba MS |
122 | { |
123 | struct zapi_labels zl = {}; | |
124 | struct zapi_nexthop *znh; | |
125 | const struct nexthop *nh; | |
faa75dfa | 126 | int i, cmd, ret; |
c9e5adba MS |
127 | |
128 | zl.type = ZEBRA_LSP_SHARP; | |
129 | zl.local_label = in_label; | |
130 | ||
131 | if (p) { | |
132 | SET_FLAG(zl.message, ZAPI_LABELS_FTN); | |
133 | prefix_copy(&zl.route.prefix, p); | |
134 | zl.route.type = type; | |
135 | zl.route.instance = instance; | |
136 | } | |
137 | ||
665edffd | 138 | /* List of nexthops is optional for delete */ |
c9e5adba | 139 | i = 0; |
665edffd MS |
140 | if (nhg) { |
141 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { | |
142 | znh = &zl.nexthops[i]; | |
143 | ||
144 | /* Must have labels to be useful */ | |
145 | if (nh->nh_label == NULL || | |
146 | nh->nh_label->num_labels == 0) | |
147 | continue; | |
148 | ||
149 | if (nh->type == NEXTHOP_TYPE_IFINDEX || | |
150 | nh->type == NEXTHOP_TYPE_BLACKHOLE) | |
151 | /* Hmm - can't really deal with these types */ | |
152 | continue; | |
153 | ||
154 | ret = zapi_nexthop_from_nexthop(znh, nh); | |
155 | if (ret < 0) | |
156 | return -1; | |
157 | ||
158 | i++; | |
474aebd9 MS |
159 | if (i >= MULTIPATH_NUM) |
160 | break; | |
665edffd MS |
161 | } |
162 | } | |
c9e5adba | 163 | |
665edffd MS |
164 | /* Whoops - no nexthops isn't very useful for install */ |
165 | if (i == 0 && install_p) | |
166 | return -1; | |
c9e5adba | 167 | |
665edffd | 168 | zl.nexthop_num = i; |
c9e5adba | 169 | |
665edffd MS |
170 | /* Add optional backup nexthop info. Since these are used by index, |
171 | * we can't just skip over an invalid backup nexthop: we will | |
172 | * invalidate the entire operation. | |
173 | */ | |
174 | if (backup_nhg != NULL) { | |
175 | i = 0; | |
176 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
177 | znh = &zl.backup_nexthops[i]; | |
c9e5adba | 178 | |
665edffd MS |
179 | /* Must have labels to be useful */ |
180 | if (nh->nh_label == NULL || | |
181 | nh->nh_label->num_labels == 0) | |
182 | return -1; | |
c9e5adba | 183 | |
665edffd MS |
184 | if (nh->type == NEXTHOP_TYPE_IFINDEX || |
185 | nh->type == NEXTHOP_TYPE_BLACKHOLE) | |
186 | /* Hmm - can't really deal with these types */ | |
187 | return -1; | |
c9e5adba | 188 | |
665edffd MS |
189 | ret = zapi_nexthop_from_nexthop(znh, nh); |
190 | if (ret < 0) | |
191 | return -1; | |
192 | ||
193 | i++; | |
474aebd9 MS |
194 | if (i >= MULTIPATH_NUM) |
195 | break; | |
665edffd MS |
196 | } |
197 | ||
198 | if (i > 0) | |
199 | SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS); | |
200 | ||
201 | zl.backup_nexthop_num = i; | |
202 | } | |
c9e5adba | 203 | |
faa75dfa MS |
204 | |
205 | if (install_p) { | |
206 | if (update_p) | |
207 | cmd = ZEBRA_MPLS_LABELS_REPLACE; | |
208 | else | |
209 | cmd = ZEBRA_MPLS_LABELS_ADD; | |
210 | } else { | |
211 | cmd = ZEBRA_MPLS_LABELS_DELETE; | |
212 | } | |
213 | ||
214 | ret = zebra_send_mpls_labels(zclient, cmd, &zl); | |
c9e5adba MS |
215 | |
216 | return ret; | |
217 | } | |
218 | ||
241e5df1 DS |
219 | /* |
220 | * route_add - Encodes a route to zebra | |
221 | * | |
222 | * This function returns true when the route was buffered | |
223 | * by the underlying stream system | |
224 | */ | |
225 | static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, | |
226 | uint32_t nhgid, const struct nexthop_group *nhg, | |
227 | const struct nexthop_group *backup_nhg) | |
228 | { | |
229 | struct zapi_route api; | |
230 | struct zapi_nexthop *api_nh; | |
231 | struct nexthop *nh; | |
232 | int i = 0; | |
233 | ||
234 | memset(&api, 0, sizeof(api)); | |
235 | api.vrf_id = vrf_id; | |
236 | api.type = ZEBRA_ROUTE_SHARP; | |
237 | api.instance = instance; | |
238 | api.safi = SAFI_UNICAST; | |
239 | memcpy(&api.prefix, p, sizeof(*p)); | |
240 | ||
241 | SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); | |
242 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); | |
243 | ||
244 | /* Only send via ID if nhgroup has been successfully installed */ | |
245 | if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) { | |
246 | SET_FLAG(api.message, ZAPI_MESSAGE_NHG); | |
247 | api.nhgid = nhgid; | |
248 | } else { | |
249 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { | |
250 | api_nh = &api.nexthops[i]; | |
251 | ||
252 | zapi_nexthop_from_nexthop(api_nh, nh); | |
253 | ||
254 | i++; | |
255 | } | |
256 | api.nexthop_num = i; | |
257 | } | |
258 | ||
259 | /* Include backup nexthops, if present */ | |
260 | if (backup_nhg && backup_nhg->nexthop) { | |
261 | SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS); | |
262 | ||
263 | i = 0; | |
264 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
265 | api_nh = &api.backup_nexthops[i]; | |
266 | ||
267 | zapi_backup_nexthop_from_nexthop(api_nh, nh); | |
268 | ||
269 | i++; | |
270 | } | |
271 | ||
272 | api.backup_nexthop_num = i; | |
273 | } | |
274 | ||
275 | if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api) == 1) | |
276 | return true; | |
277 | else | |
278 | return false; | |
279 | } | |
280 | ||
281 | /* | |
282 | * route_delete - Encodes a route for deletion to zebra | |
283 | * | |
284 | * This function returns true when the route sent was | |
285 | * buffered by the underlying stream system. | |
286 | */ | |
287 | static bool route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance) | |
288 | { | |
289 | struct zapi_route api; | |
290 | ||
291 | memset(&api, 0, sizeof(api)); | |
292 | api.vrf_id = vrf_id; | |
293 | api.type = ZEBRA_ROUTE_SHARP; | |
294 | api.safi = SAFI_UNICAST; | |
295 | api.instance = instance; | |
296 | memcpy(&api.prefix, p, sizeof(*p)); | |
297 | ||
298 | if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api) == 1) | |
299 | return true; | |
300 | else | |
301 | return false; | |
302 | } | |
303 | ||
0cf08685 | 304 | void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, |
569e87c0 | 305 | uint8_t instance, uint32_t nhgid, |
1df3b1dc MS |
306 | const struct nexthop_group *nhg, |
307 | const struct nexthop_group *backup_nhg, | |
6b98d34f DS |
308 | uint32_t routes) |
309 | { | |
310 | uint32_t temp, i; | |
dbc1bf46 | 311 | bool v4 = false; |
6b98d34f DS |
312 | |
313 | zlog_debug("Inserting %u routes", routes); | |
314 | ||
dbc1bf46 DS |
315 | if (p->family == AF_INET) { |
316 | v4 = true; | |
317 | temp = ntohl(p->u.prefix4.s_addr); | |
318 | } else | |
319 | temp = ntohl(p->u.val32[3]); | |
320 | ||
1df3b1dc MS |
321 | /* Only use backup route/nexthops if present */ |
322 | if (backup_nhg && (backup_nhg->nexthop == NULL)) | |
323 | backup_nhg = NULL; | |
324 | ||
547dc642 | 325 | monotime(&sg.r.t_start); |
6b98d34f | 326 | for (i = 0; i < routes; i++) { |
569e87c0 | 327 | route_add(p, vrf_id, (uint8_t)instance, nhgid, nhg, backup_nhg); |
dbc1bf46 DS |
328 | if (v4) |
329 | p->u.prefix4.s_addr = htonl(++temp); | |
330 | else | |
331 | p->u.val32[3] = htonl(++temp); | |
6b98d34f DS |
332 | } |
333 | } | |
334 | ||
0cf08685 DS |
335 | void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, |
336 | uint8_t instance, uint32_t routes) | |
6b98d34f DS |
337 | { |
338 | uint32_t temp, i; | |
dbc1bf46 | 339 | bool v4 = false; |
6b98d34f DS |
340 | |
341 | zlog_debug("Removing %u routes", routes); | |
342 | ||
dbc1bf46 DS |
343 | if (p->family == AF_INET) { |
344 | v4 = true; | |
345 | temp = ntohl(p->u.prefix4.s_addr); | |
346 | } else | |
347 | temp = ntohl(p->u.val32[3]); | |
348 | ||
547dc642 | 349 | monotime(&sg.r.t_start); |
6b98d34f | 350 | for (i = 0; i < routes; i++) { |
0cf08685 | 351 | route_delete(p, vrf_id, (uint8_t)instance); |
dbc1bf46 DS |
352 | if (v4) |
353 | p->u.prefix4.s_addr = htonl(++temp); | |
354 | else | |
355 | p->u.val32[3] = htonl(++temp); | |
6b98d34f DS |
356 | } |
357 | } | |
358 | ||
b939f6ff | 359 | static void handle_repeated(bool installed) |
6b98d34f | 360 | { |
547dc642 DS |
361 | struct prefix p = sg.r.orig_prefix; |
362 | sg.r.repeat--; | |
6b98d34f | 363 | |
547dc642 | 364 | if (sg.r.repeat <= 0) |
6b98d34f DS |
365 | return; |
366 | ||
367 | if (installed) { | |
547dc642 | 368 | sg.r.removed_routes = 0; |
0cf08685 DS |
369 | sharp_remove_routes_helper(&p, sg.r.vrf_id, |
370 | sg.r.inst, sg.r.total_routes); | |
6b98d34f DS |
371 | } |
372 | ||
f54f37c1 | 373 | if (!installed) { |
547dc642 | 374 | sg.r.installed_routes = 0; |
0cf08685 | 375 | sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, |
ff9aca4f | 376 | sg.r.nhgid, &sg.r.nhop_group, |
1df3b1dc | 377 | &sg.r.backup_nhop_group, |
547dc642 | 378 | sg.r.total_routes); |
6b98d34f DS |
379 | } |
380 | } | |
381 | ||
121f9dee | 382 | static int route_notify_owner(ZAPI_CALLBACK_ARGS) |
8a71d93d | 383 | { |
25c84d86 | 384 | struct timeval r; |
8a71d93d DS |
385 | struct prefix p; |
386 | enum zapi_route_notify_owner note; | |
28610f7e | 387 | uint32_t table; |
8a71d93d | 388 | |
77b38a4a S |
389 | if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, ¬e, |
390 | NULL, NULL)) | |
8a71d93d DS |
391 | return -1; |
392 | ||
5e54c602 DS |
393 | switch (note) { |
394 | case ZAPI_ROUTE_INSTALLED: | |
547dc642 DS |
395 | sg.r.installed_routes++; |
396 | if (sg.r.total_routes == sg.r.installed_routes) { | |
397 | monotime(&sg.r.t_end); | |
398 | timersub(&sg.r.t_end, &sg.r.t_start, &r); | |
051a0be4 DL |
399 | zlog_debug("Installed All Items %jd.%ld", |
400 | (intmax_t)r.tv_sec, (long)r.tv_usec); | |
6b98d34f DS |
401 | handle_repeated(true); |
402 | } | |
5e54c602 DS |
403 | break; |
404 | case ZAPI_ROUTE_FAIL_INSTALL: | |
405 | zlog_debug("Failed install of route"); | |
406 | break; | |
407 | case ZAPI_ROUTE_BETTER_ADMIN_WON: | |
408 | zlog_debug("Better Admin Distance won over us"); | |
409 | break; | |
410 | case ZAPI_ROUTE_REMOVED: | |
547dc642 DS |
411 | sg.r.removed_routes++; |
412 | if (sg.r.total_routes == sg.r.removed_routes) { | |
413 | monotime(&sg.r.t_end); | |
414 | timersub(&sg.r.t_end, &sg.r.t_start, &r); | |
051a0be4 DL |
415 | zlog_debug("Removed all Items %jd.%ld", |
416 | (intmax_t)r.tv_sec, (long)r.tv_usec); | |
6b98d34f DS |
417 | handle_repeated(false); |
418 | } | |
5e54c602 DS |
419 | break; |
420 | case ZAPI_ROUTE_REMOVE_FAIL: | |
421 | zlog_debug("Route removal Failure"); | |
422 | break; | |
423 | } | |
8a71d93d DS |
424 | return 0; |
425 | } | |
426 | ||
427 | static void zebra_connected(struct zclient *zclient) | |
428 | { | |
429 | zclient_send_reg_requests(zclient, VRF_DEFAULT); | |
67a9eda9 DS |
430 | |
431 | /* | |
432 | * Do not actually turn this on yet | |
433 | * This is just the start of the infrastructure needed here | |
434 | * This can be fixed at a later time. | |
435 | * | |
436 | * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, | |
437 | * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); | |
438 | */ | |
8a71d93d DS |
439 | } |
440 | ||
7d061b3c | 441 | void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) |
ab18a495 | 442 | { |
7d061b3c | 443 | zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); |
ab18a495 DS |
444 | } |
445 | ||
21735352 SW |
446 | void nhg_add(uint32_t id, const struct nexthop_group *nhg, |
447 | const struct nexthop_group *backup_nhg) | |
569e87c0 | 448 | { |
c6ce9334 | 449 | struct zapi_nhg api_nhg = {}; |
569e87c0 | 450 | struct zapi_nexthop *api_nh; |
569e87c0 DS |
451 | struct nexthop *nh; |
452 | ||
c6ce9334 | 453 | api_nhg.id = id; |
569e87c0 | 454 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { |
c6ce9334 | 455 | if (api_nhg.nexthop_num >= MULTIPATH_NUM) { |
54a701e4 SW |
456 | zlog_warn( |
457 | "%s: number of nexthops greater than max multipath size, truncating", | |
458 | __func__); | |
459 | break; | |
460 | } | |
461 | ||
c6ce9334 | 462 | api_nh = &api_nhg.nexthops[api_nhg.nexthop_num]; |
569e87c0 DS |
463 | |
464 | zapi_nexthop_from_nexthop(api_nh, nh); | |
c6ce9334 | 465 | api_nhg.nexthop_num++; |
569e87c0 DS |
466 | } |
467 | ||
21735352 SW |
468 | if (backup_nhg) { |
469 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
470 | if (api_nhg.backup_nexthop_num >= MULTIPATH_NUM) { | |
471 | zlog_warn( | |
472 | "%s: number of backup nexthops greater than max multipath size, truncating", | |
473 | __func__); | |
474 | break; | |
475 | } | |
476 | api_nh = &api_nhg.backup_nexthops | |
477 | [api_nhg.backup_nexthop_num]; | |
478 | ||
479 | zapi_backup_nexthop_from_nexthop(api_nh, nh); | |
480 | api_nhg.backup_nexthop_num++; | |
481 | } | |
482 | } | |
483 | ||
c6ce9334 | 484 | zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg); |
569e87c0 DS |
485 | } |
486 | ||
487 | void nhg_del(uint32_t id) | |
488 | { | |
c6ce9334 SW |
489 | struct zapi_nhg api_nhg = {}; |
490 | ||
491 | api_nhg.id = id; | |
492 | ||
493 | zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg); | |
569e87c0 DS |
494 | } |
495 | ||
91529dc8 | 496 | void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, |
b47dc61a | 497 | bool watch, bool connected) |
0ae8130d | 498 | { |
b47dc61a | 499 | int command; |
0ae8130d | 500 | |
b47dc61a DS |
501 | if (!import) { |
502 | command = ZEBRA_NEXTHOP_REGISTER; | |
503 | ||
504 | if (!watch) | |
505 | command = ZEBRA_NEXTHOP_UNREGISTER; | |
506 | } else { | |
507 | command = ZEBRA_IMPORT_ROUTE_REGISTER; | |
508 | ||
509 | if (!watch) | |
510 | command = ZEBRA_IMPORT_ROUTE_UNREGISTER; | |
511 | } | |
0ae8130d | 512 | |
91529dc8 | 513 | if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0) |
15569c58 | 514 | zlog_warn("%s: Failure to send nexthop to zebra", __func__); |
0ae8130d DS |
515 | } |
516 | ||
67a9eda9 | 517 | static int sharp_debug_nexthops(struct zapi_route *api) |
0ae8130d | 518 | { |
0ae8130d | 519 | int i; |
67a9eda9 | 520 | char buf[PREFIX_STRLEN]; |
0ae8130d | 521 | |
8b85b2cb MS |
522 | if (api->nexthop_num == 0) { |
523 | zlog_debug( | |
524 | " Not installed"); | |
525 | return 0; | |
526 | } | |
527 | ||
67a9eda9 DS |
528 | for (i = 0; i < api->nexthop_num; i++) { |
529 | struct zapi_nexthop *znh = &api->nexthops[i]; | |
0ae8130d DS |
530 | |
531 | switch (znh->type) { | |
532 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
533 | case NEXTHOP_TYPE_IPV4: | |
534 | zlog_debug( | |
d6951e5e | 535 | " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", |
0ae8130d DS |
536 | inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf, |
537 | sizeof(buf)), | |
538 | znh->type, znh->ifindex, znh->vrf_id, | |
539 | znh->label_num); | |
540 | break; | |
541 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
542 | case NEXTHOP_TYPE_IPV6: | |
543 | zlog_debug( | |
d6951e5e | 544 | " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", |
0ae8130d DS |
545 | inet_ntop(AF_INET6, &znh->gate.ipv6, buf, |
546 | sizeof(buf)), | |
547 | znh->type, znh->ifindex, znh->vrf_id, | |
548 | znh->label_num); | |
549 | break; | |
550 | case NEXTHOP_TYPE_IFINDEX: | |
d6951e5e | 551 | zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d", |
0ae8130d DS |
552 | znh->type, znh->ifindex); |
553 | break; | |
554 | case NEXTHOP_TYPE_BLACKHOLE: | |
d6951e5e | 555 | zlog_debug(" Nexthop blackhole"); |
0ae8130d DS |
556 | break; |
557 | } | |
558 | } | |
67a9eda9 DS |
559 | |
560 | return i; | |
561 | } | |
562 | static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) | |
563 | { | |
564 | struct sharp_nh_tracker *nht; | |
565 | struct zapi_route nhr; | |
566 | ||
567 | if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { | |
6c83dded | 568 | zlog_err("%s: Decode of update failed", __func__); |
67a9eda9 DS |
569 | return 0; |
570 | } | |
571 | ||
572 | zlog_debug("Received update for %pFX", &nhr.prefix); | |
573 | ||
574 | nht = sharp_nh_tracker_get(&nhr.prefix); | |
575 | nht->nhop_num = nhr.nexthop_num; | |
576 | nht->updates++; | |
577 | ||
578 | sharp_debug_nexthops(&nhr); | |
579 | ||
580 | return 0; | |
581 | } | |
582 | ||
583 | static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS) | |
584 | { | |
585 | struct zapi_route api; | |
586 | ||
587 | if (zapi_route_decode(zclient->ibuf, &api) < 0) | |
15569c58 | 588 | zlog_warn("%s: Decode of redistribute failed: %d", __func__, |
67a9eda9 DS |
589 | ZEBRA_REDISTRIBUTE_ROUTE_ADD); |
590 | ||
591 | zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), | |
592 | &api.prefix, zebra_route_string(api.type)); | |
593 | ||
594 | sharp_debug_nexthops(&api); | |
595 | ||
0ae8130d DS |
596 | return 0; |
597 | } | |
598 | ||
2be4d61a MS |
599 | /* Add a zclient with a specified session id, for testing. */ |
600 | int sharp_zclient_create(uint32_t session_id) | |
601 | { | |
602 | struct zclient *client; | |
603 | struct sharp_zclient *node; | |
604 | ||
605 | /* Check for duplicates */ | |
606 | for (node = sharp_clients_head; node != NULL; node = node->next) { | |
607 | if (node->client->session_id == session_id) | |
608 | return -1; | |
609 | } | |
610 | ||
611 | client = zclient_new(master, &zclient_options_default); | |
612 | client->sock = -1; | |
613 | client->session_id = session_id; | |
614 | ||
615 | zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); | |
616 | ||
617 | /* Register handlers for messages we expect this session to see */ | |
618 | client->opaque_msg_handler = sharp_opaque_handler; | |
619 | ||
620 | /* Enqueue on the list of test clients */ | |
621 | add_zclient(client); | |
622 | ||
623 | return 0; | |
624 | } | |
625 | ||
626 | /* Delete one of the extra test zclients */ | |
627 | int sharp_zclient_delete(uint32_t session_id) | |
628 | { | |
629 | struct sharp_zclient *node; | |
630 | ||
631 | /* Search for session */ | |
632 | for (node = sharp_clients_head; node != NULL; node = node->next) { | |
633 | if (node->client->session_id == session_id) { | |
634 | /* Dequeue from list */ | |
635 | if (node->next) | |
636 | node->next->prev = node->prev; | |
637 | if (node->prev) | |
638 | node->prev->next = node->next; | |
639 | if (node == sharp_clients_head) | |
640 | sharp_clients_head = node->next; | |
641 | ||
642 | /* Clean up zclient */ | |
643 | zclient_stop(node->client); | |
644 | zclient_free(node->client); | |
645 | ||
646 | /* Free memory */ | |
647 | XFREE(MTYPE_ZC, node); | |
648 | break; | |
649 | } | |
650 | } | |
651 | ||
652 | return 0; | |
653 | } | |
654 | ||
7f5ac773 MS |
655 | /* Handler for opaque messages */ |
656 | static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) | |
657 | { | |
7f5ac773 | 658 | struct stream *s; |
387831ff | 659 | struct zapi_opaque_msg info; |
7f5ac773 MS |
660 | |
661 | s = zclient->ibuf; | |
662 | ||
387831ff MS |
663 | if (zclient_opaque_decode(s, &info) != 0) |
664 | return -1; | |
7f5ac773 | 665 | |
2be4d61a | 666 | zlog_debug("%s: [%u] received opaque type %u", __func__, |
c8b27f2a | 667 | zclient->session_id, info.type); |
7f5ac773 MS |
668 | |
669 | return 0; | |
670 | } | |
671 | ||
2ac6c90d MS |
672 | /* |
673 | * Send OPAQUE messages, using subtype 'type'. | |
674 | */ | |
c8b27f2a MS |
675 | void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance, |
676 | uint32_t session_id, uint32_t count) | |
2ac6c90d | 677 | { |
7f5ac773 | 678 | uint8_t buf[32]; |
2ac6c90d MS |
679 | int ret; |
680 | uint32_t i; | |
681 | ||
682 | /* Prepare a small payload */ | |
683 | for (i = 0; i < sizeof(buf); i++) { | |
684 | if (type < 255) | |
685 | buf[i] = type; | |
686 | else | |
687 | buf[i] = 255; | |
688 | } | |
689 | ||
c8b27f2a | 690 | /* Send some messages - broadcast and unicast are supported */ |
2ac6c90d | 691 | for (i = 0; i < count; i++) { |
c8b27f2a MS |
692 | if (proto == 0) |
693 | ret = zclient_send_opaque(zclient, type, buf, | |
694 | sizeof(buf)); | |
695 | else | |
696 | ret = zclient_send_opaque_unicast(zclient, type, proto, | |
697 | instance, session_id, | |
698 | buf, sizeof(buf)); | |
2ac6c90d MS |
699 | if (ret < 0) { |
700 | zlog_debug("%s: send_opaque() failed => %d", | |
701 | __func__, ret); | |
702 | break; | |
703 | } | |
704 | } | |
705 | ||
706 | } | |
707 | ||
939b2339 MS |
708 | /* |
709 | * Send OPAQUE registration messages, using subtype 'type'. | |
710 | */ | |
711 | void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance, | |
712 | uint32_t session_id, uint32_t type) | |
713 | { | |
714 | struct stream *s; | |
715 | ||
716 | s = zclient->obuf; | |
717 | stream_reset(s); | |
718 | ||
719 | if (is_reg) | |
720 | zclient_create_header(s, ZEBRA_OPAQUE_REGISTER, VRF_DEFAULT); | |
721 | else | |
722 | zclient_create_header(s, ZEBRA_OPAQUE_UNREGISTER, VRF_DEFAULT); | |
723 | ||
724 | /* Send sub-type */ | |
725 | stream_putl(s, type); | |
726 | ||
727 | /* Add zclient info */ | |
728 | stream_putc(s, proto); | |
729 | stream_putw(s, instance); | |
730 | stream_putl(s, session_id); | |
731 | ||
732 | /* Put length at the first point of the stream. */ | |
733 | stream_putw_at(s, 0, stream_get_endp(s)); | |
734 | ||
735 | (void)zclient_send_message(zclient); | |
736 | ||
737 | } | |
738 | ||
da187b77 JU |
739 | void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p) |
740 | { | |
741 | zclient_send_neigh_discovery_req(zclient, ifp, p); | |
742 | } | |
743 | ||
2053061b SW |
744 | static int nhg_notify_owner(ZAPI_CALLBACK_ARGS) |
745 | { | |
746 | enum zapi_nhg_notify_owner note; | |
747 | uint32_t id; | |
748 | ||
749 | if (!zapi_nhg_notify_decode(zclient->ibuf, &id, ¬e)) | |
750 | return -1; | |
751 | ||
752 | switch (note) { | |
753 | case ZAPI_NHG_INSTALLED: | |
754 | sharp_nhgroup_id_set_installed(id, true); | |
755 | zlog_debug("Installed nhg %u", id); | |
756 | break; | |
757 | case ZAPI_NHG_FAIL_INSTALL: | |
758 | zlog_debug("Failed install of nhg %u", id); | |
759 | break; | |
760 | case ZAPI_NHG_REMOVED: | |
761 | zlog_debug("Removed nhg %u", id); | |
762 | break; | |
763 | case ZAPI_NHG_REMOVE_FAIL: | |
764 | zlog_debug("Failed removal of nhg %u", id); | |
765 | break; | |
766 | } | |
767 | ||
768 | return 0; | |
769 | } | |
770 | ||
8a71d93d DS |
771 | void sharp_zebra_init(void) |
772 | { | |
996c9314 | 773 | struct zclient_options opt = {.receive_notify = true}; |
8a71d93d | 774 | |
138c5a74 DS |
775 | if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, |
776 | sharp_ifp_down, sharp_ifp_destroy); | |
777 | ||
26f63a1e | 778 | zclient = zclient_new(master, &opt); |
8a71d93d DS |
779 | |
780 | zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); | |
781 | zclient->zebra_connected = zebra_connected; | |
8a71d93d DS |
782 | zclient->interface_address_add = interface_address_add; |
783 | zclient->interface_address_delete = interface_address_delete; | |
28b11f81 | 784 | zclient->route_notify_owner = route_notify_owner; |
0ae8130d | 785 | zclient->nexthop_update = sharp_nexthop_update; |
b47dc61a | 786 | zclient->import_check_update = sharp_nexthop_update; |
2053061b | 787 | zclient->nhg_notify_owner = nhg_notify_owner; |
67a9eda9 DS |
788 | |
789 | zclient->redistribute_route_add = sharp_redistribute_route; | |
790 | zclient->redistribute_route_del = sharp_redistribute_route; | |
7f5ac773 | 791 | zclient->opaque_msg_handler = sharp_opaque_handler; |
8a71d93d | 792 | } |