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