]>
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" |
1888e243 | 33 | #include "link_state.h" |
8a71d93d | 34 | |
547dc642 | 35 | #include "sharp_globals.h" |
86da53ab | 36 | #include "sharp_nht.h" |
8a71d93d DS |
37 | #include "sharp_zebra.h" |
38 | ||
39 | /* Zebra structure to hold current status. */ | |
40 | struct zclient *zclient = NULL; | |
41 | ||
42 | /* For registering threads. */ | |
04cbc08f | 43 | extern struct thread_master *master; |
8a71d93d | 44 | |
2be4d61a | 45 | /* Privs info */ |
04cbc08f | 46 | extern struct zebra_privs_t sharp_privs; |
2be4d61a MS |
47 | |
48 | DEFINE_MTYPE_STATIC(SHARPD, ZC, "Test zclients"); | |
49 | ||
50 | /* Struct to hold list of test zclients */ | |
51 | struct sharp_zclient { | |
52 | struct sharp_zclient *prev; | |
53 | struct sharp_zclient *next; | |
54 | struct zclient *client; | |
55 | }; | |
56 | ||
57 | /* Head of test zclient list */ | |
58 | static struct sharp_zclient *sharp_clients_head; | |
59 | ||
60 | static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS); | |
61 | ||
62 | /* Utility to add a test zclient struct to the list */ | |
63 | static void add_zclient(struct zclient *client) | |
64 | { | |
65 | struct sharp_zclient *node; | |
66 | ||
67 | node = XCALLOC(MTYPE_ZC, sizeof(struct sharp_zclient)); | |
68 | ||
69 | node->client = client; | |
70 | ||
71 | node->next = sharp_clients_head; | |
72 | if (sharp_clients_head) | |
73 | sharp_clients_head->prev = node; | |
74 | sharp_clients_head = node; | |
75 | } | |
76 | ||
77 | /* Interface addition message from zebra. */ | |
ef7bd2a3 | 78 | static int sharp_ifp_create(struct interface *ifp) |
8a71d93d | 79 | { |
8a71d93d DS |
80 | return 0; |
81 | } | |
82 | ||
3c3c3252 | 83 | static int sharp_ifp_destroy(struct interface *ifp) |
8a71d93d | 84 | { |
8a71d93d DS |
85 | return 0; |
86 | } | |
87 | ||
121f9dee | 88 | static int interface_address_add(ZAPI_CALLBACK_ARGS) |
8a71d93d | 89 | { |
121f9dee | 90 | zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
8a71d93d DS |
91 | |
92 | return 0; | |
93 | } | |
94 | ||
121f9dee | 95 | static int interface_address_delete(ZAPI_CALLBACK_ARGS) |
8a71d93d DS |
96 | { |
97 | struct connected *c; | |
98 | ||
121f9dee | 99 | c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
8a71d93d DS |
100 | |
101 | if (!c) | |
102 | return 0; | |
103 | ||
721c0857 | 104 | connected_free(&c); |
8a71d93d DS |
105 | return 0; |
106 | } | |
107 | ||
ddbf3e60 | 108 | static int sharp_ifp_up(struct interface *ifp) |
8a71d93d | 109 | { |
8a71d93d DS |
110 | return 0; |
111 | } | |
112 | ||
b0b69e59 | 113 | static int sharp_ifp_down(struct interface *ifp) |
8a71d93d | 114 | { |
8a71d93d DS |
115 | return 0; |
116 | } | |
117 | ||
faa75dfa MS |
118 | int sharp_install_lsps_helper(bool install_p, bool update_p, |
119 | const struct prefix *p, uint8_t type, | |
120 | int instance, uint32_t in_label, | |
665edffd MS |
121 | const struct nexthop_group *nhg, |
122 | const struct nexthop_group *backup_nhg) | |
c9e5adba MS |
123 | { |
124 | struct zapi_labels zl = {}; | |
125 | struct zapi_nexthop *znh; | |
126 | const struct nexthop *nh; | |
faa75dfa | 127 | int i, cmd, ret; |
c9e5adba MS |
128 | |
129 | zl.type = ZEBRA_LSP_SHARP; | |
130 | zl.local_label = in_label; | |
131 | ||
132 | if (p) { | |
133 | SET_FLAG(zl.message, ZAPI_LABELS_FTN); | |
134 | prefix_copy(&zl.route.prefix, p); | |
135 | zl.route.type = type; | |
136 | zl.route.instance = instance; | |
137 | } | |
138 | ||
665edffd | 139 | /* List of nexthops is optional for delete */ |
c9e5adba | 140 | i = 0; |
665edffd MS |
141 | if (nhg) { |
142 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { | |
143 | znh = &zl.nexthops[i]; | |
144 | ||
145 | /* Must have labels to be useful */ | |
146 | if (nh->nh_label == NULL || | |
147 | nh->nh_label->num_labels == 0) | |
148 | continue; | |
149 | ||
150 | if (nh->type == NEXTHOP_TYPE_IFINDEX || | |
151 | nh->type == NEXTHOP_TYPE_BLACKHOLE) | |
152 | /* Hmm - can't really deal with these types */ | |
153 | continue; | |
154 | ||
155 | ret = zapi_nexthop_from_nexthop(znh, nh); | |
156 | if (ret < 0) | |
157 | return -1; | |
158 | ||
159 | i++; | |
474aebd9 MS |
160 | if (i >= MULTIPATH_NUM) |
161 | break; | |
665edffd MS |
162 | } |
163 | } | |
c9e5adba | 164 | |
665edffd MS |
165 | /* Whoops - no nexthops isn't very useful for install */ |
166 | if (i == 0 && install_p) | |
167 | return -1; | |
c9e5adba | 168 | |
665edffd | 169 | zl.nexthop_num = i; |
c9e5adba | 170 | |
665edffd MS |
171 | /* Add optional backup nexthop info. Since these are used by index, |
172 | * we can't just skip over an invalid backup nexthop: we will | |
173 | * invalidate the entire operation. | |
174 | */ | |
175 | if (backup_nhg != NULL) { | |
176 | i = 0; | |
177 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
178 | znh = &zl.backup_nexthops[i]; | |
c9e5adba | 179 | |
665edffd MS |
180 | /* Must have labels to be useful */ |
181 | if (nh->nh_label == NULL || | |
182 | nh->nh_label->num_labels == 0) | |
183 | return -1; | |
c9e5adba | 184 | |
665edffd MS |
185 | if (nh->type == NEXTHOP_TYPE_IFINDEX || |
186 | nh->type == NEXTHOP_TYPE_BLACKHOLE) | |
187 | /* Hmm - can't really deal with these types */ | |
188 | return -1; | |
c9e5adba | 189 | |
665edffd MS |
190 | ret = zapi_nexthop_from_nexthop(znh, nh); |
191 | if (ret < 0) | |
192 | return -1; | |
193 | ||
194 | i++; | |
474aebd9 MS |
195 | if (i >= MULTIPATH_NUM) |
196 | break; | |
665edffd MS |
197 | } |
198 | ||
199 | if (i > 0) | |
200 | SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS); | |
201 | ||
202 | zl.backup_nexthop_num = i; | |
203 | } | |
c9e5adba | 204 | |
faa75dfa MS |
205 | |
206 | if (install_p) { | |
207 | if (update_p) | |
208 | cmd = ZEBRA_MPLS_LABELS_REPLACE; | |
209 | else | |
210 | cmd = ZEBRA_MPLS_LABELS_ADD; | |
211 | } else { | |
212 | cmd = ZEBRA_MPLS_LABELS_DELETE; | |
213 | } | |
214 | ||
7cfdb485 DS |
215 | if (zebra_send_mpls_labels(zclient, cmd, &zl) == ZCLIENT_SEND_FAILURE) |
216 | return -1; | |
c9e5adba | 217 | |
7cfdb485 | 218 | return 0; |
c9e5adba MS |
219 | } |
220 | ||
07414912 DS |
221 | enum where_to_restart { |
222 | SHARP_INSTALL_ROUTES_RESTART, | |
223 | SHARP_DELETE_ROUTES_RESTART, | |
224 | }; | |
225 | ||
226 | struct buffer_delay { | |
227 | struct prefix p; | |
228 | uint32_t count; | |
229 | uint32_t routes; | |
230 | vrf_id_t vrf_id; | |
231 | uint8_t instance; | |
232 | uint32_t nhgid; | |
c27b47d7 | 233 | uint32_t flags; |
07414912 DS |
234 | const struct nexthop_group *nhg; |
235 | const struct nexthop_group *backup_nhg; | |
236 | enum where_to_restart restart; | |
cfa2a35d | 237 | char *opaque; |
07414912 DS |
238 | } wb; |
239 | ||
241e5df1 DS |
240 | /* |
241 | * route_add - Encodes a route to zebra | |
242 | * | |
243 | * This function returns true when the route was buffered | |
244 | * by the underlying stream system | |
245 | */ | |
246 | static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, | |
247 | uint32_t nhgid, const struct nexthop_group *nhg, | |
c27b47d7 HS |
248 | const struct nexthop_group *backup_nhg, uint32_t flags, |
249 | char *opaque) | |
241e5df1 DS |
250 | { |
251 | struct zapi_route api; | |
252 | struct zapi_nexthop *api_nh; | |
253 | struct nexthop *nh; | |
254 | int i = 0; | |
255 | ||
256 | memset(&api, 0, sizeof(api)); | |
257 | api.vrf_id = vrf_id; | |
258 | api.type = ZEBRA_ROUTE_SHARP; | |
259 | api.instance = instance; | |
260 | api.safi = SAFI_UNICAST; | |
261 | memcpy(&api.prefix, p, sizeof(*p)); | |
262 | ||
c27b47d7 | 263 | api.flags = flags; |
241e5df1 DS |
264 | SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); |
265 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); | |
266 | ||
267 | /* Only send via ID if nhgroup has been successfully installed */ | |
268 | if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) { | |
269 | SET_FLAG(api.message, ZAPI_MESSAGE_NHG); | |
270 | api.nhgid = nhgid; | |
271 | } else { | |
272 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { | |
273 | api_nh = &api.nexthops[i]; | |
274 | ||
275 | zapi_nexthop_from_nexthop(api_nh, nh); | |
276 | ||
277 | i++; | |
278 | } | |
279 | api.nexthop_num = i; | |
280 | } | |
281 | ||
282 | /* Include backup nexthops, if present */ | |
283 | if (backup_nhg && backup_nhg->nexthop) { | |
284 | SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS); | |
285 | ||
286 | i = 0; | |
287 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
288 | api_nh = &api.backup_nexthops[i]; | |
289 | ||
290 | zapi_backup_nexthop_from_nexthop(api_nh, nh); | |
291 | ||
292 | i++; | |
293 | } | |
294 | ||
295 | api.backup_nexthop_num = i; | |
296 | } | |
297 | ||
cfa2a35d DS |
298 | if (strlen(opaque)) { |
299 | SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE); | |
300 | api.opaque.length = strlen(opaque) + 1; | |
301 | assert(api.opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH); | |
302 | memcpy(api.opaque.data, opaque, api.opaque.length); | |
303 | } | |
304 | ||
8a3f8f2e DS |
305 | if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api) |
306 | == ZCLIENT_SEND_BUFFERED) | |
241e5df1 DS |
307 | return true; |
308 | else | |
309 | return false; | |
310 | } | |
311 | ||
312 | /* | |
313 | * route_delete - Encodes a route for deletion to zebra | |
314 | * | |
315 | * This function returns true when the route sent was | |
316 | * buffered by the underlying stream system. | |
317 | */ | |
318 | static bool route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance) | |
319 | { | |
320 | struct zapi_route api; | |
321 | ||
322 | memset(&api, 0, sizeof(api)); | |
323 | api.vrf_id = vrf_id; | |
324 | api.type = ZEBRA_ROUTE_SHARP; | |
325 | api.safi = SAFI_UNICAST; | |
326 | api.instance = instance; | |
327 | memcpy(&api.prefix, p, sizeof(*p)); | |
328 | ||
8a3f8f2e DS |
329 | if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api) |
330 | == ZCLIENT_SEND_BUFFERED) | |
241e5df1 DS |
331 | return true; |
332 | else | |
333 | return false; | |
334 | } | |
335 | ||
07414912 DS |
336 | static void sharp_install_routes_restart(struct prefix *p, uint32_t count, |
337 | vrf_id_t vrf_id, uint8_t instance, | |
338 | uint32_t nhgid, | |
339 | const struct nexthop_group *nhg, | |
340 | const struct nexthop_group *backup_nhg, | |
4df9d859 HS |
341 | uint32_t routes, uint32_t flags, |
342 | char *opaque) | |
6b98d34f DS |
343 | { |
344 | uint32_t temp, i; | |
dbc1bf46 | 345 | bool v4 = false; |
6b98d34f | 346 | |
dbc1bf46 DS |
347 | if (p->family == AF_INET) { |
348 | v4 = true; | |
349 | temp = ntohl(p->u.prefix4.s_addr); | |
350 | } else | |
351 | temp = ntohl(p->u.val32[3]); | |
352 | ||
07414912 DS |
353 | for (i = count; i < routes; i++) { |
354 | bool buffered = route_add(p, vrf_id, (uint8_t)instance, nhgid, | |
c27b47d7 | 355 | nhg, backup_nhg, flags, opaque); |
dbc1bf46 DS |
356 | if (v4) |
357 | p->u.prefix4.s_addr = htonl(++temp); | |
358 | else | |
359 | p->u.val32[3] = htonl(++temp); | |
07414912 DS |
360 | |
361 | if (buffered) { | |
362 | wb.p = *p; | |
363 | wb.count = i+1; | |
364 | wb.routes = routes; | |
365 | wb.vrf_id = vrf_id; | |
366 | wb.instance = instance; | |
367 | wb.nhgid = nhgid; | |
368 | wb.nhg = nhg; | |
c27b47d7 | 369 | wb.flags = flags; |
07414912 | 370 | wb.backup_nhg = backup_nhg; |
cfa2a35d | 371 | wb.opaque = opaque; |
07414912 DS |
372 | wb.restart = SHARP_INSTALL_ROUTES_RESTART; |
373 | ||
374 | return; | |
375 | } | |
6b98d34f DS |
376 | } |
377 | } | |
378 | ||
07414912 DS |
379 | void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, |
380 | uint8_t instance, uint32_t nhgid, | |
381 | const struct nexthop_group *nhg, | |
382 | const struct nexthop_group *backup_nhg, | |
c27b47d7 | 383 | uint32_t routes, uint32_t flags, char *opaque) |
07414912 DS |
384 | { |
385 | zlog_debug("Inserting %u routes", routes); | |
386 | ||
387 | /* Only use backup route/nexthops if present */ | |
388 | if (backup_nhg && (backup_nhg->nexthop == NULL)) | |
389 | backup_nhg = NULL; | |
390 | ||
391 | monotime(&sg.r.t_start); | |
392 | sharp_install_routes_restart(p, 0, vrf_id, instance, nhgid, nhg, | |
c27b47d7 | 393 | backup_nhg, routes, flags, opaque); |
07414912 DS |
394 | } |
395 | ||
396 | static void sharp_remove_routes_restart(struct prefix *p, uint32_t count, | |
397 | vrf_id_t vrf_id, uint8_t instance, | |
398 | uint32_t routes) | |
6b98d34f DS |
399 | { |
400 | uint32_t temp, i; | |
dbc1bf46 | 401 | bool v4 = false; |
6b98d34f | 402 | |
dbc1bf46 DS |
403 | if (p->family == AF_INET) { |
404 | v4 = true; | |
405 | temp = ntohl(p->u.prefix4.s_addr); | |
406 | } else | |
407 | temp = ntohl(p->u.val32[3]); | |
408 | ||
07414912 DS |
409 | for (i = count; i < routes; i++) { |
410 | bool buffered = route_delete(p, vrf_id, (uint8_t)instance); | |
411 | ||
dbc1bf46 DS |
412 | if (v4) |
413 | p->u.prefix4.s_addr = htonl(++temp); | |
414 | else | |
415 | p->u.val32[3] = htonl(++temp); | |
07414912 DS |
416 | |
417 | if (buffered) { | |
418 | wb.p = *p; | |
419 | wb.count = i + 1; | |
420 | wb.vrf_id = vrf_id; | |
421 | wb.instance = instance; | |
422 | wb.routes = routes; | |
423 | wb.restart = SHARP_DELETE_ROUTES_RESTART; | |
424 | ||
425 | return; | |
426 | } | |
6b98d34f | 427 | } |
07414912 DS |
428 | } |
429 | ||
430 | void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, | |
431 | uint8_t instance, uint32_t routes) | |
432 | { | |
433 | zlog_debug("Removing %u routes", routes); | |
434 | ||
435 | monotime(&sg.r.t_start); | |
436 | ||
437 | sharp_remove_routes_restart(p, 0, vrf_id, instance, routes); | |
6b98d34f DS |
438 | } |
439 | ||
b939f6ff | 440 | static void handle_repeated(bool installed) |
6b98d34f | 441 | { |
547dc642 DS |
442 | struct prefix p = sg.r.orig_prefix; |
443 | sg.r.repeat--; | |
6b98d34f | 444 | |
547dc642 | 445 | if (sg.r.repeat <= 0) |
6b98d34f DS |
446 | return; |
447 | ||
448 | if (installed) { | |
547dc642 | 449 | sg.r.removed_routes = 0; |
0cf08685 DS |
450 | sharp_remove_routes_helper(&p, sg.r.vrf_id, |
451 | sg.r.inst, sg.r.total_routes); | |
6b98d34f DS |
452 | } |
453 | ||
f54f37c1 | 454 | if (!installed) { |
547dc642 | 455 | sg.r.installed_routes = 0; |
0cf08685 | 456 | sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, |
ff9aca4f | 457 | sg.r.nhgid, &sg.r.nhop_group, |
1df3b1dc | 458 | &sg.r.backup_nhop_group, |
c27b47d7 HS |
459 | sg.r.total_routes, sg.r.flags, |
460 | sg.r.opaque); | |
6b98d34f DS |
461 | } |
462 | } | |
463 | ||
07414912 DS |
464 | static void sharp_zclient_buffer_ready(void) |
465 | { | |
466 | switch (wb.restart) { | |
467 | case SHARP_INSTALL_ROUTES_RESTART: | |
cfa2a35d DS |
468 | sharp_install_routes_restart( |
469 | &wb.p, wb.count, wb.vrf_id, wb.instance, wb.nhgid, | |
c27b47d7 HS |
470 | wb.nhg, wb.backup_nhg, wb.routes, wb.flags, |
471 | wb.opaque); | |
07414912 | 472 | return; |
07414912 DS |
473 | case SHARP_DELETE_ROUTES_RESTART: |
474 | sharp_remove_routes_restart(&wb.p, wb.count, wb.vrf_id, | |
475 | wb.instance, wb.routes); | |
476 | return; | |
07414912 DS |
477 | } |
478 | } | |
479 | ||
121f9dee | 480 | static int route_notify_owner(ZAPI_CALLBACK_ARGS) |
8a71d93d | 481 | { |
25c84d86 | 482 | struct timeval r; |
8a71d93d DS |
483 | struct prefix p; |
484 | enum zapi_route_notify_owner note; | |
28610f7e | 485 | uint32_t table; |
8a71d93d | 486 | |
77b38a4a S |
487 | if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, ¬e, |
488 | NULL, NULL)) | |
8a71d93d DS |
489 | return -1; |
490 | ||
5e54c602 DS |
491 | switch (note) { |
492 | case ZAPI_ROUTE_INSTALLED: | |
547dc642 DS |
493 | sg.r.installed_routes++; |
494 | if (sg.r.total_routes == sg.r.installed_routes) { | |
495 | monotime(&sg.r.t_end); | |
496 | timersub(&sg.r.t_end, &sg.r.t_start, &r); | |
051a0be4 DL |
497 | zlog_debug("Installed All Items %jd.%ld", |
498 | (intmax_t)r.tv_sec, (long)r.tv_usec); | |
6b98d34f DS |
499 | handle_repeated(true); |
500 | } | |
5e54c602 DS |
501 | break; |
502 | case ZAPI_ROUTE_FAIL_INSTALL: | |
503 | zlog_debug("Failed install of route"); | |
504 | break; | |
505 | case ZAPI_ROUTE_BETTER_ADMIN_WON: | |
506 | zlog_debug("Better Admin Distance won over us"); | |
507 | break; | |
508 | case ZAPI_ROUTE_REMOVED: | |
547dc642 DS |
509 | sg.r.removed_routes++; |
510 | if (sg.r.total_routes == sg.r.removed_routes) { | |
511 | monotime(&sg.r.t_end); | |
512 | timersub(&sg.r.t_end, &sg.r.t_start, &r); | |
051a0be4 DL |
513 | zlog_debug("Removed all Items %jd.%ld", |
514 | (intmax_t)r.tv_sec, (long)r.tv_usec); | |
6b98d34f DS |
515 | handle_repeated(false); |
516 | } | |
5e54c602 DS |
517 | break; |
518 | case ZAPI_ROUTE_REMOVE_FAIL: | |
519 | zlog_debug("Route removal Failure"); | |
520 | break; | |
521 | } | |
8a71d93d DS |
522 | return 0; |
523 | } | |
524 | ||
525 | static void zebra_connected(struct zclient *zclient) | |
526 | { | |
527 | zclient_send_reg_requests(zclient, VRF_DEFAULT); | |
67a9eda9 DS |
528 | |
529 | /* | |
530 | * Do not actually turn this on yet | |
531 | * This is just the start of the infrastructure needed here | |
532 | * This can be fixed at a later time. | |
533 | * | |
534 | * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, | |
535 | * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); | |
536 | */ | |
8a71d93d DS |
537 | } |
538 | ||
7d061b3c | 539 | void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) |
ab18a495 | 540 | { |
7d061b3c | 541 | zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); |
ab18a495 DS |
542 | } |
543 | ||
21735352 SW |
544 | void nhg_add(uint32_t id, const struct nexthop_group *nhg, |
545 | const struct nexthop_group *backup_nhg) | |
569e87c0 | 546 | { |
c6ce9334 | 547 | struct zapi_nhg api_nhg = {}; |
569e87c0 | 548 | struct zapi_nexthop *api_nh; |
569e87c0 | 549 | struct nexthop *nh; |
5a9c0931 | 550 | bool is_valid = true; |
569e87c0 | 551 | |
c6ce9334 | 552 | api_nhg.id = id; |
569e87c0 | 553 | for (ALL_NEXTHOPS_PTR(nhg, nh)) { |
c6ce9334 | 554 | if (api_nhg.nexthop_num >= MULTIPATH_NUM) { |
54a701e4 SW |
555 | zlog_warn( |
556 | "%s: number of nexthops greater than max multipath size, truncating", | |
557 | __func__); | |
558 | break; | |
559 | } | |
560 | ||
5a9c0931 MS |
561 | /* Unresolved nexthops will lead to failure - only send |
562 | * nexthops that zebra will consider valid. | |
563 | */ | |
564 | if (nh->ifindex == 0) | |
565 | continue; | |
566 | ||
c6ce9334 | 567 | api_nh = &api_nhg.nexthops[api_nhg.nexthop_num]; |
569e87c0 DS |
568 | |
569 | zapi_nexthop_from_nexthop(api_nh, nh); | |
c6ce9334 | 570 | api_nhg.nexthop_num++; |
569e87c0 DS |
571 | } |
572 | ||
5a9c0931 MS |
573 | if (api_nhg.nexthop_num == 0) { |
574 | zlog_debug("%s: nhg %u not sent: no valid nexthops", | |
575 | __func__, id); | |
576 | is_valid = false; | |
577 | goto done; | |
578 | } | |
579 | ||
21735352 SW |
580 | if (backup_nhg) { |
581 | for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { | |
582 | if (api_nhg.backup_nexthop_num >= MULTIPATH_NUM) { | |
583 | zlog_warn( | |
584 | "%s: number of backup nexthops greater than max multipath size, truncating", | |
585 | __func__); | |
586 | break; | |
587 | } | |
5a9c0931 MS |
588 | |
589 | /* Unresolved nexthop: will be rejected by zebra. | |
590 | * That causes a problem, since the primary nexthops | |
591 | * rely on array indexing into the backup nexthops. If | |
592 | * that array isn't valid, the backup indexes won't be | |
593 | * valid. | |
594 | */ | |
595 | if (nh->ifindex == 0) { | |
596 | zlog_debug("%s: nhg %u: invalid backup nexthop", | |
597 | __func__, id); | |
598 | is_valid = false; | |
599 | break; | |
600 | } | |
601 | ||
21735352 SW |
602 | api_nh = &api_nhg.backup_nexthops |
603 | [api_nhg.backup_nexthop_num]; | |
604 | ||
605 | zapi_backup_nexthop_from_nexthop(api_nh, nh); | |
606 | api_nhg.backup_nexthop_num++; | |
607 | } | |
608 | } | |
609 | ||
5a9c0931 MS |
610 | done: |
611 | if (is_valid) | |
612 | zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg); | |
569e87c0 DS |
613 | } |
614 | ||
615 | void nhg_del(uint32_t id) | |
616 | { | |
c6ce9334 SW |
617 | struct zapi_nhg api_nhg = {}; |
618 | ||
619 | api_nhg.id = id; | |
620 | ||
621 | zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg); | |
569e87c0 DS |
622 | } |
623 | ||
91529dc8 | 624 | void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, |
b47dc61a | 625 | bool watch, bool connected) |
0ae8130d | 626 | { |
b47dc61a | 627 | int command; |
0ae8130d | 628 | |
b47dc61a DS |
629 | if (!import) { |
630 | command = ZEBRA_NEXTHOP_REGISTER; | |
631 | ||
632 | if (!watch) | |
633 | command = ZEBRA_NEXTHOP_UNREGISTER; | |
634 | } else { | |
635 | command = ZEBRA_IMPORT_ROUTE_REGISTER; | |
636 | ||
637 | if (!watch) | |
638 | command = ZEBRA_IMPORT_ROUTE_UNREGISTER; | |
639 | } | |
0ae8130d | 640 | |
7cfdb485 DS |
641 | if (zclient_send_rnh(zclient, command, p, connected, vrf_id) |
642 | == ZCLIENT_SEND_FAILURE) | |
15569c58 | 643 | zlog_warn("%s: Failure to send nexthop to zebra", __func__); |
0ae8130d DS |
644 | } |
645 | ||
67a9eda9 | 646 | static int sharp_debug_nexthops(struct zapi_route *api) |
0ae8130d | 647 | { |
0ae8130d DS |
648 | int i; |
649 | ||
8b85b2cb MS |
650 | if (api->nexthop_num == 0) { |
651 | zlog_debug( | |
652 | " Not installed"); | |
653 | return 0; | |
654 | } | |
655 | ||
67a9eda9 DS |
656 | for (i = 0; i < api->nexthop_num; i++) { |
657 | struct zapi_nexthop *znh = &api->nexthops[i]; | |
0ae8130d DS |
658 | |
659 | switch (znh->type) { | |
660 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
661 | case NEXTHOP_TYPE_IPV4: | |
662 | zlog_debug( | |
6dd43a35 DS |
663 | " Nexthop %pI4, type: %d, ifindex: %d, vrf: %d, label_num: %d", |
664 | &znh->gate.ipv4.s_addr, znh->type, znh->ifindex, | |
665 | znh->vrf_id, znh->label_num); | |
0ae8130d DS |
666 | break; |
667 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
668 | case NEXTHOP_TYPE_IPV6: | |
669 | zlog_debug( | |
6dd43a35 DS |
670 | " Nexthop %pI6, type: %d, ifindex: %d, vrf: %d, label_num: %d", |
671 | &znh->gate.ipv6, znh->type, znh->ifindex, | |
672 | znh->vrf_id, znh->label_num); | |
0ae8130d DS |
673 | break; |
674 | case NEXTHOP_TYPE_IFINDEX: | |
d6951e5e | 675 | zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d", |
0ae8130d DS |
676 | znh->type, znh->ifindex); |
677 | break; | |
678 | case NEXTHOP_TYPE_BLACKHOLE: | |
d6951e5e | 679 | zlog_debug(" Nexthop blackhole"); |
0ae8130d DS |
680 | break; |
681 | } | |
682 | } | |
67a9eda9 DS |
683 | |
684 | return i; | |
685 | } | |
686 | static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) | |
687 | { | |
688 | struct sharp_nh_tracker *nht; | |
689 | struct zapi_route nhr; | |
690 | ||
691 | if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { | |
6c83dded | 692 | zlog_err("%s: Decode of update failed", __func__); |
67a9eda9 DS |
693 | return 0; |
694 | } | |
695 | ||
877155ed DS |
696 | zlog_debug("Received update for %pFX metric: %u", &nhr.prefix, |
697 | nhr.metric); | |
67a9eda9 DS |
698 | |
699 | nht = sharp_nh_tracker_get(&nhr.prefix); | |
700 | nht->nhop_num = nhr.nexthop_num; | |
701 | nht->updates++; | |
702 | ||
703 | sharp_debug_nexthops(&nhr); | |
704 | ||
705 | return 0; | |
706 | } | |
707 | ||
708 | static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS) | |
709 | { | |
710 | struct zapi_route api; | |
711 | ||
712 | if (zapi_route_decode(zclient->ibuf, &api) < 0) | |
15569c58 | 713 | zlog_warn("%s: Decode of redistribute failed: %d", __func__, |
67a9eda9 DS |
714 | ZEBRA_REDISTRIBUTE_ROUTE_ADD); |
715 | ||
716 | zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), | |
717 | &api.prefix, zebra_route_string(api.type)); | |
718 | ||
719 | sharp_debug_nexthops(&api); | |
720 | ||
0ae8130d DS |
721 | return 0; |
722 | } | |
723 | ||
921af54d DS |
724 | void sharp_redistribute_vrf(struct vrf *vrf, int type) |
725 | { | |
726 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, | |
727 | 0, vrf->vrf_id); | |
728 | } | |
729 | ||
2be4d61a MS |
730 | /* Add a zclient with a specified session id, for testing. */ |
731 | int sharp_zclient_create(uint32_t session_id) | |
732 | { | |
733 | struct zclient *client; | |
734 | struct sharp_zclient *node; | |
735 | ||
736 | /* Check for duplicates */ | |
737 | for (node = sharp_clients_head; node != NULL; node = node->next) { | |
738 | if (node->client->session_id == session_id) | |
739 | return -1; | |
740 | } | |
741 | ||
742 | client = zclient_new(master, &zclient_options_default); | |
743 | client->sock = -1; | |
744 | client->session_id = session_id; | |
745 | ||
746 | zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); | |
747 | ||
748 | /* Register handlers for messages we expect this session to see */ | |
749 | client->opaque_msg_handler = sharp_opaque_handler; | |
750 | ||
751 | /* Enqueue on the list of test clients */ | |
752 | add_zclient(client); | |
753 | ||
754 | return 0; | |
755 | } | |
756 | ||
757 | /* Delete one of the extra test zclients */ | |
758 | int sharp_zclient_delete(uint32_t session_id) | |
759 | { | |
760 | struct sharp_zclient *node; | |
761 | ||
762 | /* Search for session */ | |
763 | for (node = sharp_clients_head; node != NULL; node = node->next) { | |
764 | if (node->client->session_id == session_id) { | |
765 | /* Dequeue from list */ | |
766 | if (node->next) | |
767 | node->next->prev = node->prev; | |
768 | if (node->prev) | |
769 | node->prev->next = node->next; | |
770 | if (node == sharp_clients_head) | |
771 | sharp_clients_head = node->next; | |
772 | ||
773 | /* Clean up zclient */ | |
774 | zclient_stop(node->client); | |
775 | zclient_free(node->client); | |
776 | ||
777 | /* Free memory */ | |
778 | XFREE(MTYPE_ZC, node); | |
779 | break; | |
780 | } | |
781 | } | |
782 | ||
783 | return 0; | |
784 | } | |
785 | ||
1888e243 OD |
786 | static const char *const type2txt[] = { "Generic", "Vertex", "Edge", "Subnet" }; |
787 | static const char *const status2txt[] = { "Unknown", "New", "Update", | |
788 | "Delete", "Sync", "Orphan"}; | |
7f5ac773 MS |
789 | /* Handler for opaque messages */ |
790 | static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) | |
791 | { | |
7f5ac773 | 792 | struct stream *s; |
387831ff | 793 | struct zapi_opaque_msg info; |
1888e243 | 794 | struct ls_element *lse; |
7f5ac773 MS |
795 | |
796 | s = zclient->ibuf; | |
797 | ||
387831ff MS |
798 | if (zclient_opaque_decode(s, &info) != 0) |
799 | return -1; | |
7f5ac773 | 800 | |
2be4d61a | 801 | zlog_debug("%s: [%u] received opaque type %u", __func__, |
c8b27f2a | 802 | zclient->session_id, info.type); |
7f5ac773 | 803 | |
1888e243 OD |
804 | if (info.type == LINK_STATE_UPDATE) { |
805 | lse = ls_stream2ted(sg.ted, s, false); | |
806 | if (lse) | |
807 | zlog_debug(" |- Got %s %s from Link State Database", | |
808 | status2txt[lse->status], | |
809 | type2txt[lse->type]); | |
810 | else | |
811 | zlog_debug( | |
812 | "%s: Error to convert Stream into Link State", | |
813 | __func__); | |
814 | } | |
815 | ||
7f5ac773 MS |
816 | return 0; |
817 | } | |
818 | ||
2ac6c90d MS |
819 | /* |
820 | * Send OPAQUE messages, using subtype 'type'. | |
821 | */ | |
c8b27f2a MS |
822 | void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance, |
823 | uint32_t session_id, uint32_t count) | |
2ac6c90d | 824 | { |
7f5ac773 | 825 | uint8_t buf[32]; |
2ac6c90d MS |
826 | int ret; |
827 | uint32_t i; | |
828 | ||
829 | /* Prepare a small payload */ | |
830 | for (i = 0; i < sizeof(buf); i++) { | |
831 | if (type < 255) | |
832 | buf[i] = type; | |
833 | else | |
834 | buf[i] = 255; | |
835 | } | |
836 | ||
c8b27f2a | 837 | /* Send some messages - broadcast and unicast are supported */ |
2ac6c90d | 838 | for (i = 0; i < count; i++) { |
c8b27f2a MS |
839 | if (proto == 0) |
840 | ret = zclient_send_opaque(zclient, type, buf, | |
841 | sizeof(buf)); | |
842 | else | |
843 | ret = zclient_send_opaque_unicast(zclient, type, proto, | |
844 | instance, session_id, | |
845 | buf, sizeof(buf)); | |
7cfdb485 | 846 | if (ret == ZCLIENT_SEND_FAILURE) { |
2ac6c90d MS |
847 | zlog_debug("%s: send_opaque() failed => %d", |
848 | __func__, ret); | |
849 | break; | |
850 | } | |
851 | } | |
852 | ||
853 | } | |
854 | ||
939b2339 MS |
855 | /* |
856 | * Send OPAQUE registration messages, using subtype 'type'. | |
857 | */ | |
858 | void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance, | |
859 | uint32_t session_id, uint32_t type) | |
860 | { | |
861 | struct stream *s; | |
862 | ||
863 | s = zclient->obuf; | |
864 | stream_reset(s); | |
865 | ||
866 | if (is_reg) | |
867 | zclient_create_header(s, ZEBRA_OPAQUE_REGISTER, VRF_DEFAULT); | |
868 | else | |
869 | zclient_create_header(s, ZEBRA_OPAQUE_UNREGISTER, VRF_DEFAULT); | |
870 | ||
871 | /* Send sub-type */ | |
872 | stream_putl(s, type); | |
873 | ||
874 | /* Add zclient info */ | |
875 | stream_putc(s, proto); | |
876 | stream_putw(s, instance); | |
877 | stream_putl(s, session_id); | |
878 | ||
879 | /* Put length at the first point of the stream. */ | |
880 | stream_putw_at(s, 0, stream_get_endp(s)); | |
881 | ||
882 | (void)zclient_send_message(zclient); | |
883 | ||
884 | } | |
885 | ||
1888e243 OD |
886 | /* Link State registration */ |
887 | void sharp_zebra_register_te(void) | |
888 | { | |
889 | /* First register to received Link State Update messages */ | |
890 | zclient_register_opaque(zclient, LINK_STATE_UPDATE); | |
891 | ||
892 | /* Then, request initial TED with SYNC message */ | |
893 | ls_request_sync(zclient); | |
894 | } | |
895 | ||
da187b77 JU |
896 | void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p) |
897 | { | |
898 | zclient_send_neigh_discovery_req(zclient, ifp, p); | |
899 | } | |
900 | ||
2053061b SW |
901 | static int nhg_notify_owner(ZAPI_CALLBACK_ARGS) |
902 | { | |
903 | enum zapi_nhg_notify_owner note; | |
904 | uint32_t id; | |
905 | ||
906 | if (!zapi_nhg_notify_decode(zclient->ibuf, &id, ¬e)) | |
907 | return -1; | |
908 | ||
909 | switch (note) { | |
910 | case ZAPI_NHG_INSTALLED: | |
911 | sharp_nhgroup_id_set_installed(id, true); | |
912 | zlog_debug("Installed nhg %u", id); | |
913 | break; | |
914 | case ZAPI_NHG_FAIL_INSTALL: | |
915 | zlog_debug("Failed install of nhg %u", id); | |
916 | break; | |
917 | case ZAPI_NHG_REMOVED: | |
918 | zlog_debug("Removed nhg %u", id); | |
919 | break; | |
920 | case ZAPI_NHG_REMOVE_FAIL: | |
921 | zlog_debug("Failed removal of nhg %u", id); | |
922 | break; | |
923 | } | |
924 | ||
925 | return 0; | |
926 | } | |
927 | ||
4df9d859 | 928 | int sharp_zebra_srv6_manager_get_locator_chunk(const char *locator_name) |
ade3eebc HS |
929 | { |
930 | return srv6_manager_get_locator_chunk(zclient, locator_name); | |
931 | } | |
932 | ||
933 | int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name) | |
934 | { | |
935 | return srv6_manager_release_locator_chunk(zclient, locator_name); | |
936 | } | |
937 | ||
938 | static void sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) | |
939 | { | |
940 | struct stream *s = NULL; | |
05485926 HS |
941 | struct srv6_locator_chunk s6c = {}; |
942 | struct listnode *node, *nnode; | |
943 | struct sharp_srv6_locator *loc; | |
ade3eebc HS |
944 | |
945 | s = zclient->ibuf; | |
05485926 | 946 | zapi_srv6_locator_chunk_decode(s, &s6c); |
ade3eebc | 947 | |
05485926 HS |
948 | for (ALL_LIST_ELEMENTS(sg.srv6_locators, node, nnode, loc)) { |
949 | struct prefix_ipv6 *chunk = NULL; | |
4df9d859 HS |
950 | struct listnode *chunk_node; |
951 | struct prefix_ipv6 *c; | |
952 | ||
05485926 HS |
953 | if (strcmp(loc->name, s6c.locator_name) != 0) { |
954 | zlog_err("%s: Locator name unmatch %s:%s", __func__, | |
955 | loc->name, s6c.locator_name); | |
ade3eebc | 956 | continue; |
05485926 | 957 | } |
ade3eebc | 958 | |
4df9d859 | 959 | for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c)) |
05485926 | 960 | if (!prefix_cmp(c, &s6c.prefix)) |
ade3eebc | 961 | return; |
05485926 HS |
962 | |
963 | chunk = prefix_ipv6_new(); | |
964 | *chunk = s6c.prefix; | |
ade3eebc | 965 | listnode_add(loc->chunks, chunk); |
05485926 | 966 | return; |
ade3eebc | 967 | } |
ade3eebc HS |
968 | |
969 | zlog_err("%s: can't get locator_chunk!!", __func__); | |
ade3eebc HS |
970 | } |
971 | ||
8a71d93d DS |
972 | void sharp_zebra_init(void) |
973 | { | |
996c9314 | 974 | struct zclient_options opt = {.receive_notify = true}; |
8a71d93d | 975 | |
138c5a74 DS |
976 | if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, |
977 | sharp_ifp_down, sharp_ifp_destroy); | |
978 | ||
26f63a1e | 979 | zclient = zclient_new(master, &opt); |
8a71d93d DS |
980 | |
981 | zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); | |
982 | zclient->zebra_connected = zebra_connected; | |
8a71d93d DS |
983 | zclient->interface_address_add = interface_address_add; |
984 | zclient->interface_address_delete = interface_address_delete; | |
28b11f81 | 985 | zclient->route_notify_owner = route_notify_owner; |
0ae8130d | 986 | zclient->nexthop_update = sharp_nexthop_update; |
b47dc61a | 987 | zclient->import_check_update = sharp_nexthop_update; |
2053061b | 988 | zclient->nhg_notify_owner = nhg_notify_owner; |
07414912 | 989 | zclient->zebra_buffer_write_ready = sharp_zclient_buffer_ready; |
67a9eda9 DS |
990 | zclient->redistribute_route_add = sharp_redistribute_route; |
991 | zclient->redistribute_route_del = sharp_redistribute_route; | |
7f5ac773 | 992 | zclient->opaque_msg_handler = sharp_opaque_handler; |
4df9d859 HS |
993 | zclient->process_srv6_locator_chunk = |
994 | sharp_zebra_process_srv6_locator_chunk; | |
8a71d93d | 995 | } |