]> git.proxmox.com Git - mirror_frr.git/blame - sharpd/sharp_zebra.c
Merge pull request #10183 from idryzhov/rework-vrf-rename
[mirror_frr.git] / sharpd / sharp_zebra.c
CommitLineData
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. */
40struct zclient *zclient = NULL;
41
42/* For registering threads. */
04cbc08f 43extern struct thread_master *master;
8a71d93d 44
2be4d61a 45/* Privs info */
04cbc08f 46extern struct zebra_privs_t sharp_privs;
2be4d61a
MS
47
48DEFINE_MTYPE_STATIC(SHARPD, ZC, "Test zclients");
49
50/* Struct to hold list of test zclients */
51struct sharp_zclient {
52 struct sharp_zclient *prev;
53 struct sharp_zclient *next;
54 struct zclient *client;
55};
56
57/* Head of test zclient list */
58static struct sharp_zclient *sharp_clients_head;
59
60static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS);
61
62/* Utility to add a test zclient struct to the list */
63static 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 78static int sharp_ifp_create(struct interface *ifp)
8a71d93d 79{
8a71d93d
DS
80 return 0;
81}
82
3c3c3252 83static int sharp_ifp_destroy(struct interface *ifp)
8a71d93d 84{
8a71d93d
DS
85 return 0;
86}
87
121f9dee 88static 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 95static 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 108static int sharp_ifp_up(struct interface *ifp)
8a71d93d 109{
8a71d93d
DS
110 return 0;
111}
112
b0b69e59 113static int sharp_ifp_down(struct interface *ifp)
8a71d93d 114{
8a71d93d
DS
115 return 0;
116}
117
faa75dfa
MS
118int 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
221enum where_to_restart {
222 SHARP_INSTALL_ROUTES_RESTART,
223 SHARP_DELETE_ROUTES_RESTART,
224};
225
226struct 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 */
246static 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 */
318static 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
336static 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
379void 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
396static 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
430void 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 440static 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
464static 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 480static 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, &note,
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
525static 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 539void 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
544void 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
610done:
611 if (is_valid)
612 zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
569e87c0
DS
613}
614
615void 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 624void 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
3d174ce0 629 command = ZEBRA_NEXTHOP_REGISTER;
b47dc61a 630
3d174ce0
DS
631 if (!watch)
632 command = ZEBRA_NEXTHOP_UNREGISTER;
0ae8130d 633
ed6cec97 634 if (zclient_send_rnh(zclient, command, p, connected, false, vrf_id)
7cfdb485 635 == ZCLIENT_SEND_FAILURE)
15569c58 636 zlog_warn("%s: Failure to send nexthop to zebra", __func__);
0ae8130d
DS
637}
638
67a9eda9 639static int sharp_debug_nexthops(struct zapi_route *api)
0ae8130d 640{
0ae8130d
DS
641 int i;
642
8b85b2cb
MS
643 if (api->nexthop_num == 0) {
644 zlog_debug(
645 " Not installed");
646 return 0;
647 }
648
67a9eda9
DS
649 for (i = 0; i < api->nexthop_num; i++) {
650 struct zapi_nexthop *znh = &api->nexthops[i];
0ae8130d
DS
651
652 switch (znh->type) {
653 case NEXTHOP_TYPE_IPV4_IFINDEX:
654 case NEXTHOP_TYPE_IPV4:
655 zlog_debug(
6dd43a35
DS
656 " Nexthop %pI4, type: %d, ifindex: %d, vrf: %d, label_num: %d",
657 &znh->gate.ipv4.s_addr, znh->type, znh->ifindex,
658 znh->vrf_id, znh->label_num);
0ae8130d
DS
659 break;
660 case NEXTHOP_TYPE_IPV6_IFINDEX:
661 case NEXTHOP_TYPE_IPV6:
662 zlog_debug(
6dd43a35
DS
663 " Nexthop %pI6, type: %d, ifindex: %d, vrf: %d, label_num: %d",
664 &znh->gate.ipv6, znh->type, znh->ifindex,
665 znh->vrf_id, znh->label_num);
0ae8130d
DS
666 break;
667 case NEXTHOP_TYPE_IFINDEX:
d6951e5e 668 zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d",
0ae8130d
DS
669 znh->type, znh->ifindex);
670 break;
671 case NEXTHOP_TYPE_BLACKHOLE:
d6951e5e 672 zlog_debug(" Nexthop blackhole");
0ae8130d
DS
673 break;
674 }
675 }
67a9eda9
DS
676
677 return i;
678}
679static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
680{
681 struct sharp_nh_tracker *nht;
682 struct zapi_route nhr;
683
684 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
6c83dded 685 zlog_err("%s: Decode of update failed", __func__);
67a9eda9
DS
686 return 0;
687 }
688
877155ed
DS
689 zlog_debug("Received update for %pFX metric: %u", &nhr.prefix,
690 nhr.metric);
67a9eda9
DS
691
692 nht = sharp_nh_tracker_get(&nhr.prefix);
693 nht->nhop_num = nhr.nexthop_num;
694 nht->updates++;
695
696 sharp_debug_nexthops(&nhr);
697
698 return 0;
699}
700
701static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS)
702{
703 struct zapi_route api;
704
705 if (zapi_route_decode(zclient->ibuf, &api) < 0)
15569c58 706 zlog_warn("%s: Decode of redistribute failed: %d", __func__,
67a9eda9
DS
707 ZEBRA_REDISTRIBUTE_ROUTE_ADD);
708
709 zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd),
710 &api.prefix, zebra_route_string(api.type));
711
712 sharp_debug_nexthops(&api);
713
0ae8130d
DS
714 return 0;
715}
716
921af54d
DS
717void sharp_redistribute_vrf(struct vrf *vrf, int type)
718{
719 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type,
720 0, vrf->vrf_id);
721}
722
a243d1db
DL
723static zclient_handler *const sharp_opaque_handlers[] = {
724 [ZEBRA_OPAQUE_MESSAGE] = sharp_opaque_handler,
725};
726
2be4d61a
MS
727/* Add a zclient with a specified session id, for testing. */
728int sharp_zclient_create(uint32_t session_id)
729{
730 struct zclient *client;
731 struct sharp_zclient *node;
732
733 /* Check for duplicates */
734 for (node = sharp_clients_head; node != NULL; node = node->next) {
735 if (node->client->session_id == session_id)
736 return -1;
737 }
738
a243d1db
DL
739 client = zclient_new(master, &zclient_options_default,
740 sharp_opaque_handlers,
741 array_size(sharp_opaque_handlers));
2be4d61a
MS
742 client->sock = -1;
743 client->session_id = session_id;
744
745 zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs);
746
2be4d61a
MS
747 /* Enqueue on the list of test clients */
748 add_zclient(client);
749
750 return 0;
751}
752
753/* Delete one of the extra test zclients */
754int sharp_zclient_delete(uint32_t session_id)
755{
756 struct sharp_zclient *node;
757
758 /* Search for session */
759 for (node = sharp_clients_head; node != NULL; node = node->next) {
760 if (node->client->session_id == session_id) {
761 /* Dequeue from list */
762 if (node->next)
763 node->next->prev = node->prev;
764 if (node->prev)
765 node->prev->next = node->next;
766 if (node == sharp_clients_head)
767 sharp_clients_head = node->next;
768
769 /* Clean up zclient */
770 zclient_stop(node->client);
771 zclient_free(node->client);
772
773 /* Free memory */
774 XFREE(MTYPE_ZC, node);
775 break;
776 }
777 }
778
779 return 0;
780}
781
1888e243
OD
782static const char *const type2txt[] = { "Generic", "Vertex", "Edge", "Subnet" };
783static const char *const status2txt[] = { "Unknown", "New", "Update",
784 "Delete", "Sync", "Orphan"};
7f5ac773
MS
785/* Handler for opaque messages */
786static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)
787{
7f5ac773 788 struct stream *s;
387831ff 789 struct zapi_opaque_msg info;
1888e243 790 struct ls_element *lse;
7f5ac773
MS
791
792 s = zclient->ibuf;
793
387831ff
MS
794 if (zclient_opaque_decode(s, &info) != 0)
795 return -1;
7f5ac773 796
2be4d61a 797 zlog_debug("%s: [%u] received opaque type %u", __func__,
c8b27f2a 798 zclient->session_id, info.type);
7f5ac773 799
1888e243
OD
800 if (info.type == LINK_STATE_UPDATE) {
801 lse = ls_stream2ted(sg.ted, s, false);
802 if (lse)
803 zlog_debug(" |- Got %s %s from Link State Database",
804 status2txt[lse->status],
805 type2txt[lse->type]);
806 else
807 zlog_debug(
808 "%s: Error to convert Stream into Link State",
809 __func__);
810 }
811
7f5ac773
MS
812 return 0;
813}
814
2ac6c90d
MS
815/*
816 * Send OPAQUE messages, using subtype 'type'.
817 */
c8b27f2a
MS
818void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance,
819 uint32_t session_id, uint32_t count)
2ac6c90d 820{
7f5ac773 821 uint8_t buf[32];
2ac6c90d
MS
822 int ret;
823 uint32_t i;
824
825 /* Prepare a small payload */
826 for (i = 0; i < sizeof(buf); i++) {
827 if (type < 255)
828 buf[i] = type;
829 else
830 buf[i] = 255;
831 }
832
c8b27f2a 833 /* Send some messages - broadcast and unicast are supported */
2ac6c90d 834 for (i = 0; i < count; i++) {
c8b27f2a
MS
835 if (proto == 0)
836 ret = zclient_send_opaque(zclient, type, buf,
837 sizeof(buf));
838 else
839 ret = zclient_send_opaque_unicast(zclient, type, proto,
840 instance, session_id,
841 buf, sizeof(buf));
7cfdb485 842 if (ret == ZCLIENT_SEND_FAILURE) {
2ac6c90d
MS
843 zlog_debug("%s: send_opaque() failed => %d",
844 __func__, ret);
845 break;
846 }
847 }
848
849}
850
939b2339
MS
851/*
852 * Send OPAQUE registration messages, using subtype 'type'.
853 */
854void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance,
855 uint32_t session_id, uint32_t type)
856{
857 struct stream *s;
858
859 s = zclient->obuf;
860 stream_reset(s);
861
862 if (is_reg)
863 zclient_create_header(s, ZEBRA_OPAQUE_REGISTER, VRF_DEFAULT);
864 else
865 zclient_create_header(s, ZEBRA_OPAQUE_UNREGISTER, VRF_DEFAULT);
866
867 /* Send sub-type */
868 stream_putl(s, type);
869
870 /* Add zclient info */
871 stream_putc(s, proto);
872 stream_putw(s, instance);
873 stream_putl(s, session_id);
874
875 /* Put length at the first point of the stream. */
876 stream_putw_at(s, 0, stream_get_endp(s));
877
878 (void)zclient_send_message(zclient);
879
880}
881
1888e243
OD
882/* Link State registration */
883void sharp_zebra_register_te(void)
884{
885 /* First register to received Link State Update messages */
886 zclient_register_opaque(zclient, LINK_STATE_UPDATE);
887
888 /* Then, request initial TED with SYNC message */
889 ls_request_sync(zclient);
890}
891
da187b77
JU
892void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
893{
894 zclient_send_neigh_discovery_req(zclient, ifp, p);
895}
896
2053061b
SW
897static int nhg_notify_owner(ZAPI_CALLBACK_ARGS)
898{
899 enum zapi_nhg_notify_owner note;
900 uint32_t id;
901
902 if (!zapi_nhg_notify_decode(zclient->ibuf, &id, &note))
903 return -1;
904
905 switch (note) {
906 case ZAPI_NHG_INSTALLED:
907 sharp_nhgroup_id_set_installed(id, true);
908 zlog_debug("Installed nhg %u", id);
909 break;
910 case ZAPI_NHG_FAIL_INSTALL:
911 zlog_debug("Failed install of nhg %u", id);
912 break;
913 case ZAPI_NHG_REMOVED:
914 zlog_debug("Removed nhg %u", id);
915 break;
916 case ZAPI_NHG_REMOVE_FAIL:
917 zlog_debug("Failed removal of nhg %u", id);
918 break;
919 }
920
921 return 0;
922}
923
4df9d859 924int sharp_zebra_srv6_manager_get_locator_chunk(const char *locator_name)
ade3eebc
HS
925{
926 return srv6_manager_get_locator_chunk(zclient, locator_name);
927}
928
929int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name)
930{
931 return srv6_manager_release_locator_chunk(zclient, locator_name);
932}
933
a243d1db 934static int sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
ade3eebc
HS
935{
936 struct stream *s = NULL;
05485926
HS
937 struct srv6_locator_chunk s6c = {};
938 struct listnode *node, *nnode;
939 struct sharp_srv6_locator *loc;
ade3eebc
HS
940
941 s = zclient->ibuf;
05485926 942 zapi_srv6_locator_chunk_decode(s, &s6c);
ade3eebc 943
05485926
HS
944 for (ALL_LIST_ELEMENTS(sg.srv6_locators, node, nnode, loc)) {
945 struct prefix_ipv6 *chunk = NULL;
4df9d859
HS
946 struct listnode *chunk_node;
947 struct prefix_ipv6 *c;
948
05485926
HS
949 if (strcmp(loc->name, s6c.locator_name) != 0) {
950 zlog_err("%s: Locator name unmatch %s:%s", __func__,
951 loc->name, s6c.locator_name);
ade3eebc 952 continue;
05485926 953 }
ade3eebc 954
4df9d859 955 for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c))
05485926 956 if (!prefix_cmp(c, &s6c.prefix))
a243d1db 957 return 0;
05485926
HS
958
959 chunk = prefix_ipv6_new();
960 *chunk = s6c.prefix;
ade3eebc 961 listnode_add(loc->chunks, chunk);
a243d1db 962 return 0;
ade3eebc 963 }
ade3eebc
HS
964
965 zlog_err("%s: can't get locator_chunk!!", __func__);
a243d1db 966 return 0;
ade3eebc
HS
967}
968
a243d1db
DL
969static zclient_handler *const sharp_handlers[] = {
970 [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
971 [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
972 [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner,
973 [ZEBRA_NEXTHOP_UPDATE] = sharp_nexthop_update,
974 [ZEBRA_NHG_NOTIFY_OWNER] = nhg_notify_owner,
975 [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = sharp_redistribute_route,
976 [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = sharp_redistribute_route,
977 [ZEBRA_OPAQUE_MESSAGE] = sharp_opaque_handler,
978 [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
979 sharp_zebra_process_srv6_locator_chunk,
980};
981
8a71d93d
DS
982void sharp_zebra_init(void)
983{
996c9314 984 struct zclient_options opt = {.receive_notify = true};
8a71d93d 985
138c5a74
DS
986 if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up,
987 sharp_ifp_down, sharp_ifp_destroy);
988
a243d1db
DL
989 zclient = zclient_new(master, &opt, sharp_handlers,
990 array_size(sharp_handlers));
8a71d93d
DS
991
992 zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs);
993 zclient->zebra_connected = zebra_connected;
07414912 994 zclient->zebra_buffer_write_ready = sharp_zclient_buffer_ready;
8a71d93d 995}